refactor(former): 🔄 restructure form components and stores

* Remove unused FormLayout and SuperForm stores.
* Consolidate form logic into Former component.
* Implement new Former layout and types.
* Update stories for new Former component.
* Clean up unused styles and types across the project.
This commit is contained in:
2026-01-12 23:19:25 +02:00
parent b2817f4233
commit 095ddf6162
41 changed files with 710 additions and 2027 deletions

View File

@@ -0,0 +1,42 @@
//@ts-nocheck
import type { Meta, StoryObj } from '@storybook/react-vite';
import { Box } from '@mantine/core';
import { fn } from 'storybook/test';
import { FormTest } from './example';
const Renderable = (props: any) => {
return (
<Box h="100%" mih="400px" miw="400px" w="100%">
<FormTest {...props} />
</Box>
);
};
const meta = {
// Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#action-args
args: { onClick: fn() },
// More on argTypes: https://storybook.js.org/docs/api/argtypes
argTypes: {
backgroundColor: { control: 'color' },
},
component: Renderable,
parameters: {
// Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout
//layout: 'centered',
},
// This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs
tags: ['autodocs'],
title: 'Former/Former Basic',
} satisfies Meta<typeof Renderable>;
export default meta;
type Story = StoryObj<typeof meta>;
// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args
export const BasicExample: Story = {
args: {
label: 'Test',
},
};

View File

@@ -0,0 +1,118 @@
import { Button, Drawer, Group, Paper, Select, Stack, Switch } from '@mantine/core';
import { useRef, useState } from 'react';
import { Controller } from 'react-hook-form';
import type { FormerRef } from '../Former.types';
import { Former } from '../Former';
export const FormTest = () => {
const [request, setRequest] = useState<null | string>('insert');
const [wrapped, setWrapped] = useState(false);
const [open, setOpen] = useState(false);
const [formData, setFormData] = useState({ a: 99 });
console.log('formData', formData);
const ref = useRef<FormerRef>(null);
return (
<Stack h="100%" mih="400px" w="90%">
<Select
data={['insert', 'update', 'delete', 'select', 'view']}
onChange={setRequest}
value={request}
/>
<Switch
checked={wrapped}
label="Wrapped in Drawer"
onChange={(event) => setWrapped(event.currentTarget.checked)}
/>
<Button onClick={() => setOpen(true)}>Open Former Drawer</Button>
<Group>
<Button
onClick={async () => {
const valid = await ref.current?.validate();
console.log('validate -> ', valid, ref.current);
}}
>
Test Ref Values. See console
</Button>
<Button
onClick={async () => {
setTimeout(() => {
ref.current?.close?.();
}, 3000);
}}
>
Test Show/Hide
</Button>
</Group>
<Former
//wrapper={(children, getState) => <div>{children}</div>}
//opened={true}
apiKeyField="a"
onAPICall={(mode, request, value) => {
console.log('API Call', mode, request, value);
if (mode === 'read') {
return new Promise((resolve) => {
setTimeout(() => {
resolve({ a: 'Another Value', test: 'Loaded Value' });
}, 1000);
});
}
return new Promise((resolve) => {
setTimeout(() => {
resolve(value || {});
}, 1000);
});
}}
onChange={setFormData}
onClose={() => setOpen(false)}
opened={open}
primeData={{ a: '66', test: 'primed' }}
ref={ref}
request={request as any}
useFormProps={{ criteriaMode: 'all', shouldUseNativeValidation: false }}
values={formData}
wrapper={
wrapped
? (children, opened, onClose, onOpen, getState) => {
const values = getState('values');
return (
<Drawer
h={'100%'}
onClose={() => onClose?.()}
opened={opened ?? false}
title={`Drawer Former - Current A Value: ${values?.a}`}
w={'50%'}
>
<Paper h="100%" shadow="sm" w="100%" withBorder>
{children}
<Button>Test Save</Button>
</Paper>
</Drawer>
);
}
: undefined
}
>
<Stack h="1200px">
<Stack>
<Controller
name="test"
render={({ field }) => <input type="text" {...field} placeholder="A" />}
/>
<Controller
name="a"
render={({ field }) => <input type="text" {...field} placeholder="B" />}
rules={{ required: 'Field is required' }}
/>
</Stack>
<Stack>
<button type="submit">Submit</button>
<button type="reset">Reset</button>
</Stack>
</Stack>
</Former>
</Stack>
);
};