@twintag/twintag-form 0.2.0 → 0.3.0

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.
Files changed (49) hide show
  1. package/.turbo/turbo-build.log +35 -27
  2. package/CHANGELOG.md +6 -0
  3. package/README.md +90 -87
  4. package/dist/index.es.js +6786 -6803
  5. package/dist/index.umd.js +43 -43
  6. package/dist/lib/__stories__/Form.stories.d.ts +7 -0
  7. package/dist/lib/__stories__/Form.stories.d.ts.map +1 -0
  8. package/dist/lib/components/Input/checkbox.d.ts +2 -2
  9. package/dist/lib/components/Input/checkbox.d.ts.map +1 -1
  10. package/dist/lib/components/Input/file.d.ts +2 -2
  11. package/dist/lib/components/Input/file.d.ts.map +1 -1
  12. package/dist/lib/components/Input/index.d.ts +2 -0
  13. package/dist/lib/components/Input/index.d.ts.map +1 -1
  14. package/dist/lib/components/Input/simple.d.ts +2 -2
  15. package/dist/lib/components/Input/simple.d.ts.map +1 -1
  16. package/dist/lib/components/Input/submit.d.ts +2 -2
  17. package/dist/lib/components/Input/submit.d.ts.map +1 -1
  18. package/dist/lib/components/Input/textarea.d.ts +2 -2
  19. package/dist/lib/components/Input/textarea.d.ts.map +1 -1
  20. package/dist/lib/components/Input/toggle.d.ts +2 -2
  21. package/dist/lib/components/Input/toggle.d.ts.map +1 -1
  22. package/dist/lib/components/Label/index.d.ts +9 -0
  23. package/dist/lib/components/Label/index.d.ts.map +1 -0
  24. package/dist/lib/components/index.d.ts +5 -0
  25. package/dist/lib/components/index.d.ts.map +1 -0
  26. package/dist/lib/index.d.ts +6 -4
  27. package/dist/lib/index.d.ts.map +1 -1
  28. package/dist/lib/styles.d.ts +1 -0
  29. package/dist/lib/styles.d.ts.map +1 -1
  30. package/dist/twind.config.d.ts.map +1 -1
  31. package/dist/webcomponent.es.js +6779 -6793
  32. package/dist/webcomponent.umd.js +43 -43
  33. package/lib/__stories__/Form.stories.tsx +38 -0
  34. package/lib/components/Form/index.tsx +1 -1
  35. package/lib/components/Input/checkbox.tsx +7 -4
  36. package/lib/components/Input/file.tsx +12 -5
  37. package/lib/components/Input/index.tsx +2 -2
  38. package/lib/components/Input/simple.tsx +10 -11
  39. package/lib/components/Input/submit.tsx +7 -5
  40. package/lib/components/Input/textarea.tsx +14 -11
  41. package/lib/components/Input/toggle.tsx +23 -18
  42. package/lib/components/Label/index.tsx +22 -0
  43. package/lib/components/index.tsx +5 -0
  44. package/lib/index.tsx +3 -3
  45. package/lib/styles.ts +12 -8
  46. package/package.json +2 -4
  47. package/scripts/build.js +5 -0
  48. package/tsconfig.json +1 -1
  49. package/twind.config.ts +5 -0
