@twintag/twintag-form 0.3.1 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +42 -40
- package/CHANGELOG.md +20 -0
- package/dist/index.es.js +4711 -4688
- package/dist/index.umd.js +46 -46
- package/dist/lib/__stories__/Form.stories.d.ts.map +1 -1
- package/dist/lib/components/Category/index.d.ts +9 -0
- package/dist/lib/components/Category/index.d.ts.map +1 -0
- package/dist/lib/components/Form/index.d.ts +2 -2
- package/dist/lib/components/Form/index.d.ts.map +1 -1
- package/dist/lib/components/Form/register.d.ts +4 -5
- package/dist/lib/components/Form/register.d.ts.map +1 -1
- package/dist/lib/components/Input/checkbox.d.ts +2 -2
- package/dist/lib/components/Input/checkbox.d.ts.map +1 -1
- package/dist/lib/components/Input/file.d.ts +2 -2
- package/dist/lib/components/Input/file.d.ts.map +1 -1
- package/dist/lib/components/Input/index.d.ts +2 -3
- package/dist/lib/components/Input/index.d.ts.map +1 -1
- package/dist/lib/components/Input/simple.d.ts +2 -2
- package/dist/lib/components/Input/simple.d.ts.map +1 -1
- package/dist/lib/components/Input/submit.d.ts +2 -2
- package/dist/lib/components/Input/submit.d.ts.map +1 -1
- package/dist/lib/components/Input/textarea.d.ts +2 -2
- package/dist/lib/components/Input/textarea.d.ts.map +1 -1
- package/dist/lib/components/Input/toggle.d.ts +2 -2
- package/dist/lib/components/Input/toggle.d.ts.map +1 -1
- package/dist/lib/components/Label/index.d.ts +2 -2
- package/dist/lib/components/Label/index.d.ts.map +1 -1
- package/dist/lib/components/index.d.ts +2 -1
- package/dist/lib/components/index.d.ts.map +1 -1
- package/dist/lib/index.d.ts +2 -2
- package/dist/lib/index.d.ts.map +1 -1
- package/dist/lib/styles.d.ts +22 -12
- package/dist/lib/styles.d.ts.map +1 -1
- package/dist/lib/types/index.d.ts +2 -3
- package/dist/lib/types/index.d.ts.map +1 -1
- package/dist/twind.config.d.ts.map +1 -1
- package/dist/webcomponent.es.js +5134 -5119
- package/dist/webcomponent.umd.js +48 -48
- package/lib/__stories__/Form.stories.tsx +16 -5
- package/lib/components/Category/index.tsx +29 -0
- package/lib/components/Form/index.tsx +4 -3
- package/lib/components/Form/register.tsx +41 -42
- package/lib/components/Input/checkbox.tsx +6 -4
- package/lib/components/Input/file.tsx +7 -5
- package/lib/components/Input/index.tsx +4 -2
- package/lib/components/Input/simple.tsx +4 -3
- package/lib/components/Input/submit.tsx +3 -2
- package/lib/components/Input/textarea.tsx +4 -3
- package/lib/components/Input/toggle.tsx +7 -5
- package/lib/components/Label/index.tsx +2 -1
- package/lib/components/index.tsx +2 -1
- package/lib/index.tsx +28 -23
- package/lib/styles.ts +42 -20
- package/lib/types/index.ts +2 -3
- package/package.json +3 -2
- package/twind.config.ts +3 -1
|
@@ -3,6 +3,8 @@ import TwintagForm from '../index';
|
|
|
3
3
|
// Replace your-framework with the name of your framework
|
|
4
4
|
import type { Meta, StoryObj } from '@storybook/react';
|
|
5
5
|
|
|
6
|
+
import { withActions } from '@storybook/addon-actions/decorator';
|
|
7
|
+
|
|
6
8
|
const meta: Meta<typeof TwintagForm> = {
|
|
7
9
|
/* 👇 The title prop is optional.
|
|
8
10
|
* See https://storybook.js.org/docs/7.0/react/configure/overview#configure-story-loading
|
|
@@ -10,6 +12,12 @@ const meta: Meta<typeof TwintagForm> = {
|
|
|
10
12
|
*/
|
|
11
13
|
title: 'Form',
|
|
12
14
|
component: TwintagForm,
|
|
15
|
+
parameters: {
|
|
16
|
+
actions: {
|
|
17
|
+
handles: ['twintag-form-valid', 'twintag-form-invalid'],
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
decorators: [withActions as any],
|
|
13
21
|
};
|
|
14
22
|
|
|
15
23
|
export default meta;
|
|
@@ -20,14 +28,17 @@ export const Example: Story = {
|
|
|
20
28
|
args: {
|
|
21
29
|
config: [
|
|
22
30
|
{
|
|
23
|
-
type: '
|
|
24
|
-
label: '
|
|
25
|
-
|
|
26
|
-
|
|
31
|
+
type: 'category',
|
|
32
|
+
label: 'Category test',
|
|
33
|
+
items: [
|
|
34
|
+
{ type: 'input', label: 'Test', bind: 'test' },
|
|
35
|
+
{ type: 'input:toggle', label: 'Email', bind: 'email' },
|
|
36
|
+
{ type: 'input:file', label: 'File test', bind: 'fileTest' },
|
|
37
|
+
],
|
|
27
38
|
},
|
|
28
|
-
{ type: 'input', label: 'Test', bind: 'test' },
|
|
29
39
|
{ type: 'input:file', label: 'Image', bind: 'image' },
|
|
30
40
|
{ type: 'input:checkbox', label: 'Checkbox', bind: 'checkbox' },
|
|
41
|
+
{ type: 'input:checkbox', label: 'Checkbox Test', bind: 'checkTest' },
|
|
31
42
|
{ type: 'input:submit', label: 'Submit' },
|
|
32
43
|
],
|
|
33
44
|
options: {
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { FC } from 'react';
|
|
2
|
+
import type { VariantProps } from 'tailwind-variants';
|
|
3
|
+
import type { WithChildren } from 'twintag-types/dom';
|
|
4
|
+
|
|
5
|
+
import { useMemo } from 'react';
|
|
6
|
+
|
|
7
|
+
import type { CommonProps } from '@twintag-form/types';
|
|
8
|
+
|
|
9
|
+
import { categoryStyle } from '@twintag-form/styles';
|
|
10
|
+
|
|
11
|
+
type Props = CommonProps<VariantProps<typeof categoryStyle>['variant']> &
|
|
12
|
+
WithChildren;
|
|
13
|
+
|
|
14
|
+
const Category: FC<Props> = ({ label, options, children }) => {
|
|
15
|
+
const { container, span, items } = useMemo(() => {
|
|
16
|
+
if (options?.variant) return categoryStyle({ variant: options.variant });
|
|
17
|
+
return categoryStyle();
|
|
18
|
+
}, []);
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<section className={container()}>
|
|
22
|
+
{label ? <span className={span()}>{label}</span> : <></>}
|
|
23
|
+
|
|
24
|
+
<div className={items()}>{children}</div>
|
|
25
|
+
</section>
|
|
26
|
+
);
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export default Category;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { FC } from 'react';
|
|
1
2
|
import type { FieldValues } from 'react-hook-form';
|
|
2
3
|
import type { WithChildren } from 'twintag-types/dom';
|
|
3
4
|
|
|
@@ -12,7 +13,7 @@ type Props = {
|
|
|
12
13
|
};
|
|
13
14
|
} & WithChildren;
|
|
14
15
|
|
|
15
|
-
const Form = ({ children, options }
|
|
16
|
+
const Form: FC<Props> = ({ children, options }) => {
|
|
16
17
|
const formRef = useRef<HTMLFormElement>(null);
|
|
17
18
|
|
|
18
19
|
const {
|
|
@@ -71,10 +72,10 @@ const Form = ({ children, options }: Props) => {
|
|
|
71
72
|
return (
|
|
72
73
|
<form
|
|
73
74
|
ref={formRef}
|
|
74
|
-
className='font-
|
|
75
|
+
className='font-ff-text relative'
|
|
75
76
|
onSubmit={handleSubmit(onValid, onInvalid)}
|
|
76
77
|
>
|
|
77
|
-
<div className='grid w-auto
|
|
78
|
+
<div className='grid w-auto'>
|
|
78
79
|
<RegisterInputs useForm={{ register, control }}>
|
|
79
80
|
{children}
|
|
80
81
|
</RegisterInputs>
|
|
@@ -1,69 +1,68 @@
|
|
|
1
|
-
import type { ReactElement } from 'react';
|
|
1
|
+
import type { FC, ReactElement } from 'react';
|
|
2
2
|
import type { UseFormRegister, Control } from 'react-hook-form';
|
|
3
3
|
import type { WithChildren } from 'twintag-types/dom';
|
|
4
4
|
|
|
5
|
-
import { Children
|
|
5
|
+
import { Children } from 'react';
|
|
6
6
|
|
|
7
7
|
import Input from '../Input';
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
children,
|
|
11
|
-
useForm,
|
|
12
|
-
}: {
|
|
9
|
+
type Props = {
|
|
13
10
|
useForm: { register: UseFormRegister<any>; control: Control };
|
|
14
|
-
} & WithChildren
|
|
11
|
+
} & WithChildren;
|
|
12
|
+
|
|
13
|
+
const RegisterInputs: FC<Props> = ({ children, useForm }) => {
|
|
15
14
|
return Children.map(children as any, (child) => {
|
|
16
15
|
if (!child) return null;
|
|
17
16
|
|
|
17
|
+
const Component = child.type;
|
|
18
|
+
|
|
18
19
|
if (child.props?.config?.items) {
|
|
19
|
-
return
|
|
20
|
-
|
|
21
|
-
...child.props
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
20
|
+
return (
|
|
21
|
+
<Component
|
|
22
|
+
{...child.props}
|
|
23
|
+
config={{
|
|
24
|
+
...child.props.config,
|
|
25
|
+
items: child.props.config.items.map((item: any) => {
|
|
26
|
+
if (item.type === 'input') {
|
|
27
|
+
return {
|
|
28
|
+
...item,
|
|
29
|
+
useForm,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
29
32
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
33
|
+
return item;
|
|
34
|
+
}),
|
|
35
|
+
}}
|
|
36
|
+
/>
|
|
37
|
+
);
|
|
34
38
|
}
|
|
35
39
|
|
|
36
40
|
if (child.props?.children) {
|
|
37
|
-
return
|
|
38
|
-
child.
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
{child.props.children}
|
|
44
|
-
</RegisterInputs>
|
|
41
|
+
return (
|
|
42
|
+
<Component {...child.props}>
|
|
43
|
+
<RegisterInputs useForm={useForm}>
|
|
44
|
+
{child.props.children}
|
|
45
|
+
</RegisterInputs>
|
|
46
|
+
</Component>
|
|
45
47
|
);
|
|
46
48
|
}
|
|
47
49
|
|
|
48
50
|
if ((child as ReactElement).props?.config?.type === 'input') {
|
|
49
|
-
return
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
51
|
+
return (
|
|
52
|
+
<Component
|
|
53
|
+
config={{
|
|
54
|
+
...child.props.config,
|
|
55
|
+
useForm,
|
|
56
|
+
}}
|
|
57
|
+
/>
|
|
58
|
+
);
|
|
55
59
|
}
|
|
56
60
|
|
|
57
61
|
if (child.type === Input) {
|
|
58
|
-
return
|
|
59
|
-
...child.props,
|
|
60
|
-
useForm,
|
|
61
|
-
});
|
|
62
|
+
return <Component {...child.props} useForm={useForm} />;
|
|
62
63
|
}
|
|
63
64
|
|
|
64
|
-
return
|
|
65
|
-
...child.props,
|
|
66
|
-
});
|
|
65
|
+
return <Component {...child.props} />;
|
|
67
66
|
});
|
|
68
67
|
};
|
|
69
68
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { FC } from 'react';
|
|
1
2
|
import type { VariantProps } from 'tailwind-variants';
|
|
2
3
|
|
|
3
4
|
import { useMemo } from 'react';
|
|
@@ -12,16 +13,16 @@ import { checkboxStyle } from '@twintag-form/styles';
|
|
|
12
13
|
|
|
13
14
|
type Props = CommonProps<VariantProps<typeof checkboxStyle>['variant']>;
|
|
14
15
|
|
|
15
|
-
const Checkbox = ({ useForm, label, bind, options }
|
|
16
|
+
const Checkbox: FC<Props> = ({ useForm, label, bind, options }) => {
|
|
16
17
|
const { container, checkbox } = useMemo(() => {
|
|
17
18
|
if (options?.variant) return checkboxStyle({ variant: options.variant });
|
|
18
19
|
return checkboxStyle();
|
|
19
20
|
}, []);
|
|
20
21
|
|
|
21
22
|
const {
|
|
22
|
-
field: {
|
|
23
|
+
field: { ref, value, onChange },
|
|
23
24
|
} = useController({
|
|
24
|
-
name: bind
|
|
25
|
+
name: bind,
|
|
25
26
|
control: useForm ? useForm.control : undefined,
|
|
26
27
|
defaultValue: false,
|
|
27
28
|
rules: {
|
|
@@ -32,6 +33,7 @@ const Checkbox = ({ useForm, label, bind, options }: Props) => {
|
|
|
32
33
|
return (
|
|
33
34
|
<label className={container()}>
|
|
34
35
|
<RdxCheckbox.Root
|
|
36
|
+
ref={ref}
|
|
35
37
|
className={checkbox()}
|
|
36
38
|
defaultChecked={value}
|
|
37
39
|
onCheckedChange={(state) => {
|
|
@@ -44,7 +46,7 @@ const Checkbox = ({ useForm, label, bind, options }: Props) => {
|
|
|
44
46
|
</RdxCheckbox.Root>
|
|
45
47
|
|
|
46
48
|
<Label className='text-label' required={!options?.optionalField}>
|
|
47
|
-
{label
|
|
49
|
+
{label}
|
|
48
50
|
</Label>
|
|
49
51
|
</label>
|
|
50
52
|
);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { FC } from 'react';
|
|
1
2
|
import type { VariantProps } from 'tailwind-variants';
|
|
2
3
|
|
|
3
4
|
import { useMemo } from 'react';
|
|
@@ -11,16 +12,16 @@ import { fileStyle } from '@twintag-form/styles';
|
|
|
11
12
|
|
|
12
13
|
type Props = CommonProps<VariantProps<typeof fileStyle>['variant']>;
|
|
13
14
|
|
|
14
|
-
const File = ({ useForm, label, bind, options }
|
|
15
|
+
const File: FC<Props> = ({ useForm, label, bind, options }) => {
|
|
15
16
|
const { container, span, input } = useMemo(() => {
|
|
16
17
|
if (options?.variant) return fileStyle({ variant: options?.variant });
|
|
17
18
|
return fileStyle();
|
|
18
19
|
}, []);
|
|
19
20
|
|
|
20
21
|
const {
|
|
21
|
-
field: {
|
|
22
|
+
field: { ref, value, onChange },
|
|
22
23
|
} = useController({
|
|
23
|
-
name: bind
|
|
24
|
+
name: bind,
|
|
24
25
|
control: useForm ? useForm.control : undefined,
|
|
25
26
|
defaultValue: null,
|
|
26
27
|
rules: {
|
|
@@ -32,13 +33,14 @@ const File = ({ useForm, label, bind, options }: Props) => {
|
|
|
32
33
|
<label className={container()}>
|
|
33
34
|
{label ? (
|
|
34
35
|
<Label className={span()} required={!options?.optionalField}>
|
|
35
|
-
{label
|
|
36
|
+
{label}
|
|
36
37
|
</Label>
|
|
37
38
|
) : (
|
|
38
39
|
<></>
|
|
39
40
|
)}
|
|
40
41
|
|
|
41
42
|
<input
|
|
43
|
+
ref={ref}
|
|
42
44
|
type='file'
|
|
43
45
|
multiple
|
|
44
46
|
capture='environment'
|
|
@@ -54,7 +56,7 @@ const File = ({ useForm, label, bind, options }: Props) => {
|
|
|
54
56
|
className={`${input()} ${
|
|
55
57
|
value && value.length > 0
|
|
56
58
|
? 'border-primary text-input'
|
|
57
|
-
: 'border-slate-700/10 text-
|
|
59
|
+
: 'border-slate-700/10 text-placeholder'
|
|
58
60
|
}`}
|
|
59
61
|
>
|
|
60
62
|
<span className='grid'>
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { FC } from 'react';
|
|
2
|
+
|
|
1
3
|
import Simple from './simple';
|
|
2
4
|
import Textarea from './textarea';
|
|
3
5
|
import Toggle from './toggle';
|
|
@@ -5,7 +7,7 @@ import File from './file';
|
|
|
5
7
|
import Submit from './submit';
|
|
6
8
|
import Checkbox from './checkbox';
|
|
7
9
|
|
|
8
|
-
|
|
10
|
+
const Inputs = new Map()
|
|
9
11
|
.set('simple', Simple)
|
|
10
12
|
.set('textarea', Textarea)
|
|
11
13
|
.set('toggle', Toggle)
|
|
@@ -19,7 +21,7 @@ type Props = {
|
|
|
19
21
|
bind?: string;
|
|
20
22
|
};
|
|
21
23
|
|
|
22
|
-
const Input = ({ subtype = 'simple', ...rest }
|
|
24
|
+
const Input: FC<Props> = ({ subtype = 'simple', ...rest }) => {
|
|
23
25
|
const InputComponent = Inputs.get(subtype);
|
|
24
26
|
|
|
25
27
|
if (!InputComponent) return <></>;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { FC } from 'react';
|
|
1
2
|
import type { VariantProps } from 'tailwind-variants';
|
|
2
3
|
|
|
3
4
|
import { useMemo } from 'react';
|
|
@@ -9,7 +10,7 @@ import { simpleStyle } from '@twintag-form/styles';
|
|
|
9
10
|
|
|
10
11
|
type Props = CommonProps<VariantProps<typeof simpleStyle>['variant']>;
|
|
11
12
|
|
|
12
|
-
const Simple = ({ useForm, label, bind, options }
|
|
13
|
+
const Simple: FC<Props> = ({ useForm, label, bind, options }) => {
|
|
13
14
|
const { container, span, input } = useMemo(() => {
|
|
14
15
|
if (options?.variant) return simpleStyle({ variant: options.variant });
|
|
15
16
|
return simpleStyle();
|
|
@@ -19,7 +20,7 @@ const Simple = ({ useForm, label, bind, options }: Props) => {
|
|
|
19
20
|
<label className={container()}>
|
|
20
21
|
{label ? (
|
|
21
22
|
<Label className={span()} required={!options?.optionalField}>
|
|
22
|
-
{label
|
|
23
|
+
{label}
|
|
23
24
|
</Label>
|
|
24
25
|
) : (
|
|
25
26
|
<></>
|
|
@@ -29,7 +30,7 @@ const Simple = ({ useForm, label, bind, options }: Props) => {
|
|
|
29
30
|
type='text'
|
|
30
31
|
placeholder={options?.placeholder || 'Write here...'}
|
|
31
32
|
className={input()}
|
|
32
|
-
{...useForm!.register(bind
|
|
33
|
+
{...useForm!.register(bind, {
|
|
33
34
|
required: options?.optionalField ? false : `${label} is required`,
|
|
34
35
|
})}
|
|
35
36
|
/>
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { FC } from 'react';
|
|
1
2
|
import type { VariantProps } from 'tailwind-variants';
|
|
2
3
|
|
|
3
4
|
import { useMemo } from 'react';
|
|
@@ -8,7 +9,7 @@ import { submitStyle } from '@twintag-form/styles';
|
|
|
8
9
|
|
|
9
10
|
type Props = CommonProps<VariantProps<typeof submitStyle>['variant']>;
|
|
10
11
|
|
|
11
|
-
const Submit = ({ label, options }
|
|
12
|
+
const Submit: FC<Props> = ({ label, options }) => {
|
|
12
13
|
const style = useMemo(() => {
|
|
13
14
|
if (options?.variant) return submitStyle({ variant: options.variant });
|
|
14
15
|
return submitStyle();
|
|
@@ -17,7 +18,7 @@ const Submit = ({ label, options }: Props) => {
|
|
|
17
18
|
return (
|
|
18
19
|
<div className='flex w-full justify-center'>
|
|
19
20
|
<button type='submit' className={style}>
|
|
20
|
-
{label
|
|
21
|
+
{label}
|
|
21
22
|
</button>
|
|
22
23
|
</div>
|
|
23
24
|
);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { FC } from 'react';
|
|
1
2
|
import type { VariantProps } from 'tailwind-variants';
|
|
2
3
|
|
|
3
4
|
import { useMemo } from 'react';
|
|
@@ -9,7 +10,7 @@ import { simpleStyle } from '@twintag-form/styles';
|
|
|
9
10
|
|
|
10
11
|
type Props = CommonProps<VariantProps<typeof simpleStyle>['variant']>;
|
|
11
12
|
|
|
12
|
-
const Textarea = ({ useForm, label, bind, options }
|
|
13
|
+
const Textarea: FC<Props> = ({ useForm, label, bind, options }) => {
|
|
13
14
|
const { container, span, input } = useMemo(() => {
|
|
14
15
|
if (options?.variant) return simpleStyle({ variant: options.variant });
|
|
15
16
|
return simpleStyle();
|
|
@@ -19,7 +20,7 @@ const Textarea = ({ useForm, label, bind, options }: Props) => {
|
|
|
19
20
|
<label className={container()}>
|
|
20
21
|
{label ? (
|
|
21
22
|
<Label className={span()} required={!options?.optionalField}>
|
|
22
|
-
{label
|
|
23
|
+
{label}
|
|
23
24
|
</Label>
|
|
24
25
|
) : (
|
|
25
26
|
<></>
|
|
@@ -28,7 +29,7 @@ const Textarea = ({ useForm, label, bind, options }: Props) => {
|
|
|
28
29
|
<textarea
|
|
29
30
|
className={input()}
|
|
30
31
|
placeholder={options?.placeholder || 'Write here...'}
|
|
31
|
-
{...useForm!.register(bind
|
|
32
|
+
{...useForm!.register(bind, {
|
|
32
33
|
required: options?.optionalField ? false : `${label} is required`,
|
|
33
34
|
})}
|
|
34
35
|
/>
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { FC } from 'react';
|
|
1
2
|
import type { VariantProps } from 'tailwind-variants';
|
|
2
3
|
|
|
3
4
|
import { useMemo } from 'react';
|
|
@@ -11,16 +12,16 @@ import { toggleStyle } from '@twintag-form/styles';
|
|
|
11
12
|
|
|
12
13
|
type Props = CommonProps<VariantProps<typeof toggleStyle>['variant']>;
|
|
13
14
|
|
|
14
|
-
const Toggle = ({ useForm, label, bind, options }
|
|
15
|
+
const Toggle: FC<Props> = ({ useForm, label, bind, options }) => {
|
|
15
16
|
const { container, span, input, thumb } = useMemo(() => {
|
|
16
17
|
if (options?.variant) return toggleStyle({ variant: options.variant });
|
|
17
18
|
return toggleStyle();
|
|
18
19
|
}, []);
|
|
19
20
|
|
|
20
21
|
const {
|
|
21
|
-
field: {
|
|
22
|
+
field: { ref, value, onChange },
|
|
22
23
|
} = useController({
|
|
23
|
-
name: bind
|
|
24
|
+
name: bind,
|
|
24
25
|
control: useForm ? useForm.control : undefined,
|
|
25
26
|
defaultValue: false,
|
|
26
27
|
rules: {
|
|
@@ -32,14 +33,15 @@ const Toggle = ({ useForm, label, bind, options }: Props) => {
|
|
|
32
33
|
<label className={container()}>
|
|
33
34
|
{label ? (
|
|
34
35
|
<Label className={span()} required={!options?.optionalField}>
|
|
35
|
-
{label
|
|
36
|
+
{label}
|
|
36
37
|
</Label>
|
|
37
38
|
) : (
|
|
38
39
|
<></>
|
|
39
40
|
)}
|
|
40
41
|
|
|
41
42
|
<Switch.Root
|
|
42
|
-
id={bind
|
|
43
|
+
id={bind}
|
|
44
|
+
ref={ref}
|
|
43
45
|
checked={value}
|
|
44
46
|
className={input()}
|
|
45
47
|
onCheckedChange={(state) => {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { FC } from 'react';
|
|
1
2
|
import type { WithChildren } from 'twintag-types/dom';
|
|
2
3
|
|
|
3
4
|
import { labelStyle } from '@twintag-form/styles';
|
|
@@ -7,7 +8,7 @@ type Props = {
|
|
|
7
8
|
className?: string;
|
|
8
9
|
} & WithChildren;
|
|
9
10
|
|
|
10
|
-
const Label = ({ className, required, children }
|
|
11
|
+
const Label: FC<Props> = ({ className, required, children }) => {
|
|
11
12
|
const style = labelStyle({
|
|
12
13
|
className,
|
|
13
14
|
});
|
package/lib/components/index.tsx
CHANGED
package/lib/index.tsx
CHANGED
|
@@ -2,8 +2,9 @@ import type { FC, ReactNode } from 'react';
|
|
|
2
2
|
|
|
3
3
|
import { LabelToString } from 'twintag-types/dom';
|
|
4
4
|
|
|
5
|
-
import Input from '@twintag-form/components/Input';
|
|
6
5
|
import Form from '@twintag-form/components/Form';
|
|
6
|
+
import Input from '@twintag-form/components/Input';
|
|
7
|
+
import Category from '@twintag-form/components/Category';
|
|
7
8
|
|
|
8
9
|
type Config = {
|
|
9
10
|
key?: number;
|
|
@@ -25,9 +26,9 @@ type Component = {
|
|
|
25
26
|
|
|
26
27
|
type Format = {
|
|
27
28
|
$config: Config;
|
|
28
|
-
$blocks?: Map<string,
|
|
29
|
-
$containers?: Map<string,
|
|
30
|
-
$available?: Map<string,
|
|
29
|
+
$blocks?: Map<string, FC<Component>>;
|
|
30
|
+
$containers?: Map<string, FC<Component>>;
|
|
31
|
+
$available?: Map<string, FC<Component>>;
|
|
31
32
|
};
|
|
32
33
|
|
|
33
34
|
const format = ({ $config, $blocks, $containers, $available }: Format) => {
|
|
@@ -77,8 +78,8 @@ const format = ({ $config, $blocks, $containers, $available }: Format) => {
|
|
|
77
78
|
|
|
78
79
|
type Params = {
|
|
79
80
|
$config: Config;
|
|
80
|
-
$blocks?: Map<string,
|
|
81
|
-
$containers?: Map<string,
|
|
81
|
+
$blocks?: Map<string, FC<Component>>;
|
|
82
|
+
$containers?: Map<string, FC<Component>>;
|
|
82
83
|
};
|
|
83
84
|
|
|
84
85
|
const useConfig = (params: Params) => {
|
|
@@ -94,7 +95,7 @@ const useConfig = (params: Params) => {
|
|
|
94
95
|
};
|
|
95
96
|
|
|
96
97
|
const blocks = new Map().set('input', Input);
|
|
97
|
-
const containers = new Map().set('form', Form);
|
|
98
|
+
const containers = new Map().set('form', Form).set('category', Category);
|
|
98
99
|
|
|
99
100
|
type RendererProps = {
|
|
100
101
|
config: Config & {
|
|
@@ -103,30 +104,34 @@ type RendererProps = {
|
|
|
103
104
|
};
|
|
104
105
|
};
|
|
105
106
|
|
|
106
|
-
const FormRenderer = ({ config }
|
|
107
|
+
const FormRenderer: FC<RendererProps> = ({ config }) => {
|
|
107
108
|
const { key, type, subtype, label, bind, items, block, container, ...rest } =
|
|
108
109
|
config;
|
|
109
110
|
|
|
110
111
|
if (!type) return null;
|
|
111
112
|
|
|
112
|
-
if (container
|
|
113
|
+
if (container) {
|
|
113
114
|
const Component = container;
|
|
114
115
|
|
|
115
116
|
return (
|
|
116
117
|
<Component key={key} subtype={subtype} label={label} {...rest}>
|
|
117
|
-
{items.
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
118
|
+
{items && Array.isArray(items) ? (
|
|
119
|
+
items.map((item, idx) => (
|
|
120
|
+
<FormRenderer
|
|
121
|
+
key={idx}
|
|
122
|
+
config={{
|
|
123
|
+
...rest,
|
|
124
|
+
...item,
|
|
125
|
+
options: {
|
|
126
|
+
...item.options,
|
|
127
|
+
variant: rest.options?.variant,
|
|
128
|
+
},
|
|
129
|
+
}}
|
|
130
|
+
/>
|
|
131
|
+
))
|
|
132
|
+
) : (
|
|
133
|
+
<></>
|
|
134
|
+
)}
|
|
130
135
|
</Component>
|
|
131
136
|
);
|
|
132
137
|
}
|
|
@@ -156,7 +161,7 @@ type Props = {
|
|
|
156
161
|
};
|
|
157
162
|
};
|
|
158
163
|
|
|
159
|
-
const TwintagForm = ({ config, options }
|
|
164
|
+
const TwintagForm: FC<Props> = ({ config, options }) => {
|
|
160
165
|
const __config = useConfig({
|
|
161
166
|
$blocks: blocks,
|
|
162
167
|
$containers: containers,
|
package/lib/styles.ts
CHANGED
|
@@ -1,12 +1,29 @@
|
|
|
1
1
|
import { tv } from 'tailwind-variants';
|
|
2
2
|
|
|
3
3
|
export const labelStyle = tv({
|
|
4
|
-
base: '
|
|
4
|
+
base: 'text-label',
|
|
5
|
+
});
|
|
6
|
+
|
|
7
|
+
export const containerStyle = tv({
|
|
8
|
+
base: 'my-2',
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
export const categoryStyle = tv({
|
|
12
|
+
slots: {
|
|
13
|
+
container: 'w-full grid mt-4 first:mt-0',
|
|
14
|
+
span: 'text-category-label',
|
|
15
|
+
items: 'grid mt-2 mb-4 empty:mb-0',
|
|
16
|
+
},
|
|
17
|
+
variants: {
|
|
18
|
+
variant: {},
|
|
19
|
+
},
|
|
5
20
|
});
|
|
6
21
|
|
|
7
22
|
export const checkboxStyle = tv({
|
|
8
23
|
slots: {
|
|
9
|
-
container:
|
|
24
|
+
container: containerStyle({
|
|
25
|
+
className: 'flex gap-4 items-center w-full',
|
|
26
|
+
}),
|
|
10
27
|
checkbox:
|
|
11
28
|
'flex appearance-none items-center justify-center bg-white outline-none ring-0 border-2 border-primary focus:ring-0 focus:border-accent',
|
|
12
29
|
},
|
|
@@ -27,7 +44,9 @@ export const checkboxStyle = tv({
|
|
|
27
44
|
|
|
28
45
|
export const fileStyle = tv({
|
|
29
46
|
slots: {
|
|
30
|
-
container:
|
|
47
|
+
container: containerStyle({
|
|
48
|
+
className: 'w-full block',
|
|
49
|
+
}),
|
|
31
50
|
span: '',
|
|
32
51
|
input:
|
|
33
52
|
'w-full cursor-pointer ring-0 focus:ring-0 border-2 border-transparent',
|
|
@@ -53,10 +72,11 @@ export const fileStyle = tv({
|
|
|
53
72
|
|
|
54
73
|
export const simpleStyle = tv({
|
|
55
74
|
slots: {
|
|
56
|
-
container:
|
|
75
|
+
container: containerStyle({
|
|
76
|
+
className: 'w-full',
|
|
77
|
+
}),
|
|
57
78
|
span: '',
|
|
58
|
-
input:
|
|
59
|
-
'w-full ring-0 placeholder:text-slate-400 focus:ring-0 border-2 border-transparent text-input',
|
|
79
|
+
input: 'w-full ring-0 placeholder:text-placeholder focus:ring-0 border-2 border-transparent text-input',
|
|
60
80
|
},
|
|
61
81
|
variants: {
|
|
62
82
|
variant: {
|
|
@@ -76,22 +96,11 @@ export const simpleStyle = tv({
|
|
|
76
96
|
},
|
|
77
97
|
});
|
|
78
98
|
|
|
79
|
-
export const submitStyle = tv({
|
|
80
|
-
base: 'w-max max-w-full',
|
|
81
|
-
variants: {
|
|
82
|
-
variant: {
|
|
83
|
-
alpha: 'bg-primary text-white px-4 py-2 rounded-md',
|
|
84
|
-
beta: 'bg-primary text-white px-4 py-2',
|
|
85
|
-
},
|
|
86
|
-
},
|
|
87
|
-
defaultVariants: {
|
|
88
|
-
variant: 'alpha',
|
|
89
|
-
},
|
|
90
|
-
});
|
|
91
|
-
|
|
92
99
|
export const toggleStyle = tv({
|
|
93
100
|
slots: {
|
|
94
|
-
container:
|
|
101
|
+
container: containerStyle({
|
|
102
|
+
className: 'w-full cursor-pointer',
|
|
103
|
+
}),
|
|
95
104
|
span: '',
|
|
96
105
|
input: 'relative outline-none ring-2 ring-transparent',
|
|
97
106
|
thumb: 'block transition-transform duration-100 will-change-transform',
|
|
@@ -118,3 +127,16 @@ export const toggleStyle = tv({
|
|
|
118
127
|
variant: 'alpha',
|
|
119
128
|
},
|
|
120
129
|
});
|
|
130
|
+
|
|
131
|
+
export const submitStyle = tv({
|
|
132
|
+
base: 'w-max max-w-full mt-2',
|
|
133
|
+
variants: {
|
|
134
|
+
variant: {
|
|
135
|
+
alpha: 'bg-primary text-white px-4 py-2 rounded-md',
|
|
136
|
+
beta: 'bg-primary text-white px-4 py-2',
|
|
137
|
+
},
|
|
138
|
+
},
|
|
139
|
+
defaultVariants: {
|
|
140
|
+
variant: 'alpha',
|
|
141
|
+
},
|
|
142
|
+
});
|