From dfdd24c15358fbfbb9993daf3926f3337f6b55a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Zasso?= Date: Sat, 27 Jun 2026 12:00:35 +0200 Subject: [PATCH 1/5] chore: use types without typo --- src/component/hooks/usePanelPreferences.ts | 8 ++++---- src/component/modal/setting/WorkspaceItem.tsx | 4 ++-- src/component/panels/RangesPanel/RangesPanel.tsx | 4 ++-- src/component/panels/RangesPanel/RangesTable.tsx | 4 ++-- src/component/panels/RangesPanel/RangesTableRow.tsx | 4 ++-- .../panels/multipleAnalysisPanel/AnalysisChart.tsx | 4 ++-- src/component/reducer/preferences/preferencesReducer.ts | 4 ++-- .../reducer/preferences/utilities/initWorkspace.ts | 4 ++-- .../reducer/preferences/utilities/mapWorkspaces.ts | 4 ++-- src/component/toolbar/ToolTypes.ts | 4 ++-- src/data/data1d/multipleSpectraAnalysis.ts | 4 ++-- 11 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/component/hooks/usePanelPreferences.ts b/src/component/hooks/usePanelPreferences.ts index c3771f11c6..b66025078c 100644 --- a/src/component/hooks/usePanelPreferences.ts +++ b/src/component/hooks/usePanelPreferences.ts @@ -2,8 +2,8 @@ import type { MatrixGenerationOptions, MultipleSpectraAnalysisPreferences, PanelsPreferences, - WorkSpacePanelPreferences, Workspace, + WorkspacePanelPreferences, } from '@zakodium/nmrium-core'; import has from 'lodash/has.js'; import { useMemo } from 'react'; @@ -128,15 +128,15 @@ export function usePanelPreferences( ? MatrixGenerationOptions : T extends 'multipleSpectraAnalysis' ? MultipleSpectraAnalysisPreferences - : WorkSpacePanelPreferences[T]; + : WorkspacePanelPreferences[T]; export function usePanelPreferences( panelKey: T, -): WorkSpacePanelPreferences[T]; +): WorkspacePanelPreferences[T]; export function usePanelPreferences( panelKey: T, nucleus?: string, -): WorkSpacePanelPreferences[T] { +): WorkspacePanelPreferences[T] { const { current } = usePreferences(); return useMemo(() => { return getPanelPreferences(current, panelKey, nucleus); diff --git a/src/component/modal/setting/WorkspaceItem.tsx b/src/component/modal/setting/WorkspaceItem.tsx index 90d7456300..b3eaf12177 100644 --- a/src/component/modal/setting/WorkspaceItem.tsx +++ b/src/component/modal/setting/WorkspaceItem.tsx @@ -1,4 +1,4 @@ -import type { WorkSpaceSource } from '@zakodium/nmrium-core'; +import type { WorkspaceSource } from '@zakodium/nmrium-core'; import type { CSSProperties, ChangeEvent, MouseEvent } from 'react'; import { useState } from 'react'; import { Button } from 'react-science/ui'; @@ -115,7 +115,7 @@ const style = { alignItems: 'center', }; -const WorkspaceIndicator = (props: { source: WorkSpaceSource }) => { +const WorkspaceIndicator = (props: { source: WorkspaceSource }) => { let letter = ''; let backgroundColor = 'red'; diff --git a/src/component/panels/RangesPanel/RangesPanel.tsx b/src/component/panels/RangesPanel/RangesPanel.tsx index 27378e2e90..a5a3bcf601 100644 --- a/src/component/panels/RangesPanel/RangesPanel.tsx +++ b/src/component/panels/RangesPanel/RangesPanel.tsx @@ -1,7 +1,7 @@ import type { Info1D, Range, Ranges } from '@zakodium/nmr-types'; import type { Spectrum1D, - WorkSpacePanelPreferences, + WorkspacePanelPreferences, } from '@zakodium/nmrium-core'; import type { NmrData1D } from 'cheminfo-types'; import { xGetFromToIndex } from 'ml-spectra-processing'; @@ -37,7 +37,7 @@ interface RangesTablePanelInnerProps { info: Info1D; xDomain: number[]; activeTab: string; - preferences: WorkSpacePanelPreferences['ranges']; + preferences: WorkspacePanelPreferences['ranges']; } export interface RangesTableDataMetaInfo { diff --git a/src/component/panels/RangesPanel/RangesTable.tsx b/src/component/panels/RangesPanel/RangesTable.tsx index 022ed517d2..3b39036ee2 100644 --- a/src/component/panels/RangesPanel/RangesTable.tsx +++ b/src/component/panels/RangesPanel/RangesTable.tsx @@ -1,6 +1,6 @@ import styled from '@emotion/styled'; import type { Info1D } from '@zakodium/nmr-types'; -import type { WorkSpacePanelPreferences } from '@zakodium/nmrium-core'; +import type { WorkspacePanelPreferences } from '@zakodium/nmrium-core'; import { FaLink } from 'react-icons/fa'; import { withDialog } from '../../elements/DialogManager.js'; @@ -61,7 +61,7 @@ const Table = styled.table` `; interface RangesTableProps extends TableContextMenuProps { - preferences: WorkSpacePanelPreferences['ranges']; + preferences: WorkspacePanelPreferences['ranges']; tableData: RangesTableDataRow[]; activeTab: string; info: Info1D; diff --git a/src/component/panels/RangesPanel/RangesTableRow.tsx b/src/component/panels/RangesPanel/RangesTableRow.tsx index 01471d5a01..b47f5aba8a 100644 --- a/src/component/panels/RangesPanel/RangesTableRow.tsx +++ b/src/component/panels/RangesPanel/RangesTableRow.tsx @@ -1,5 +1,5 @@ import type { Info1D } from '@zakodium/nmr-types'; -import type { WorkSpacePanelPreferences } from '@zakodium/nmrium-core'; +import type { WorkspacePanelPreferences } from '@zakodium/nmrium-core'; import type { CSSProperties, MouseEvent } from 'react'; import { useCallback, useMemo } from 'react'; @@ -35,7 +35,7 @@ const ConstantlyHighlightedRowStyle = { interface RangesTableRowProps extends TableContextMenuProps { rowData: RangeData; - preferences: WorkSpacePanelPreferences['ranges']; + preferences: WorkspacePanelPreferences['ranges']; info: Info1D; } diff --git a/src/component/panels/multipleAnalysisPanel/AnalysisChart.tsx b/src/component/panels/multipleAnalysisPanel/AnalysisChart.tsx index a9a3844431..b838cbe2ca 100644 --- a/src/component/panels/multipleAnalysisPanel/AnalysisChart.tsx +++ b/src/component/panels/multipleAnalysisPanel/AnalysisChart.tsx @@ -3,7 +3,7 @@ import { css } from '@emotion/react'; import type { JpathTableColumn, Spectrum, - WorkSpacePanelPreferences, + WorkspacePanelPreferences, } from '@zakodium/nmrium-core'; import dlv from 'dlv'; import type { ChangeEvent } from 'react'; @@ -82,7 +82,7 @@ function getPlotDataAsString( options: { plotOptions: PlotOptions; spectra: Spectrum[]; - spectraPanelPreferences: WorkSpacePanelPreferences['spectra']; + spectraPanelPreferences: WorkspacePanelPreferences['spectra']; }, ) { const { plotOptions, spectra, spectraPanelPreferences } = options; diff --git a/src/component/reducer/preferences/preferencesReducer.ts b/src/component/reducer/preferences/preferencesReducer.ts index c635a6823c..4494322761 100644 --- a/src/component/reducer/preferences/preferencesReducer.ts +++ b/src/component/reducer/preferences/preferencesReducer.ts @@ -9,8 +9,8 @@ import type { PanelPreferencesType, PanelsPreferences, PrintPageOptions, - WorkSpaceSource, Workspace, + WorkspaceSource, } from '@zakodium/nmrium-core'; import { CURRENT_EXPORT_VERSION, migrateSettings } from '@zakodium/nmrium-core'; import type { Draft } from 'immer'; @@ -223,7 +223,7 @@ export type PreferencesActions = | CutSpectraAnalysisAction | ToggleSplitPanelAction; -export type WorkspaceWithSource = Workspace & { source: WorkSpaceSource }; +export type WorkspaceWithSource = Workspace & { source: WorkspaceSource }; type WorkspacesWithSource = Record; export interface PreferencesState { diff --git a/src/component/reducer/preferences/utilities/initWorkspace.ts b/src/component/reducer/preferences/utilities/initWorkspace.ts index 535fb0b4b8..d50331b7a5 100644 --- a/src/component/reducer/preferences/utilities/initWorkspace.ts +++ b/src/component/reducer/preferences/utilities/initWorkspace.ts @@ -1,4 +1,4 @@ -import type { WorkSpaceSource } from '@zakodium/nmrium-core'; +import type { WorkspaceSource } from '@zakodium/nmrium-core'; import lodashMerge from 'lodash/merge.js'; import { workspaceDefaultProperties } from '../../../workspaces/workspaceDefaultProperties.js'; @@ -6,7 +6,7 @@ import type { WorkspaceWithSource } from '../preferencesReducer.js'; export function initWorkspace( preferences: any, - data: { source: WorkSpaceSource; label: string }, + data: { source: WorkspaceSource; label: string }, ): WorkspaceWithSource { return lodashMerge({}, workspaceDefaultProperties, preferences, data); } diff --git a/src/component/reducer/preferences/utilities/mapWorkspaces.ts b/src/component/reducer/preferences/utilities/mapWorkspaces.ts index 7d046d8a6e..9f539874aa 100644 --- a/src/component/reducer/preferences/utilities/mapWorkspaces.ts +++ b/src/component/reducer/preferences/utilities/mapWorkspaces.ts @@ -1,7 +1,7 @@ import type { - WorkSpaceSource, Workspace, WorkspacePreferences, + WorkspaceSource, } from '@zakodium/nmrium-core'; import lodashMerge from 'lodash/merge.js'; @@ -10,7 +10,7 @@ import { workspaceDefaultProperties } from '../../../workspaces/workspaceDefault interface MapWorkspacesOptions { ignoreKeys?: object; mergeWithDefaultProperties?: boolean; - source?: WorkSpaceSource; + source?: WorkspaceSource; } export function mapWorkspaces( diff --git a/src/component/toolbar/ToolTypes.ts b/src/component/toolbar/ToolTypes.ts index 1335d41f84..cc7ae044ab 100644 --- a/src/component/toolbar/ToolTypes.ts +++ b/src/component/toolbar/ToolTypes.ts @@ -1,5 +1,5 @@ import type { Info1D, Info2D } from '@zakodium/nmr-types'; -import type { NMRiumToolBarPreferences } from '@zakodium/nmrium-core'; +import type { NMRiumToolbarPreferences } from '@zakodium/nmrium-core'; import { Filters1D, Filters2D } from 'nmr-processing'; import type { DisplayerMode } from '../reducer/Reducer.js'; @@ -32,7 +32,7 @@ export interface ToolOptionItem { isExperimental?: true; } -export type MainTool = keyof NMRiumToolBarPreferences; +export type MainTool = keyof NMRiumToolbarPreferences; /** * Tools that are selectable in panels, not in the main toolbar. diff --git a/src/data/data1d/multipleSpectraAnalysis.ts b/src/data/data1d/multipleSpectraAnalysis.ts index 7a57a1a90f..6ce06db434 100644 --- a/src/data/data1d/multipleSpectraAnalysis.ts +++ b/src/data/data1d/multipleSpectraAnalysis.ts @@ -8,7 +8,7 @@ import type { SpectraAnalysisColumns, Spectrum1D, Spectrum, - WorkSpacePanelPreferences, + WorkspacePanelPreferences, } from '@zakodium/nmrium-core'; import { ANALYSIS_COLUMN_TYPES, @@ -314,7 +314,7 @@ function calculate( export function getDataAsString( spectraAnalysis: SpectraAnalysisData, spectra: Spectrum1D[], - spectraPanelPreferences: WorkSpacePanelPreferences['spectra'], + spectraPanelPreferences: WorkspacePanelPreferences['spectra'], ) { const spectraData = convertSpectraArrayToObject(spectra); if (spectraAnalysis) { From a17c5da30a57f5f1cab58c7a3cba2217dd7cdea2 Mon Sep 17 00:00:00 2001 From: hamed musallam Date: Mon, 29 Jun 2026 14:41:18 +0200 Subject: [PATCH 2/5] feat: support custom tick styles based on user preferences --- src/component/elements/D3Axis.tsx | 106 +++++++++++------- src/component/hooks/use_ticks_config.ts | 8 +- .../tabs/axis_tab.tsx | 42 ++++++- .../validation/axis_tab_validation.ts | 17 ++- .../workspaces/workspaceDefaultProperties.ts | 18 ++- 5 files changed, 136 insertions(+), 55 deletions(-) diff --git a/src/component/elements/D3Axis.tsx b/src/component/elements/D3Axis.tsx index e8770b165a..53931ead9c 100644 --- a/src/component/elements/D3Axis.tsx +++ b/src/component/elements/D3Axis.tsx @@ -24,9 +24,9 @@ type SecondaryGridElementProps = PrimaryGridElementProps & { interface D3AxisProps extends - BaseD3AxisProps, - Pick, 'transform' | 'children' | 'className'>, - UseLinearPrimaryTicksResult { + BaseD3AxisProps, + Pick, 'transform' | 'children' | 'className'>, + UseLinearPrimaryTicksResult { gridSize: number; primaryGridProps?: PrimaryGridElementProps; secondaryGridProps?: SecondaryGridElementProps; @@ -35,9 +35,9 @@ interface D3AxisProps showSecondaryGrid?: boolean; } -interface TicketsProps extends UseLinearPrimaryTicksResult, BaseD3AxisProps {} +interface TicketsProps extends UseLinearPrimaryTicksResult, BaseD3AxisProps { } interface BaseLineProps - extends Pick, BaseD3AxisProps {} + extends Pick, BaseD3AxisProps { } interface GridProps extends UseLinearPrimaryTicksResult { axisPosition: AxisPosition; @@ -51,6 +51,8 @@ function isVerticalAxis(axisPosition: AxisPosition) { function BaseLine(props: BaseLineProps) { const { axisPosition, tickLength = 6, scale } = props; + const { primaryTicks } = useTicksConfig(); + const [x1, x2] = scale.range(); const sign = ['left', 'top'].includes(axisPosition) ? -1 : 1; @@ -60,12 +62,20 @@ function BaseLine(props: BaseLineProps) { path = `M${sign * tickLength},${x2} H0 V${x1} H${sign * tickLength}`; } - return ; + return ( + + ); } function Tickets(props: TicketsProps) { const { ticks, tickLength = 6, axisPosition } = props; - const config = useTicksConfig(); + const { primaryTicks, secondaryTicks } = useTicksConfig(); if (!Array.isArray(ticks) || ticks.length === 0) return null; @@ -75,15 +85,15 @@ function Tickets(props: TicketsProps) { const positionTextConfig: SVGStyledTextProps = isVertical ? { - x: positionSign * (tickLength + 3), - dy: '0.32em', - textAnchor: positionSign === -1 ? 'end' : 'start', - } + x: positionSign * (tickLength + 3), + dy: '0.32em', + textAnchor: positionSign === -1 ? 'end' : 'start', + } : { - y: positionSign * (tickLength + 3), - dy: positionSign === -1 ? '0em' : '0.71em', - textAnchor: 'middle', - }; + y: positionSign * (tickLength + 3), + dy: positionSign === -1 ? '0em' : '0.71em', + textAnchor: 'middle', + }; const positionPrimaryLineConfig: SVGStyledLineProps = isVertical ? { x1: positionSign * tickLength, x2: 0 } @@ -93,30 +103,30 @@ function Tickets(props: TicketsProps) { const secondaryTickOffset = getSecondaryTickOffset(ticks, positionSign); const positionSecondaryLineConfig: SVGStyledLineProps = isVertical ? { - x1: positionSign * secondaryTickLength, - x2: 0, - y1: secondaryTickOffset, - y2: secondaryTickOffset, - } + x1: positionSign * secondaryTickLength, + x2: 0, + y1: secondaryTickOffset, + y2: secondaryTickOffset, + } : { - y1: positionSign * secondaryTickLength, - y2: 0, - x1: secondaryTickOffset, - x2: secondaryTickOffset, - }; + y1: positionSign * secondaryTickLength, + y2: 0, + x1: secondaryTickOffset, + x2: secondaryTickOffset, + }; const positionSecondaryFirstLineConfig: SVGStyledLineProps = isVertical ? { - x1: positionSign * secondaryTickLength, - x2: 0, - y1: -secondaryTickOffset, - y2: -secondaryTickOffset, - } + x1: positionSign * secondaryTickLength, + x2: 0, + y1: -secondaryTickOffset, + y2: -secondaryTickOffset, + } : { - y1: positionSign * secondaryTickLength, - y2: 0, - x1: -secondaryTickOffset, - x2: -secondaryTickOffset, - }; + y1: positionSign * secondaryTickLength, + y2: 0, + x1: -secondaryTickOffset, + x2: -secondaryTickOffset, + }; return ticks.map(({ label, position }, index) => { const isFirst = index === 0; @@ -127,19 +137,31 @@ function Tickets(props: TicketsProps) { transform={`translate(${isVertical ? `0,${position}` : `${position},0`})`} className="tick" > - {config.isSecondaryEnabled && isFirst && ( - + {secondaryTicks.enabled && isFirst && ( + )} - - - {config.isSecondaryEnabled && ( - + + + {secondaryTicks.enabled && ( + )} {label} diff --git a/src/component/hooks/use_ticks_config.ts b/src/component/hooks/use_ticks_config.ts index 21915ade40..f5d23f941a 100644 --- a/src/component/hooks/use_ticks_config.ts +++ b/src/component/hooks/use_ticks_config.ts @@ -5,11 +5,5 @@ export function useTicksConfig() { const { current } = usePreferences(); const axis = current.axis ?? workspaceDefaultProperties.axis; - const { textStyle } = axis.primaryTicks; - const { enabled } = axis.secondaryTicks; - - return { - textStyle, - isSecondaryEnabled: enabled, - }; + return axis; } diff --git a/src/component/modal/setting/tanstack_general_settings/tabs/axis_tab.tsx b/src/component/modal/setting/tanstack_general_settings/tabs/axis_tab.tsx index 1fff99a75d..337f2cbc88 100644 --- a/src/component/modal/setting/tanstack_general_settings/tabs/axis_tab.tsx +++ b/src/component/modal/setting/tanstack_general_settings/tabs/axis_tab.tsx @@ -32,10 +32,48 @@ const TicksSection = withFieldGroup({ -
+ + {(field) => } + + + {(field) => ( + + )} + + + {(field) => } + + + + {(field) => ( + + )} + + + {(field) => ( + + )} + + + {(field) => } + {({ Checkbox }) => } diff --git a/src/component/modal/setting/tanstack_general_settings/validation/axis_tab_validation.ts b/src/component/modal/setting/tanstack_general_settings/validation/axis_tab_validation.ts index a4bb03df07..f8eab7f31e 100644 --- a/src/component/modal/setting/tanstack_general_settings/validation/axis_tab_validation.ts +++ b/src/component/modal/setting/tanstack_general_settings/validation/axis_tab_validation.ts @@ -14,10 +14,23 @@ const gridlinesValidation = z.object({ secondary: gridlineValidation, }); +const primaryTicksValidation = z.object({ + textStyle: svgTextStyleFieldsSchema, + tickStyle: svgLineStyleFieldsSchema.omit({ + strokeDasharray: true, + }), +}); +const secondaryTicksValidation = z.object({ + enabled: z.boolean(), + tickStyle: svgLineStyleFieldsSchema.omit({ + strokeDasharray: true, + }), +}); + export const axisValidation = z .object({ - primaryTicks: z.object({ textStyle: svgTextStyleFieldsSchema }), - secondaryTicks: z.object({ enabled: z.boolean() }), + primaryTicks: primaryTicksValidation, + secondaryTicks: secondaryTicksValidation, gridlines1D: gridlinesValidation, gridlines2D: gridlinesValidation, }) diff --git a/src/component/workspaces/workspaceDefaultProperties.ts b/src/component/workspaces/workspaceDefaultProperties.ts index 5749a4744e..c60e174e28 100644 --- a/src/component/workspaces/workspaceDefaultProperties.ts +++ b/src/component/workspaces/workspaceDefaultProperties.ts @@ -77,8 +77,22 @@ export const workspaceDefaultProperties: RequiredWorkspacePreferences = { } satisfies Required, axis: { - secondaryTicks: { enabled: true }, - primaryTicks: { textStyle: { fontSize: 10 } }, + secondaryTicks: { + enabled: true, + tickStyle: { + strokeWidth: 1, + strokeOpacity: 1, + stroke: '#000000', + }, + }, + primaryTicks: { + textStyle: { fontSize: 10 }, + tickStyle: { + strokeWidth: 1, + strokeOpacity: 1, + stroke: '#000000', + }, + }, gridlines1D: { primary: { enabled: true, From 212ab08c4e2e7c2c755171c6cc181c12e32dc982 Mon Sep 17 00:00:00 2001 From: hamed musallam Date: Mon, 29 Jun 2026 15:19:55 +0200 Subject: [PATCH 3/5] feat: add custom axis label styling based on user preferences --- src/component/1d/HorizontalAxis1D.tsx | 14 ++- src/component/2d/DirectAxis2D.tsx | 15 ++- src/component/2d/IndirectAxis2D.tsx | 14 ++- src/component/elements/D3Axis.tsx | 66 +++++------ .../tabs/axis_tab.tsx | 108 ++++++++++-------- .../validation/axis_tab_validation.ts | 1 + .../workspaces/workspaceDefaultProperties.ts | 3 + 7 files changed, 129 insertions(+), 92 deletions(-) diff --git a/src/component/1d/HorizontalAxis1D.tsx b/src/component/1d/HorizontalAxis1D.tsx index efa58ee1b7..4d8086cc40 100644 --- a/src/component/1d/HorizontalAxis1D.tsx +++ b/src/component/1d/HorizontalAxis1D.tsx @@ -1,5 +1,6 @@ import { useMemo, useRef } from 'react'; import { useLinearPrimaryTicks } from 'react-d3-utils'; +import { SVGStyledText } from 'react-science/ui'; import { AxisUnitPicker } from '../1d-2d/components/axis_unit_picker.tsx'; import { useChartData } from '../context/ChartContext.js'; @@ -11,6 +12,7 @@ import { useHorizontalAxisUnit, } from '../hooks/use_axis_unit.ts'; import { useGridline1DConfig } from '../hooks/use_gridlines_config.ts'; +import { useTicksConfig } from '../hooks/use_ticks_config.ts'; import { useIsInset } from './inset/InsetProvider.js'; @@ -33,6 +35,7 @@ export function HorizontalAxis1D() { 'horizontal', refAxis, ); + const { labelStyle } = useTicksConfig(); const gridConfig = useGridline1DConfig(); if (!width || !height) { @@ -59,9 +62,16 @@ export function HorizontalAxis1D() { allowedUnits={allowedUnits} onChange={setUnit} > - + {unitLabel} - +
)} diff --git a/src/component/2d/DirectAxis2D.tsx b/src/component/2d/DirectAxis2D.tsx index 9fc3be3639..3acf61cd1c 100644 --- a/src/component/2d/DirectAxis2D.tsx +++ b/src/component/2d/DirectAxis2D.tsx @@ -1,5 +1,6 @@ import { memo, useRef } from 'react'; import { useLinearPrimaryTicks } from 'react-d3-utils'; +import { SVGStyledText } from 'react-science/ui'; import { useIsInset } from '../1d/inset/InsetProvider.tsx'; import { AxisUnitPicker } from '../1d-2d/components/axis_unit_picker.tsx'; @@ -8,6 +9,7 @@ import { D3Axis } from '../elements/D3Axis.js'; import { useCheckExportStatus } from '../hooks/useViewportSize.tsx'; import { axisUnitToLabel, useDirectAxisUnit } from '../hooks/use_axis_unit.ts'; import { useGridline2DConfig } from '../hooks/use_gridlines_config.ts'; +import { useTicksConfig } from '../hooks/use_ticks_config.ts'; import { useScale2DX } from './utilities/scale.js'; @@ -93,11 +95,18 @@ interface UnitLabelProps { } function UnitLabel(props: UnitLabelProps) { const { width, children } = props; - + const { labelStyle } = useTicksConfig(); return ( - + {children} - + ); } diff --git a/src/component/2d/IndirectAxis2D.tsx b/src/component/2d/IndirectAxis2D.tsx index 88845069d0..8e6668a284 100644 --- a/src/component/2d/IndirectAxis2D.tsx +++ b/src/component/2d/IndirectAxis2D.tsx @@ -1,5 +1,6 @@ import { memo, useRef } from 'react'; import { useLinearPrimaryTicks } from 'react-d3-utils'; +import { SVGStyledText } from 'react-science/ui'; import { useIsInset } from '../1d/inset/InsetProvider.tsx'; import { AxisUnitPicker } from '../1d-2d/components/axis_unit_picker.tsx'; @@ -13,6 +14,7 @@ import { useIndirectAxisUnit, } from '../hooks/use_axis_unit.ts'; import { useGridline2DConfig } from '../hooks/use_gridlines_config.ts'; +import { useTicksConfig } from '../hooks/use_ticks_config.ts'; import { useScale2DY } from './utilities/scale.js'; @@ -108,8 +110,8 @@ interface UnitLabelProps { } function UnitLabel(props: UnitLabelProps) { const { children } = props; - - const { getTextWidth } = useTextMetrics({ labelSize: 10 }); + const { labelStyle } = useTicksConfig(); + const { getTextWidth } = useTextMetrics({ labelSize: labelStyle.fontSize }); const labelHeight = getTextWidth(children); return ( @@ -124,14 +126,16 @@ function UnitLabel(props: UnitLabelProps) { y={-5} opacity={0.8} /> - {children} - + ); } diff --git a/src/component/elements/D3Axis.tsx b/src/component/elements/D3Axis.tsx index 53931ead9c..1c838edfae 100644 --- a/src/component/elements/D3Axis.tsx +++ b/src/component/elements/D3Axis.tsx @@ -24,9 +24,9 @@ type SecondaryGridElementProps = PrimaryGridElementProps & { interface D3AxisProps extends - BaseD3AxisProps, - Pick, 'transform' | 'children' | 'className'>, - UseLinearPrimaryTicksResult { + BaseD3AxisProps, + Pick, 'transform' | 'children' | 'className'>, + UseLinearPrimaryTicksResult { gridSize: number; primaryGridProps?: PrimaryGridElementProps; secondaryGridProps?: SecondaryGridElementProps; @@ -35,9 +35,9 @@ interface D3AxisProps showSecondaryGrid?: boolean; } -interface TicketsProps extends UseLinearPrimaryTicksResult, BaseD3AxisProps { } +interface TicketsProps extends UseLinearPrimaryTicksResult, BaseD3AxisProps {} interface BaseLineProps - extends Pick, BaseD3AxisProps { } + extends Pick, BaseD3AxisProps {} interface GridProps extends UseLinearPrimaryTicksResult { axisPosition: AxisPosition; @@ -85,15 +85,15 @@ function Tickets(props: TicketsProps) { const positionTextConfig: SVGStyledTextProps = isVertical ? { - x: positionSign * (tickLength + 3), - dy: '0.32em', - textAnchor: positionSign === -1 ? 'end' : 'start', - } + x: positionSign * (tickLength + 3), + dy: '0.32em', + textAnchor: positionSign === -1 ? 'end' : 'start', + } : { - y: positionSign * (tickLength + 3), - dy: positionSign === -1 ? '0em' : '0.71em', - textAnchor: 'middle', - }; + y: positionSign * (tickLength + 3), + dy: positionSign === -1 ? '0em' : '0.71em', + textAnchor: 'middle', + }; const positionPrimaryLineConfig: SVGStyledLineProps = isVertical ? { x1: positionSign * tickLength, x2: 0 } @@ -103,30 +103,30 @@ function Tickets(props: TicketsProps) { const secondaryTickOffset = getSecondaryTickOffset(ticks, positionSign); const positionSecondaryLineConfig: SVGStyledLineProps = isVertical ? { - x1: positionSign * secondaryTickLength, - x2: 0, - y1: secondaryTickOffset, - y2: secondaryTickOffset, - } + x1: positionSign * secondaryTickLength, + x2: 0, + y1: secondaryTickOffset, + y2: secondaryTickOffset, + } : { - y1: positionSign * secondaryTickLength, - y2: 0, - x1: secondaryTickOffset, - x2: secondaryTickOffset, - }; + y1: positionSign * secondaryTickLength, + y2: 0, + x1: secondaryTickOffset, + x2: secondaryTickOffset, + }; const positionSecondaryFirstLineConfig: SVGStyledLineProps = isVertical ? { - x1: positionSign * secondaryTickLength, - x2: 0, - y1: -secondaryTickOffset, - y2: -secondaryTickOffset, - } + x1: positionSign * secondaryTickLength, + x2: 0, + y1: -secondaryTickOffset, + y2: -secondaryTickOffset, + } : { - y1: positionSign * secondaryTickLength, - y2: 0, - x1: -secondaryTickOffset, - x2: -secondaryTickOffset, - }; + y1: positionSign * secondaryTickLength, + y2: 0, + x1: -secondaryTickOffset, + x2: -secondaryTickOffset, + }; return ticks.map(({ label, position }, index) => { const isFirst = index === 0; diff --git a/src/component/modal/setting/tanstack_general_settings/tabs/axis_tab.tsx b/src/component/modal/setting/tanstack_general_settings/tabs/axis_tab.tsx index 337f2cbc88..3eba912449 100644 --- a/src/component/modal/setting/tanstack_general_settings/tabs/axis_tab.tsx +++ b/src/component/modal/setting/tanstack_general_settings/tabs/axis_tab.tsx @@ -28,56 +28,66 @@ const TicksSection = withFieldGroup({ const { AppField, Section } = group; return ( -
- - - {(field) => } - - - {(field) => ( - - )} - - - {(field) => } - + <> +
+ +
+
+ + + {(field) => } + + + {(field) => ( + + )} + + + {(field) => } + +
- - {(field) => ( - - )} - - - {(field) => ( - - )} - - - {(field) => } - - - {({ Checkbox }) => } - -
+
+ + {({ Checkbox }) => } + + + {(field) => } + + + {(field) => ( + + )} + + + {(field) => } + +
+ ); }, }); diff --git a/src/component/modal/setting/tanstack_general_settings/validation/axis_tab_validation.ts b/src/component/modal/setting/tanstack_general_settings/validation/axis_tab_validation.ts index f8eab7f31e..c6f707f598 100644 --- a/src/component/modal/setting/tanstack_general_settings/validation/axis_tab_validation.ts +++ b/src/component/modal/setting/tanstack_general_settings/validation/axis_tab_validation.ts @@ -29,6 +29,7 @@ const secondaryTicksValidation = z.object({ export const axisValidation = z .object({ + labelStyle: svgTextStyleFieldsSchema, primaryTicks: primaryTicksValidation, secondaryTicks: secondaryTicksValidation, gridlines1D: gridlinesValidation, diff --git a/src/component/workspaces/workspaceDefaultProperties.ts b/src/component/workspaces/workspaceDefaultProperties.ts index c60e174e28..a4b9e2ecb8 100644 --- a/src/component/workspaces/workspaceDefaultProperties.ts +++ b/src/component/workspaces/workspaceDefaultProperties.ts @@ -77,6 +77,9 @@ export const workspaceDefaultProperties: RequiredWorkspacePreferences = { } satisfies Required, axis: { + labelStyle: { + fontSize: 10, + }, secondaryTicks: { enabled: true, tickStyle: { From 175737eb4c47b63d96edfb0b1749756f1183c305 Mon Sep 17 00:00:00 2001 From: hamed musallam Date: Mon, 29 Jun 2026 16:18:31 +0200 Subject: [PATCH 4/5] refactor: rename label 'Secondary width' to 'Width' --- .../modal/setting/tanstack_general_settings/tabs/axis_tab.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/component/modal/setting/tanstack_general_settings/tabs/axis_tab.tsx b/src/component/modal/setting/tanstack_general_settings/tabs/axis_tab.tsx index 3eba912449..85de9f8a3a 100644 --- a/src/component/modal/setting/tanstack_general_settings/tabs/axis_tab.tsx +++ b/src/component/modal/setting/tanstack_general_settings/tabs/axis_tab.tsx @@ -84,7 +84,7 @@ const TicksSection = withFieldGroup({ )} - {(field) => } + {(field) => } From c45c1ae81e781cdd35cdb5d5df83c9d5c5d7d3e5 Mon Sep 17 00:00:00 2001 From: hamed musallam Date: Wed, 1 Jul 2026 14:55:37 +0200 Subject: [PATCH 5/5] refactor: primary ticks section layout --- .../tabs/axis_tab.tsx | 54 ++++++++++++------- 1 file changed, 35 insertions(+), 19 deletions(-) diff --git a/src/component/modal/setting/tanstack_general_settings/tabs/axis_tab.tsx b/src/component/modal/setting/tanstack_general_settings/tabs/axis_tab.tsx index 85de9f8a3a..3dbfffed71 100644 --- a/src/component/modal/setting/tanstack_general_settings/tabs/axis_tab.tsx +++ b/src/component/modal/setting/tanstack_general_settings/tabs/axis_tab.tsx @@ -1,3 +1,4 @@ +import styled from '@emotion/styled'; import { FieldGroupSVGLineStyleFields, FieldGroupSVGTextStyleFields, @@ -9,6 +10,18 @@ import type { z } from 'zod'; import type { gridlineValidation } from '../validation/axis_tab_validation.ts'; import { defaultGeneralSettingsFormValues } from '../validation.ts'; +// TODO: Expose the Fieldset and Legend components in react-science/ui package +const Fieldset = styled.fieldset` + display: block; + border-top: 1px lightgrey groove; + min-inline-size: min-content; +`; + +const Legend = styled.legend` + display: block; + padding-inline-end: 5px; +`; + export const AxisTab = withForm({ defaultValues: defaultGeneralSettingsFormValues, render: ({ form }) => { @@ -41,27 +54,30 @@ const TicksSection = withFieldGroup({ - - {(field) => } - - - {(field) => ( - - )} - - - {(field) => } - +
+ Line style + + {(field) => } + + + {(field) => ( + + )} + + + {(field) => } + +