@@ -0,0 +1,38 @@
1
+ import TwintagForm from '../index';
2
+
3
+ // Replace your-framework with the name of your framework
4
+ import type { Meta, StoryObj } from '@storybook/react';
5
+
6
+ const meta: Meta<typeof TwintagForm> = {
7
+ /* 👇 The title prop is optional.
8
+ * See https://storybook.js.org/docs/7.0/react/configure/overview#configure-story-loading
9
+ * to learn how to generate automatic titles
10
+ */
11
+ title: 'Form',
12
+ component: TwintagForm,
13
+ };
14
+
15
+ export default meta;
16
+
17
+ type Story = StoryObj<typeof TwintagForm>;
18
+
19
+ export const Example: Story = {
20
+ args: {
21
+ config: [
22
+ {
23
+ type: 'input:toggle',
24
+ label: 'Email',
25
+ bind: 'email',
26
+ options: { optionalField: true },
27
+ },
28
+ { type: 'input', label: 'Test', bind: 'test' },
29
+ { type: 'input:file', label: 'Image', bind: 'image' },
30
+ { type: 'input:checkbox', label: 'Checkbox', bind: 'checkbox' },
31
+ { type: 'input:submit', label: 'Submit' },
32
+ ],
33
+ options: {
34
+ variant: 'beta',
35
+ resetOnSubmit: true,
36
+ },
37
+ },
38
+ };
@@ -71,7 +71,7 @@ const Form = ({ children, options }: Props) => {
71
71
  return (
72
72
  <form
73
73
  ref={formRef}
74
- className='relative font-sans'
74
+ className='relative font-fftext'
75
75
  onSubmit={handleSubmit(onValid, onInvalid)}
76
76
  >
77
77
  <div className='grid w-auto gap-4'>
@@ -5,9 +5,10 @@ import { useController } from 'react-hook-form';
5
5
  import { CheckIcon } from '@heroicons/react/24/outline';
6
6
  import * as RdxCheckbox from '@radix-ui/react-checkbox';
7
7
 
8
- import type { CommonProps } from '@/types';
8
+ import type { CommonProps } from '@twintag-form/types';
9
9
 
10
- import { checkboxStyle } from '@/styles';
10
+ import { Label } from '@twintag-form/components';
11
+ import { checkboxStyle } from '@twintag-form/styles';
11
12
 
12
13
  type Props = CommonProps<VariantProps<typeof checkboxStyle>['variant']>;
13
14
 
@@ -37,12 +38,14 @@ const Checkbox = ({ useForm, label, bind, options }: Props) => {
37
38
  onChange(state);
38
39
  }}
39
40
  >
40
- <RdxCheckbox.Indicator className='text-black'>
41
+ <RdxCheckbox.Indicator className='text-input'>
41
42
  <CheckIcon className='w-4' />
42
43
  </RdxCheckbox.Indicator>
43
44
  </RdxCheckbox.Root>
44
45
 
45
- <span className='leading-none text-black'>{label as string}</span>
46
+ <Label className='text-label' required={!options?.optionalField}>
47
+ {label as string}
48
+ </Label>
46
49
  </label>
47
50
  );
48
51
  };
@@ -4,9 +4,10 @@ import { useMemo } from 'react';
4
4
  import { useController } from 'react-hook-form';
5
5
  import { CloudArrowUpIcon } from '@heroicons/react/24/outline';
6
6
 
7
- import type { CommonProps } from '@/types';
7
+ import type { CommonProps } from '@twintag-form/types';
8
8
 
9
- import { fileStyle } from '@/styles';
9
+ import { Label } from '@twintag-form/components';
10
+ import { fileStyle } from '@twintag-form/styles';
10
11
 
11
12
  type Props = CommonProps<VariantProps<typeof fileStyle>['variant']>;
12
13
 
@@ -29,7 +30,13 @@ const File = ({ useForm, label, bind, options }: Props) => {
29
30
 
30
31
  return (
31
32
  <label className={container()}>
32
- {label ? <span className={span()}>{label as string}</span> : <></>}
33
+ {label ? (
34
+ <Label className={span()} required={!options?.optionalField}>
35
+ {label as string}
36
+ </Label>
37
+ ) : (
38
+ <></>
39
+ )}
33
40
 
34
41
  <input
35
42
  type='file'
@@ -40,13 +47,13 @@ const File = ({ useForm, label, bind, options }: Props) => {
40
47
  onChange(e.target.files);
41
48
  }
42
49
  }}
