diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml
index 3d7cd3457..42872cfd4 100644
--- a/.github/workflows/e2e.yml
+++ b/.github/workflows/e2e.yml
@@ -8,7 +8,7 @@ on:
jobs:
e2e:
- runs-on: macos-latest
+ runs-on: ubuntu-latest
strategy:
matrix:
project: [chromium, firefox, webkit]
diff --git a/package-lock.json b/package-lock.json
index 08331a9e8..f80f7a062 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -14,6 +14,7 @@
"@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.1",
"@hookform/resolvers": "^5.2.2",
+ "@tanstack/react-form": "^1.23.8",
"@zakodium/nmr-types": "^0.5.0",
"@zakodium/nmrium-core": "^0.5.0",
"@zakodium/nmrium-core-plugins": "^0.6.18",
@@ -58,10 +59,11 @@
"react-ocl-nmr": "^4.1.1",
"react-plot": "^3.1.2",
"react-rnd": "^10.5.2",
- "react-science": "^19.3.1",
+ "react-science": "^19.4.0",
"react-table": "^7.8.0",
"smart-array-filter": "^5.0.0",
- "yup": "^1.7.1"
+ "yup": "^1.7.1",
+ "zod": "^4.1.12"
},
"devDependencies": {
"@blueprintjs/core": "^6.3.4",
@@ -10643,9 +10645,9 @@
}
},
"node_modules/react-science": {
- "version": "19.3.1",
- "resolved": "https://registry.npmjs.org/react-science/-/react-science-19.3.1.tgz",
- "integrity": "sha512-qgkf0mdoUMFLIVfNWMN6sijdGlnEagd/s9mqXJPvSu/iJbL0f6Zvzn1cC8H2vbyHr44JkTT2cFKOERQMjDwmyg==",
+ "version": "19.4.0",
+ "resolved": "https://registry.npmjs.org/react-science/-/react-science-19.4.0.tgz",
+ "integrity": "sha512-VHsyk3dY5sTaZ1FYViauQ6VZtrx3Ksnbo00zUr0fmd2uZ2cLJa5qDgiYkWAzdZ59AAMvccWuxcSH1ba8Q+QpPg==",
"license": "MIT",
"dependencies": {
"@atlaskit/pragmatic-drag-and-drop": "^1.7.7",
diff --git a/package.json b/package.json
index 867c10eff..0f37e66ee 100644
--- a/package.json
+++ b/package.json
@@ -68,6 +68,7 @@
"@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.1",
"@hookform/resolvers": "^5.2.2",
+ "@tanstack/react-form": "^1.23.8",
"@zakodium/nmr-types": "^0.5.0",
"@zakodium/nmrium-core": "^0.5.0",
"@zakodium/nmrium-core-plugins": "^0.6.18",
@@ -112,10 +113,11 @@
"react-ocl-nmr": "^4.1.1",
"react-plot": "^3.1.2",
"react-rnd": "^10.5.2",
- "react-science": "^19.3.1",
+ "react-science": "^19.4.0",
"react-table": "^7.8.0",
"smart-array-filter": "^5.0.0",
- "yup": "^1.7.1"
+ "yup": "^1.7.1",
+ "zod": "^4.1.12"
},
"devDependencies": {
"@blueprintjs/core": "^6.3.4",
diff --git a/src/component/hooks/useSaveSettings.tsx b/src/component/hooks/useSaveSettings.tsx
index ef9ed40fb..5f8923158 100644
--- a/src/component/hooks/useSaveSettings.tsx
+++ b/src/component/hooks/useSaveSettings.tsx
@@ -1,124 +1,111 @@
-import { Dialog, DialogBody, DialogFooter } from '@blueprintjs/core';
-import styled from '@emotion/styled';
-import { yupResolver } from '@hookform/resolvers/yup';
+import { Button, Dialog, DialogBody, DialogFooter } from '@blueprintjs/core';
+import { revalidateLogic } from '@tanstack/react-form';
import type { Workspace } from '@zakodium/nmrium-core';
import { useRef } from 'react';
-import { useForm } from 'react-hook-form';
-import { useOnOff } from 'react-science/ui';
-import * as Yup from 'yup';
+import { useForm as useReactScienceForm, useOnOff } from 'react-science/ui';
+import { z } from 'zod/v4';
import { usePreferences } from '../context/PreferencesContext.js';
import { useToaster } from '../context/ToasterContext.js';
-import ActionButtons from '../elements/ActionButtons.js';
-import { Input2Controller } from '../elements/Input2Controller.js';
import { useWorkspaceAction } from './useWorkspaceAction.js';
-const schema = Yup.object().shape({
- workspaceName: Yup.string().required(),
+const schema = z.object({
+ workspaceName: z
+ .string()
+ .trim()
+ .min(1, { error: 'Workspace name must have at least one character' }),
});
-function WorkspaceAddForm(props: any) {
- const { className, message, control, onEnter } = props;
-
- return (
-
-
{message}
-
{
- if (event.key === 'Enter') {
- onEnter();
- }
- }}
- />
-
- );
-}
-
export function useSaveSettings() {
const toaster = useToaster();
const [isOpenDialog, openDialog, closeDialog] = useOnOff(false);
const settingsRef = useRef();
const { current } = usePreferences();
- const { handleSubmit, control, reset } = useForm({
- defaultValues: { workspaceName: '' },
- resolver: yupResolver(schema),
- });
+
const { saveWorkspace, addNewWorkspace } = useWorkspaceAction();
- function handleAddNewWorkspace({ workspaceName }: { workspaceName: string }) {
- addNewWorkspace(workspaceName, settingsRef.current);
- closeDialog();
- toaster.show({
- message: 'Preferences saved successfully',
- intent: 'success',
- });
- }
+ const form = useReactScienceForm({
+ defaultValues: { workspaceName: '' },
+ validationLogic: revalidateLogic({ modeAfterSubmission: 'change' }),
+ validators: { onDynamic: schema },
+ onSubmit: ({ value }) => {
+ const { workspaceName } = value;
+ addNewWorkspace(workspaceName, settingsRef.current);
+ closeDialog();
+
+ toaster.show({
+ message: 'Preferences saved successfully',
+ intent: 'success',
+ });
+ },
+ });
function saveSettings(values?: Partial) {
settingsRef.current = values as Workspace;
if (current.source !== 'user') {
- reset({ workspaceName: '' });
+ form.reset();
openDialog();
} else {
saveWorkspace(values);
-
closeDialog();
}
}
+
return {
saveSettings,
SaveSettingsModal: () => {
return (
);
},
};
}
-
-const DialogContent = styled(DialogBody)`
- background-color: white;
- text-align: center;
-`;
-
-const Title = styled.p`
- font-size: 1em;
- font-weight: bold;
- padding: 0 30px;
- text-align: left;
-`;
diff --git a/test-e2e/panels/spectra.test.ts b/test-e2e/panels/spectra.test.ts
index 8482ccb9b..045e6fac3 100644
--- a/test-e2e/panels/spectra.test.ts
+++ b/test-e2e/panels/spectra.test.ts
@@ -29,7 +29,7 @@ test('Check if the color picker is visible after click on the ColorIndicator', a
const nmrium = await NmriumPage.create(page);
await nmrium.open2D();
await nmrium.page.click('_react=SpectraTabs >> _react=Tab[tabid="1H,1H"]');
- const sketchPicker = nmrium.page.locator('_react=ColorPicker');
+ const sketchPicker = nmrium.page.locator('_react=Saturation');
await expect(sketchPicker).toHaveCount(0);
await nmrium.page.click('_react=ColorIndicator >> nth=0');
@@ -70,7 +70,7 @@ test('Check change spectrum color, Should be white', async ({ page }) => {
await nmrium.page.click('_react=ColorIndicator');
// Click on the top-left of the color picker (white)
- await nmrium.page.click('_react=ColorPicker >> div >> nth=0', {
+ await nmrium.page.click('_react=Saturation', {
position: { x: 0, y: 0 },
});
@@ -128,7 +128,7 @@ test('2d spectrum', async ({ page }) => {
await nmrium.page.click('_react=ColorIndicator');
// change the color to #ddb1c9ff
- await nmrium.page.click('_react=ColorPicker >> div >> nth=0', {
+ await nmrium.page.click('_react=Saturation', {
position: { x: 40, y: 20 },
});
@@ -145,7 +145,7 @@ test('2d spectrum', async ({ page }) => {
// Close color picker
await nmrium.viewer.locator.click({ force: true });
- await expect(nmrium.page.locator('_react=ColorPicker')).toBeHidden();
+ await expect(nmrium.page.locator('_react=Saturation')).toBeHidden();
});
await test.step('Change H1,H1 spectrum', async () => {
await nmrium.page.click('_react=SpectraTabs >> _react=Tab[tabid="1H,1H"]');
@@ -194,15 +194,15 @@ test('2d spectrum', async ({ page }) => {
.click();
await nmrium.page.click(
- '_react=ColorPicker >> _react=SketchPresetColors >> nth=0 >> div >> nth=0',
+ '_react=SketchPresetColors >> nth=0 >> div >> nth=0',
);
// Change colors
await nmrium.page.click(
- '_react=ColorPicker >> _react=SketchPresetColors >> nth=0 >> div >> nth=0',
+ '_react=SketchPresetColors >> nth=0 >> div >> nth=0',
);
await nmrium.page.click(
- '_react=ColorPicker >> _react=SketchPresetColors >> nth=1 >> div >> nth=5',
+ '_react=SketchPresetColors >> nth=1 >> div >> nth=5',
);
// Check that ColorIndicator color changed