diff --git a/package-lock.json b/package-lock.json index ad0a1526a..edd06acc2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,8 +16,8 @@ "@tanstack/react-store": "^0.11.0", "@tanstack/react-table": "^8.21.3", "@zakodium/nmr-types": "^0.5.18", - "@zakodium/nmrium-core": "^0.7.37", - "@zakodium/nmrium-core-plugins": "^0.7.50", + "@zakodium/nmrium-core": "^0.7.40", + "@zakodium/nmrium-core-plugins": "^0.7.53", "@zakodium/pdnd-esm": "^1.1.0", "@zakodium/utils": "^0.2.0", "@zip.js/zip.js": "^2.8.26", @@ -3970,9 +3970,9 @@ } }, "node_modules/@zakodium/nmrium-core": { - "version": "0.7.37", - "resolved": "https://registry.npmjs.org/@zakodium/nmrium-core/-/nmrium-core-0.7.37.tgz", - "integrity": "sha512-jlehjYSNiuvYTcoMi2jgihmCC/PMQqorUYlnrlSN1zUMvWHlMXMrB9a+nfHRlCXnMNkPNCEINLTwacGKqiWhLg==", + "version": "0.7.40", + "resolved": "https://registry.npmjs.org/@zakodium/nmrium-core/-/nmrium-core-0.7.40.tgz", + "integrity": "sha512-dyy4MsGWDbXA4/yCnpCgj7aIp31+IEWjGafJNeAIsv7vRbv1Sus5FkPCyLP/fubI2sfaJxPoHboJ/aOVybQjug==", "license": "CC-BY-NC-SA-4.0", "dependencies": { "@zakodium/utils": "^0.2.0", @@ -3989,24 +3989,24 @@ } }, "node_modules/@zakodium/nmrium-core-plugins": { - "version": "0.7.50", - "resolved": "https://registry.npmjs.org/@zakodium/nmrium-core-plugins/-/nmrium-core-plugins-0.7.50.tgz", - "integrity": "sha512-n+ypOorejkk/6MFhnjIo/5qUKRYssxyy1QBDRwPKlq0g2MuG+f9QXxpEBs7IENdYr3GYatJdYHkrIbtf9pHwXQ==", + "version": "0.7.53", + "resolved": "https://registry.npmjs.org/@zakodium/nmrium-core-plugins/-/nmrium-core-plugins-0.7.53.tgz", + "integrity": "sha512-bX0UoCMfDHnFOyrD0PdaQIvxZGisWGST4/qABefWwHa+5b/VJuKcpLR5FIMDzgEm8IcmqFoCev4OT31aNC1CbA==", "license": "CC-BY-NC-SA-4.0", "dependencies": { "@date-fns/utc": "^2.1.1", - "@zakodium/nmrium-core": "^0.7.37", + "@zakodium/nmrium-core": "^0.7.40", "cheminfo-types": "^1.15.0", "convert-to-jcamp": "^7.0.0", "date-fns": "^4.4.0", "file-collection": "^6.6.1", "gyromagnetic-ratio": "^2.0.0", "is-any-array": "^3.0.0", - "jcampconverter": "^12.5.0", + "jcampconverter": "^12.5.1", "linear-sum-assignment": "^1.0.9", "lodash.merge": "^4.6.2", "ml-spectra-processing": "^14.29.1", - "nmr-processing": "^22.19.0", + "nmr-processing": "^22.19.1", "openchemlib": "^9.23.0", "openchemlib-utils": "^8.17.0", "sdf-parser": "^9.0.0", @@ -8432,9 +8432,9 @@ } }, "node_modules/jcampconverter": { - "version": "12.5.0", - "resolved": "https://registry.npmjs.org/jcampconverter/-/jcampconverter-12.5.0.tgz", - "integrity": "sha512-aEHivNTxqZFMPSR7HHA+37KlqLUMlLwAjtmwgq72jM1VolZ9k1/tEwvDALFbu5RdtP8sMITPcaGl2UhJ+rP4NQ==", + "version": "12.5.1", + "resolved": "https://registry.npmjs.org/jcampconverter/-/jcampconverter-12.5.1.tgz", + "integrity": "sha512-vTYX9xcDBkPRK1qeGd2ejtEQmNKs+qXG7EOEFDgyoH0BKC+PQUmERp/GQAI0Xat0Ro/So+IgGfRLJ+kHA9stOw==", "license": "CC-BY-NC-SA-4.0", "dependencies": { "cheminfo-types": "^1.15.0", @@ -9680,9 +9680,9 @@ } }, "node_modules/nmr-processing": { - "version": "22.19.0", - "resolved": "https://registry.npmjs.org/nmr-processing/-/nmr-processing-22.19.0.tgz", - "integrity": "sha512-GUJVa6ZrdPshoxeVRhvq9rkNEM0ILkjnLQO1MgGVYRNrAoqHM28ykyLF0UFNp8U+5OKN54cpZ8rnTLvkzC0M3A==", + "version": "22.19.1", + "resolved": "https://registry.npmjs.org/nmr-processing/-/nmr-processing-22.19.1.tgz", + "integrity": "sha512-xNTa3A+mqoVOXwm73o39japJlpQaeLyl7iK+FXkkLteiP4BOvbwjm+mkc7vou/QIid8XbP1m3+hyb9MWuo+iAQ==", "license": "CC-BY-NC-SA-4.0", "dependencies": { "binary-search": "^1.3.6", diff --git a/package.json b/package.json index 1bd813bf3..6b31cff3e 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,7 @@ "clean-lib": "rimraf lib", "cspell": "cspell lint \"**/*.tsx\"", "dev": "vite --host localhost --port 3000 --open", - "eslint": "eslint . --cache --max-warnings=102", + "eslint": "eslint . --cache --max-warnings=103", "eslint-fix": "node --run eslint -- --fix", "install:clean": "rm -rf node_modules/ && rm -rf package-lock.json && npm install && npm start", "knip": "knip", @@ -70,8 +70,8 @@ "@tanstack/react-store": "^0.11.0", "@tanstack/react-table": "^8.21.3", "@zakodium/nmr-types": "^0.5.18", - "@zakodium/nmrium-core": "^0.7.37", - "@zakodium/nmrium-core-plugins": "^0.7.50", + "@zakodium/nmrium-core": "^0.7.40", + "@zakodium/nmrium-core-plugins": "^0.7.53", "@zakodium/pdnd-esm": "^1.1.0", "@zakodium/utils": "^0.2.0", "@zip.js/zip.js": "^2.8.26", diff --git a/src/component/1d/HorizontalAxis1D.tsx b/src/component/1d/HorizontalAxis1D.tsx index efa58ee1b..4d8086cc4 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 9fc3be363..3acf61cd1 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 88845069d..8e6668a28 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 e8770b165..1c838edfa 100644 --- a/src/component/elements/D3Axis.tsx +++ b/src/component/elements/D3Axis.tsx @@ -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; @@ -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 21915ade4..f5d23f941 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 1fff99a75..3dbfffed7 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 }) => { @@ -28,18 +41,69 @@ const TicksSection = withFieldGroup({ const { AppField, Section } = group; return ( -
- -
- - {({ Checkbox }) => } - -
+ <> +
+ +
+
+ +
+ Line style + + {(field) => } + + + {(field) => ( + + )} + + + {(field) => } + +
+
+ +
+ + {({ 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 a4bb03df0..c6f707f59 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,24 @@ 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() }), + labelStyle: svgTextStyleFieldsSchema, + primaryTicks: primaryTicksValidation, + secondaryTicks: secondaryTicksValidation, gridlines1D: gridlinesValidation, gridlines2D: gridlinesValidation, }) diff --git a/src/component/workspaces/workspaceDefaultProperties.ts b/src/component/workspaces/workspaceDefaultProperties.ts index 5749a4744..a4b9e2ecb 100644 --- a/src/component/workspaces/workspaceDefaultProperties.ts +++ b/src/component/workspaces/workspaceDefaultProperties.ts @@ -77,8 +77,25 @@ export const workspaceDefaultProperties: RequiredWorkspacePreferences = { } satisfies Required, axis: { - secondaryTicks: { enabled: true }, - primaryTicks: { textStyle: { fontSize: 10 } }, + labelStyle: { + 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,