43
- className='sr-only peer'
50
+ className='peer sr-only'
44
51
  />
45
52
 
46
53
  <span
47
54
  className={`${input()} ${
48
55
  value && value.length > 0
49
- ? 'border-primary text-primary'
56
+ ? 'border-primary text-input'
50
57
  : 'border-slate-700/10 text-slate-400'
51
58
  }`}
52
59
  >
@@ -1,5 +1,3 @@
1
- import type { CommonProps } from '@/types';
2
-
3
1
  import Simple from './simple';
4
2
  import Textarea from './textarea';
5
3
  import Toggle from './toggle';
@@ -17,6 +15,8 @@ export const Inputs = new Map()
17
15
 
18
16
  type Props = {
19
17
  subtype?: string;
18
+ label?: string;
19
+ bind?: string;
20
20
  };
21
21
 
22
22
  const Input = ({ subtype = 'simple', ...rest }: Props) => {
@@ -1,32 +1,31 @@
1
1
  import type { VariantProps } from 'tailwind-variants';
2
2
 
3
- import { useId, useMemo } from 'react';
3
+ import { useMemo } from 'react';
4
4
 
5
- import type { CommonProps } from '@/types';
5
+ import type { CommonProps } from '@twintag-form/types';
6
6
 
7
- import { simpleStyle } from '@/styles';
7
+ import { Label } from '@twintag-form/components';
8
+ import { simpleStyle } from '@twintag-form/styles';
8
9
 
9
10
  type Props = CommonProps<VariantProps<typeof simpleStyle>['variant']>;
10
11
 
11
12
  const Simple = ({ useForm, label, bind, options }: Props) => {
12
- const id = useId();
13
-
14
13
  const { container, span, input } = useMemo(() => {
15
14
  if (options?.variant) return simpleStyle({ variant: options.variant });
16
15
  return simpleStyle();
17
16
  }, []);
18
17
 
19
18
  return (
20
- <div className={container()}>
19
+ <label className={container()}>
21
20
  {label ? (
22
- <label htmlFor={id}>
23
- <span className={span()}>{label as string}</span>
24
- </label>
21
+ <Label className={span()} required={!options?.optionalField}>
22
+ {label as string}
23
+ </Label>
25
24
  ) : (
26
25
  <></>
27
26
  )}
27
+
28
28
  <input
29
- id={id}
30
29
  type='text'
31
30
  placeholder={options?.placeholder || 'Write here...'}
32
31
  className={input()}
@@ -34,7 +33,7 @@ const Simple = ({ useForm, label, bind, options }: Props) => {
34
33
  required: options?.optionalField ? false : `${label} is required`,
35
34
  })}
36
35
  />
37
- </div>
36
+ </label>
38
37
  );
39
38
  };
40
39
 
@@ -2,9 +2,9 @@ import type { VariantProps } from 'tailwind-variants';
2
2
 
3
3
  import { useMemo } from 'react';
4
4
 
5
- import type { CommonProps } from '@/types';
5
+ import type { CommonProps } from '@twintag-form/types';
6
6
 
7
- import { submitStyle } from '@/styles';
7
+ import { submitStyle } from '@twintag-form/styles';
8
8
 
9
9
  type Props = CommonProps<VariantProps<typeof submitStyle>['variant']>;
10
10
 
@@ -15,9 +15,11 @@ const Submit = ({ label, options }: Props) => {
15
15
  }, []);
16
16
 
17
17
  return (
18
- <button type='submit' className={style}>
19
- {label as string}
20
- </button>
18
+ <div className='w-full flex justify-center'>
19
+ <button type='submit' className={style}>
20
+ {label as string}
21
+ </button>
22
+ </div>
21
23
  );
22
24
  };
23
25
 
@@ -1,35 +1,38 @@
1
1
  import type { VariantProps } from 'tailwind-variants';
2
2
 
3
- import { useId, useMemo } from 'react';
3
+ import { useMemo } from 'react';
4
4
 
5
- import type { CommonProps } from '@/types';
5
+ import type { CommonProps } from '@twintag-form/types';
6
6
 
7
- import { simpleStyle } from '@/styles';
7
+ import { Label } from '@twintag-form/components';
8
+ import { simpleStyle } from '@twintag-form/styles';
8
9
 
9
10
  type Props = CommonProps<VariantProps<typeof simpleStyle>['variant']>;
10
11
 
11
12
  const Textarea = ({ useForm, label, bind, options }: Props) => {
12
- const id = useId();
13
-
14
13
  const { container, span, input } = useMemo(() => {
15
14
  if (options?.variant) return simpleStyle({ variant: options.variant });
16
15
  return simpleStyle();
17
16
  }, []);
18
17
 
19
18
  return (
20
- <div className={container()}>
21
- <label htmlFor={id}>
22
- <span className={span()}>{label as string}</span>
23
- </label>
19
+ <label className={container()}>
20
+ {label ? (
21
+ <Label className={span()} required={!options?.optionalField}>
22
+ {label as string}
23
+ </Label>
24
+ ) : (
25
+ <></>
26
+ )}
27
+
24
28
  <textarea
25
- id={id}
26
29
  className={input()}
27
30
  placeholder={options?.placeholder || 'Write here...'}
28
31
  {...useForm!.register(bind as string, {
29
32
  required: options?.optionalField ? false : `${label} is required`,
30
33
  })}
31
34
  />
32
- </div>
35
+ </label>
33
36
  );
34
37
  };
35
38
 
@@ -4,9 +4,10 @@ import { useMemo } from 'react';
4
4
  import { useController } from 'react-hook-form';
5
5
  import * as Switch from '@radix-ui/react-switch';
6
6
 
7
- import type { CommonProps } from '@/types';
7
+ import type { CommonProps } from '@twintag-form/types';
8
8
 
9
- import { toggleStyle } from '@/styles';
9
+ import { Label } from '@twintag-form/components';
10
+ import { toggleStyle } from '@twintag-form/styles';
10
11
 
11
12
  type Props = CommonProps<VariantProps<typeof toggleStyle>['variant']>;
12
13
 
@@ -28,22 +29,26 @@ const Toggle = ({ useForm, label, bind, options }: Props) => {
28
29
  });
29
30
 
30
31
  return (
31
- <div className='w-full'>
32
- <label className={container()}>
33
- {label ? <span className={span()}>{label as string}</span> : <></>}
34
-
35
- <Switch.Root
36
- id={bind as string}
37
- checked={value}
38
- className={input()}
39
- onCheckedChange={(state) => {
40
- onChange(state);
41
- }}
42
- >
43
- <Switch.Thumb className={thumb()} />
44
- </Switch.Root>
45
- </label>
46
- </div>
32
+ <label className={container()}>
33
+ {label ? (
34
+ <Label className={span()} required={!options?.optionalField}>
35
+ {label as string}
36
+ </Label>
37
+ ) : (
38
+ <></>
39
+ )}
40
+
41
+ <Switch.Root
42
+ id={bind as string}
43
+ checked={value}
44
+ className={input()}
45
+ onCheckedChange={(state) => {
46
+ onChange(state);
47
+ }}
48
+ >
49
+ <Switch.Thumb className={thumb()} />
50
+ </Switch.Root>
51
+ </label>
47
52
  );
48
53
  };
49
54
 
@@ -0,0 +1,22 @@
1
+ import type { WithChildren } from 'twintag-types/dom';
2
+
3
+ import { labelStyle } from '@twintag-form/styles';
4
+
5
+ type Props = {
6
+ required?: boolean;
7
+ className?: string;
8
+ } & WithChildren;
9
+
10
+ const Label = ({ className, required, children }: Props) => {
11
+ const style = labelStyle({
12
+ className,
13
+ })
14
+
15
+ return (
16
+ <span className={style}>
17
+ {children} {required ? '*' : ''}
18
+ </span>
19
+ );
20
+ };
21
+
22
+ export default Label;
@@ -0,0 +1,5 @@
1
+ import Form from './Form';
2
+ import Input from './Input';
3
+ import Label from './Label';
4
+
5
+ export { Form, Input, Label };
package/lib/index.tsx CHANGED
@@ -2,8 +2,8 @@ import type { FC, ReactNode } from 'react';
2
2
 
3
3
  import { LabelToString } from 'twintag-types/dom';
4
4
 
5
- import Input from './components/Input';
6
- import Form from './components/Form';
5
+ import Input from '@twintag-form/components/Input';
6
+ import Form from '@twintag-form/components/Form';
7
7
 
8
8
  type Config = {
9
9
  key?: number;
@@ -149,7 +149,7 @@ const FormRenderer = ({ config }: RendererProps) => {
149
149
  };
150
150
 
151
151
  type Props = {
152
- config: Component[];
152
+ config: Config[];
153
153
  options?: {
154
154
  variant?: string;
155
155
  resetOnSubmit?: boolean;
package/lib/styles.ts CHANGED
@@ -1,5 +1,9 @@
1
1
  import { tv } from 'tailwind-variants';
2
2
 
3
+ export const labelStyle = tv({
4
+ base: 'font-fftext text-label',
5
+ })
6
+
3
7
  export const checkboxStyle = tv({
4
8
  slots: {
5
9
  container: 'flex gap-4 items-center w-full',
@@ -24,7 +28,7 @@ export const checkboxStyle = tv({
24
28
  export const fileStyle = tv({
25
29
  slots: {
26
30
  container: 'w-full block',
27
- span: 'font-semibold',
31
+ span: '',
28
32
  input:
29
33
  'w-full cursor-pointer ring-0 focus:ring-0 border-2 border-transparent',
30
34
  },
@@ -36,7 +40,7 @@ export const fileStyle = tv({
36
40
  'flex items-center justify-between gap-4 rounded-md px-3 py-2 border-slate-700/10 peer-focus:border-accent',
37
41
  },
38
42
  beta: {
39
- container: 'grid gap-1.5',
43
+ container: 'grid gap-0',
40
44
  input:
41
45
  'flex items-center justify-between gap-4 py-2 border-b-slate-700/10 peer-focus:border-b-accent',
42
46
  },
@@ -50,9 +54,9 @@ export const fileStyle = tv({
50
54
  export const simpleStyle = tv({
51
55
  slots: {
52
56
  container: 'w-full',
53
- span: 'font-semibold',
57
+ span: '',
54
58
  input:
55
- 'w-full ring-0 placeholder:text-slate-400 focus:ring-0 border-2 border-transparent',
59
+ 'w-full ring-0 placeholder:text-slate-400 focus:ring-0 border-2 border-transparent text-input',
56
60
  },
57
61
  variants: {
58
62
  variant: {
@@ -61,7 +65,7 @@ export const simpleStyle = tv({
61
65
  input: 'rounded-md border-slate-700/10 focus:border-accent',
62
66
  },
63
67
  beta: {
64
- container: 'grid gap-1.5',
68
+ container: 'grid gap-0',
65
69
  input:
66
70
  'px-0 focus:border-transparent focus:border-b-accent border-b-slate-700/10',
67
71
  },
@@ -88,7 +92,7 @@ export const submitStyle = tv({
88
92
  export const toggleStyle = tv({
89
93
  slots: {
90
94
  container: 'w-full cursor-pointer',
91
- span: 'font-semibold',
95
+ span: '',
92
96
  input: 'relative outline-none ring-2 ring-transparent',
93
97
  thumb: 'block transition-transform duration-100 will-change-transform',
94
98
  },
@@ -97,14 +101,14 @@ export const toggleStyle = tv({
97
101
  alpha: {
98
102
  container: 'flex justify-between',
99
103
  input:
100
- 'h-6 w-9 rounded-full bg-primary border border-black ring-2 focus:ring-accent data-[state=checked]:bg-white',
104
+ 'h-6 w-9 rounded-full bg-primary border border-black ring-2 focus:border-transparent focus:ring-accent data-[state=checked]:bg-white',
101
105
  thumb:
102
106
  'h-4 w-4 translate-x-0.5 rounded-full bg-white data-[state=checked]:translate-x-4 data-[state=checked]:bg-primary',
103
107
  },
104
108
  beta: {
105
109
  container: 'flex justify-between',
106
110
  input:
107
- 'h-6 w-9 rounded-full bg-primary border border-black ring-2 focus:border-transparent focus:ring-accent data-[state=checked]:bg-white',
111
+ 'h-6 w-9 rounded-full bg-primary border border-black ring-2 focus:border-transparent focus:ring-accent data-[state=checked]:bg-white',
108
112
  thumb:
109
113
  'h-4 w-4 translate-x-0.5 rounded-full bg-white data-[state=checked]:translate-x-4 data-[state=checked]:bg-primary',
110
114
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@twintag/twintag-form",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "author": "Twintag",
5
5
  "type": "module",
6
6
  "exports": {
@@ -20,6 +20,7 @@
20
20
  "@r2wc/react-to-web-component": "^2.0.2",
21
21
  "@radix-ui/react-checkbox": "^1.0.4",
22
22
  "@radix-ui/react-switch": "^1.0.2",
23
+ "@storybook/react": "7.0.2",
23
24
  "@twind/core": "^1.1.3",
24
25
  "@twind/preset-autoprefix": "^1.0.7",
25
26
  "@twind/preset-tailwind": "^1.1.4",
@@ -34,11 +35,8 @@
34
35
  "@rollup/plugin-typescript": "^11.1.1",
35
36
  "@types/react": "^18.0.28",
36
37
  "@types/react-dom": "^18.0.11",
37
- "@vitejs/plugin-react-swc": "^3.0.0",
38
38
  "eslint": "^8.38.0",
39
39
  "rollup": "^3.18.0",
40
- "typescript": "^5.0.2",
41
- "vite": "^4.1.0",
42
40
  "vite-plugin-dts": "^2.1.0",
43
41
  "tailwind-config": "0.0.0",
44
42
  "tsconfig": "0.0.0",
package/scripts/build.js CHANGED
@@ -22,6 +22,11 @@ const webcomponentsLibrary = {
22
22
 
23
23
  const getSharedConfiguration = ({ plugins, ...library }) => {
24
24
  return defineConfig({
25
+ resolve: {
26
+ alias: {
27
+ '@twintag-form': resolve(__dirname, '../lib'),
28
+ }
29
+ },
25
30
  plugins: [react(), typescript(), ...plugins],
26
31
  build: {
27
32
  lib: {
package/tsconfig.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "compilerOptions": {
6
6
  "baseUrl": ".",
7
7
  "paths": {
8
- "@/*": ["./lib/*"]
8
+ "@twintag-form/*": ["./lib/*"]
9
9
  },
10
10
  "outDir": "./dist",
11
11
  "declaration": true
package/twind.config.ts CHANGED
@@ -10,7 +10,12 @@ export default defineConfig({
10
10
  colors: {
11
11
  primary: 'var(--clr-primary,black)',
12
12
  accent: 'var(--clr-accent,blue)',
13
+ label: 'var(--clr-label,black)',
14
+ input: 'var(--clr-input,black)',
13
15
  },
16
+ fontFamily: {
17
+ fftext: ['var(--ff-text)', 'Helvetica', 'Arial', 'sans-serif'],
18
+ }
14
19
  },
15
20
  },
16
21
  presets: [