@regardio/react 0.5.7 → 0.7.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 (214) hide show
  1. package/dist/background-slideshow/index.d.mts +34 -0
  2. package/dist/background-slideshow/index.mjs +110 -0
  3. package/dist/blurry-gradient/index.d.mts +16 -0
  4. package/dist/blurry-gradient/index.mjs +93 -0
  5. package/dist/button/index.d.mts +2 -0
  6. package/dist/button/index.mjs +3 -0
  7. package/dist/button-BiSQpBbc.mjs +129 -0
  8. package/dist/carousel/index.d.mts +74 -0
  9. package/dist/carousel/index.mjs +136 -0
  10. package/dist/checkbox/index.d.mts +28 -0
  11. package/dist/checkbox/index.mjs +70 -0
  12. package/dist/checkbox-group/index.d.mts +16 -0
  13. package/dist/checkbox-group/index.mjs +29 -0
  14. package/dist/chunk-BTpB_u-K.mjs +18 -0
  15. package/dist/countdown/index.d.mts +4 -0
  16. package/dist/countdown/index.mjs +58 -0
  17. package/dist/field/index.d.mts +68 -0
  18. package/dist/field/index.mjs +115 -0
  19. package/dist/fieldset/index.d.mts +34 -0
  20. package/dist/fieldset/index.mjs +61 -0
  21. package/dist/form/index.d.mts +21 -0
  22. package/dist/form/index.mjs +31 -0
  23. package/dist/generic-error/index.d.mts +44 -0
  24. package/dist/generic-error/index.mjs +57 -0
  25. package/dist/grid/index.d.mts +101 -0
  26. package/dist/grid/index.mjs +219 -0
  27. package/dist/heading/index.d.mts +27 -0
  28. package/dist/heading/index.mjs +28 -0
  29. package/dist/highlight/index.d.mts +17 -0
  30. package/dist/highlight/index.mjs +35 -0
  31. package/dist/hooks/use-current-route-data.d.mts +8 -0
  32. package/dist/hooks/use-current-route-data.mjs +22 -0
  33. package/dist/hooks/{use-focus-search.d.ts → use-focus-search.d.mts} +4 -3
  34. package/dist/hooks/use-focus-search.mjs +23 -0
  35. package/dist/hooks/use-matches-data.d.mts +10 -0
  36. package/dist/hooks/use-matches-data.mjs +23 -0
  37. package/dist/hooks/use-media-query.d.mts +9 -0
  38. package/dist/hooks/use-media-query.mjs +28 -0
  39. package/dist/hooks/use-mobile.d.mts +4 -0
  40. package/dist/hooks/use-mobile.mjs +22 -0
  41. package/dist/hooks/use-nonce.d.mts +6 -0
  42. package/dist/hooks/use-nonce.mjs +13 -0
  43. package/dist/hooks/use-orientation.d.mts +12 -0
  44. package/dist/hooks/use-orientation.mjs +32 -0
  45. package/dist/hooks/use-user.d.mts +53 -0
  46. package/dist/hooks/use-user.mjs +39 -0
  47. package/dist/icon-button/index.d.mts +28 -0
  48. package/dist/icon-button/index.mjs +36 -0
  49. package/dist/if/index.d.mts +13 -0
  50. package/dist/if/index.mjs +21 -0
  51. package/dist/iframe/index.d.mts +11 -0
  52. package/dist/iframe/index.mjs +15 -0
  53. package/dist/index-Bj5_XfEC.d.mts +29 -0
  54. package/dist/index-C_evL5vG.d.mts +35 -0
  55. package/dist/input/index.d.mts +2 -0
  56. package/dist/input/index.mjs +3 -0
  57. package/dist/input-CtR6aRVi.mjs +73 -0
  58. package/dist/link/index.d.mts +71 -0
  59. package/dist/link/index.mjs +129 -0
  60. package/dist/list/index.d.mts +72 -0
  61. package/dist/list/index.mjs +54 -0
  62. package/dist/markdown-container/index.d.mts +23 -0
  63. package/dist/markdown-container/index.mjs +71 -0
  64. package/dist/password-input/index.d.mts +23 -0
  65. package/dist/password-input/index.mjs +92 -0
  66. package/dist/picture/index.d.mts +39 -0
  67. package/dist/picture/index.mjs +3 -0
  68. package/dist/picture-DkX3W5zl.mjs +69 -0
  69. package/dist/protected-email/index.d.mts +24 -0
  70. package/dist/protected-email/index.mjs +37 -0
  71. package/dist/radio/index.d.mts +28 -0
  72. package/dist/radio/index.mjs +72 -0
  73. package/dist/radio-group/index.d.mts +16 -0
  74. package/dist/radio-group/index.mjs +29 -0
  75. package/dist/slider/index.d.mts +63 -0
  76. package/dist/slider/index.mjs +133 -0
  77. package/dist/switch/index.d.mts +29 -0
  78. package/dist/switch/index.mjs +87 -0
  79. package/dist/text/index.d.mts +25 -0
  80. package/dist/text/index.mjs +32 -0
  81. package/dist/text-EQC4zJbE.mjs +52 -0
  82. package/dist/toggle/index.d.mts +25 -0
  83. package/dist/toggle/index.mjs +82 -0
  84. package/dist/utils/author/index.d.mts +4 -0
  85. package/dist/utils/author/index.mjs +26 -0
  86. package/dist/utils/text/{index.d.ts → index.d.mts} +9 -8
  87. package/dist/utils/text/index.mjs +3 -0
  88. package/package.json +131 -83
  89. package/src/background-slideshow/background-slideshow.tsx +1 -2
  90. package/src/blurry-gradient/blurry-gradient.tsx +1 -1
  91. package/src/button/button.stories.tsx +161 -0
  92. package/src/button/button.test.tsx +73 -0
  93. package/src/button/button.tsx +118 -0
  94. package/src/button/index.ts +2 -0
  95. package/src/carousel/carousel-content.tsx +17 -14
  96. package/src/carousel/carousel-item.tsx +18 -18
  97. package/src/carousel/carousel-next.tsx +22 -17
  98. package/src/carousel/carousel-previous.tsx +22 -17
  99. package/src/carousel/carousel-root.tsx +91 -86
  100. package/src/checkbox/checkbox.stories.tsx +118 -0
  101. package/src/checkbox/checkbox.tsx +102 -0
  102. package/src/checkbox/index.ts +2 -0
  103. package/src/checkbox-group/checkbox-group.tsx +40 -0
  104. package/src/checkbox-group/index.ts +2 -0
  105. package/src/countdown/countdown.tsx +1 -1
  106. package/src/field/field.stories.tsx +105 -0
  107. package/src/field/field.test.tsx +61 -0
  108. package/src/field/field.tsx +186 -0
  109. package/src/field/index.ts +12 -0
  110. package/src/fieldset/fieldset.stories.tsx +204 -0
  111. package/src/fieldset/fieldset.test.tsx +63 -0
  112. package/src/fieldset/fieldset.tsx +86 -0
  113. package/src/fieldset/index.ts +7 -0
  114. package/src/form/form.stories.tsx +230 -0
  115. package/src/form/form.test.tsx +68 -0
  116. package/src/form/form.tsx +38 -0
  117. package/src/form/index.ts +2 -0
  118. package/src/generic-error/generic-error.tsx +2 -3
  119. package/src/grid/grid-item.tsx +77 -36
  120. package/src/grid/grid-root.tsx +49 -22
  121. package/src/heading/heading.tsx +7 -3
  122. package/src/highlight/highlight.tsx +1 -1
  123. package/src/hooks/use-current-route-data.ts +4 -2
  124. package/src/hooks/use-focus-search.ts +3 -1
  125. package/src/hooks/use-matches-data.ts +2 -0
  126. package/src/hooks/use-media-query.ts +2 -0
  127. package/src/hooks/use-mobile.ts +3 -1
  128. package/src/hooks/use-nonce.ts +3 -3
  129. package/src/hooks/use-orientation.ts +2 -0
  130. package/src/hooks/use-user.tsx +3 -2
  131. package/src/icon-button/icon-button.stories.tsx +128 -7
  132. package/src/icon-button/icon-button.test.tsx +152 -0
  133. package/src/icon-button/icon-button.tsx +43 -9
  134. package/src/if/if.tsx +3 -1
  135. package/src/input/index.ts +2 -0
  136. package/src/input/input.stories.tsx +151 -0
  137. package/src/input/input.test.tsx +65 -0
  138. package/src/input/input.tsx +113 -0
  139. package/src/link/link.tsx +4 -3
  140. package/src/list/list-item.tsx +10 -13
  141. package/src/list/list-root-context.ts +3 -3
  142. package/src/list/list-root.tsx +10 -13
  143. package/src/password-input/index.ts +1 -1
  144. package/src/password-input/password-input.tsx +104 -27
  145. package/src/protected-email/protected-email.tsx +6 -1
  146. package/src/radio/index.ts +2 -0
  147. package/src/radio/radio.tsx +103 -0
  148. package/src/radio-group/index.ts +2 -0
  149. package/src/radio-group/radio-group.tsx +40 -0
  150. package/src/slider/index.ts +18 -0
  151. package/src/slider/slider.tsx +201 -0
  152. package/src/switch/index.ts +2 -0
  153. package/src/switch/switch.stories.tsx +118 -0
  154. package/src/switch/switch.tsx +112 -0
  155. package/src/text/text.tsx +6 -1
  156. package/src/toggle/index.ts +2 -0
  157. package/src/toggle/toggle.stories.tsx +232 -0
  158. package/src/toggle/toggle.test.tsx +149 -0
  159. package/src/toggle/toggle.tsx +88 -0
  160. package/src/utils/text/text.tsx +8 -16
  161. package/dist/background-slideshow/index.d.ts +0 -24
  162. package/dist/background-slideshow/index.js +0 -165
  163. package/dist/blurry-gradient/index.d.ts +0 -16
  164. package/dist/blurry-gradient/index.js +0 -128
  165. package/dist/carousel/index.d.ts +0 -36
  166. package/dist/carousel/index.js +0 -171
  167. package/dist/countdown/index.d.ts +0 -5
  168. package/dist/countdown/index.js +0 -73
  169. package/dist/generic-error/index.d.ts +0 -43
  170. package/dist/generic-error/index.js +0 -47
  171. package/dist/grid/index.d.ts +0 -1196
  172. package/dist/grid/index.js +0 -239
  173. package/dist/heading/index.d.ts +0 -24
  174. package/dist/heading/index.js +0 -99
  175. package/dist/highlight/index.d.ts +0 -13
  176. package/dist/highlight/index.js +0 -59
  177. package/dist/hooks/use-current-route-data.d.ts +0 -7
  178. package/dist/hooks/use-current-route-data.js +0 -16
  179. package/dist/hooks/use-focus-search.js +0 -19
  180. package/dist/hooks/use-matches-data.d.ts +0 -9
  181. package/dist/hooks/use-matches-data.js +0 -15
  182. package/dist/hooks/use-media-query.d.ts +0 -8
  183. package/dist/hooks/use-media-query.js +0 -20
  184. package/dist/hooks/use-mobile.d.ts +0 -3
  185. package/dist/hooks/use-mobile.js +0 -19
  186. package/dist/hooks/use-nonce.d.ts +0 -7
  187. package/dist/hooks/use-nonce.js +0 -8
  188. package/dist/hooks/use-orientation.d.ts +0 -11
  189. package/dist/hooks/use-orientation.js +0 -29
  190. package/dist/hooks/use-user.d.ts +0 -50
  191. package/dist/hooks/use-user.js +0 -25
  192. package/dist/icon-button/index.d.ts +0 -9
  193. package/dist/icon-button/index.js +0 -17
  194. package/dist/if/index.d.ts +0 -10
  195. package/dist/if/index.js +0 -24
  196. package/dist/iframe/index.d.ts +0 -10
  197. package/dist/iframe/index.js +0 -17
  198. package/dist/link/index.d.ts +0 -55
  199. package/dist/link/index.js +0 -195
  200. package/dist/list/index.d.ts +0 -69
  201. package/dist/list/index.js +0 -65
  202. package/dist/markdown-container/index.d.ts +0 -22
  203. package/dist/markdown-container/index.js +0 -128
  204. package/dist/password-input/index.d.ts +0 -11
  205. package/dist/password-input/index.js +0 -46
  206. package/dist/picture/index.d.ts +0 -38
  207. package/dist/picture/index.js +0 -68
  208. package/dist/protected-email/index.d.ts +0 -20
  209. package/dist/protected-email/index.js +0 -30
  210. package/dist/text/index.d.ts +0 -20
  211. package/dist/text/index.js +0 -38
  212. package/dist/utils/author/index.d.ts +0 -3
  213. package/dist/utils/author/index.js +0 -33
  214. package/dist/utils/text/index.js +0 -73
@@ -0,0 +1,102 @@
1
+ import { Checkbox as BaseUICheckbox } from '@base-ui/react/checkbox';
2
+ import { tv } from '@regardio/tailwind/utils';
3
+ import type { ComponentProps } from 'react';
4
+
5
+ const checkboxRoot = tv({
6
+ base: [
7
+ 'h-4',
8
+ 'w-4',
9
+ 'rounded',
10
+ 'border',
11
+ 'border-gray-300',
12
+ 'bg-white',
13
+ 'focus:outline-none',
14
+ 'focus:ring-2',
15
+ 'focus:ring-blue-500',
16
+ 'focus:ring-offset-2',
17
+ 'disabled:cursor-not-allowed',
18
+ 'disabled:opacity-50',
19
+ 'data-[checked]:bg-blue-600',
20
+ 'data-[checked]:border-blue-600',
21
+ 'transition-colors',
22
+ 'duration-200',
23
+ 'cursor-pointer',
24
+ ],
25
+ defaultVariants: {
26
+ size: 'md',
27
+ },
28
+ variants: {
29
+ size: {
30
+ lg: ['h-5', 'w-5'],
31
+ md: ['h-4', 'w-4'],
32
+ sm: ['h-3', 'w-3'],
33
+ },
34
+ },
35
+ });
36
+
37
+ const checkboxIndicator = tv({
38
+ base: ['flex', 'items-center', 'justify-center', 'text-white', 'data-[unchecked]:invisible'],
39
+ });
40
+
41
+ export type CheckboxSize = 'sm' | 'md' | 'lg';
42
+
43
+ export interface CheckboxRootProps
44
+ extends Omit<ComponentProps<typeof BaseUICheckbox.Root>, 'className'> {
45
+ className?: string;
46
+ size?: CheckboxSize;
47
+ }
48
+
49
+ export interface CheckboxIndicatorProps
50
+ extends Omit<ComponentProps<typeof BaseUICheckbox.Indicator>, 'className'> {
51
+ className?: string;
52
+ }
53
+
54
+ export const CheckboxRoot = ({
55
+ className,
56
+ size = 'md',
57
+ ...props
58
+ }: CheckboxRootProps): React.JSX.Element => {
59
+ return (
60
+ <BaseUICheckbox.Root
61
+ className={checkboxRoot({
62
+ className,
63
+ size,
64
+ })}
65
+ {...props}
66
+ />
67
+ );
68
+ };
69
+
70
+ export const CheckboxIndicator = ({
71
+ className,
72
+ children,
73
+ ...props
74
+ }: CheckboxIndicatorProps): React.JSX.Element => {
75
+ return (
76
+ <BaseUICheckbox.Indicator
77
+ className={checkboxIndicator({ className })}
78
+ {...props}
79
+ >
80
+ {children || (
81
+ <svg
82
+ fill="none"
83
+ height="12"
84
+ stroke="currentColor"
85
+ strokeWidth="2"
86
+ viewBox="0 0 12 12"
87
+ width="12"
88
+ >
89
+ <polyline points="2,6 5,9 10,3" />
90
+ </svg>
91
+ )}
92
+ </BaseUICheckbox.Indicator>
93
+ );
94
+ };
95
+
96
+ export const Checkbox: {
97
+ Indicator: typeof CheckboxIndicator;
98
+ Root: typeof CheckboxRoot;
99
+ } = {
100
+ Indicator: CheckboxIndicator,
101
+ Root: CheckboxRoot,
102
+ };
@@ -0,0 +1,2 @@
1
+ export type { CheckboxIndicatorProps, CheckboxRootProps, CheckboxSize } from './checkbox';
2
+ export { Checkbox, CheckboxIndicator, CheckboxRoot } from './checkbox';
@@ -0,0 +1,40 @@
1
+ import { CheckboxGroup as BaseUICheckboxGroup } from '@base-ui/react/checkbox-group';
2
+ import { tv } from '@regardio/tailwind/utils';
3
+ import type { ComponentProps } from 'react';
4
+
5
+ const checkboxGroup = tv({
6
+ base: ['flex', 'flex-col', 'gap-2'],
7
+ defaultVariants: {
8
+ orientation: 'vertical',
9
+ },
10
+ variants: {
11
+ orientation: {
12
+ horizontal: ['flex-row', 'gap-4'],
13
+ vertical: ['flex-col', 'gap-2'],
14
+ },
15
+ },
16
+ });
17
+
18
+ export type CheckboxGroupOrientation = 'horizontal' | 'vertical';
19
+
20
+ export interface CheckboxGroupProps
21
+ extends Omit<ComponentProps<typeof BaseUICheckboxGroup>, 'className'> {
22
+ className?: string;
23
+ orientation?: CheckboxGroupOrientation;
24
+ }
25
+
26
+ export const CheckboxGroup = ({
27
+ className,
28
+ orientation = 'vertical',
29
+ ...props
30
+ }: CheckboxGroupProps): React.JSX.Element => {
31
+ return (
32
+ <BaseUICheckboxGroup
33
+ className={checkboxGroup({
34
+ className,
35
+ orientation,
36
+ })}
37
+ {...props}
38
+ />
39
+ );
40
+ };
@@ -0,0 +1,2 @@
1
+ export type { CheckboxGroupOrientation, CheckboxGroupProps } from './checkbox-group';
2
+ export { CheckboxGroup } from './checkbox-group';
@@ -3,7 +3,7 @@
3
3
  import { cn } from '@regardio/tailwind/utils';
4
4
  import { useEffect, useState } from 'react';
5
5
 
6
- export function Countdown() {
6
+ export function Countdown(): React.JSX.Element {
7
7
  const [timerValue, setTimerValue] = useState(0);
8
8
  const [isMounted, setIsMounted] = useState(false);
9
9
 
@@ -0,0 +1,105 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import { Checkbox } from '../checkbox';
3
+ import { Input } from '../input';
4
+ import { Field } from './field';
5
+
6
+ const meta: Meta<typeof Field.Root> = {
7
+ argTypes: {
8
+ variant: {
9
+ control: 'select',
10
+ description: 'Field variant',
11
+ options: ['default', 'required'],
12
+ },
13
+ },
14
+ component: Field.Root,
15
+ parameters: {
16
+ layout: 'centered',
17
+ },
18
+ tags: ['autodocs'],
19
+ title: 'Components/Field',
20
+ } satisfies Meta<typeof Field.Root>;
21
+
22
+ export default meta;
23
+ type Story = StoryObj<typeof meta>;
24
+
25
+ export const Default: Story = {
26
+ render: () => (
27
+ <Field.Root>
28
+ <Field.Label>Email Address</Field.Label>
29
+ <Input placeholder="Enter your email" />
30
+ <Field.Description>We'll never share your email with anyone else.</Field.Description>
31
+ </Field.Root>
32
+ ),
33
+ };
34
+
35
+ export const WithError: Story = {
36
+ render: () => (
37
+ <Field.Root>
38
+ <Field.Label variant="error">Email Address</Field.Label>
39
+ <Input
40
+ placeholder="Enter your email"
41
+ variant="error"
42
+ />
43
+ <Field.Error>This field is required</Field.Error>
44
+ </Field.Root>
45
+ ),
46
+ };
47
+
48
+ export const Required: Story = {
49
+ render: () => (
50
+ <Field.Root variant="required">
51
+ <Field.Label>Full Name</Field.Label>
52
+ <Input placeholder="Enter your full name" />
53
+ <Field.Description>Please enter your first and last name.</Field.Description>
54
+ </Field.Root>
55
+ ),
56
+ };
57
+
58
+ export const HorizontalLayout: Story = {
59
+ render: () => (
60
+ <Field.Root>
61
+ <Field.Item layout="horizontal">
62
+ <Checkbox.Root>
63
+ <Checkbox.Indicator />
64
+ </Checkbox.Root>
65
+ <Field.Label>Subscribe to newsletter</Field.Label>
66
+ </Field.Item>
67
+ <Field.Description>Receive updates about new features</Field.Description>
68
+ </Field.Root>
69
+ ),
70
+ };
71
+
72
+ export const MultipleFields: Story = {
73
+ render: () => (
74
+ <div className="space-y-6">
75
+ <Field.Root>
76
+ <Field.Label>First Name</Field.Label>
77
+ <Input placeholder="Enter your first name" />
78
+ </Field.Root>
79
+ <Field.Root>
80
+ <Field.Label>Last Name</Field.Label>
81
+ <Input placeholder="Enter your last name" />
82
+ </Field.Root>
83
+ <Field.Root variant="required">
84
+ <Field.Label>Email</Field.Label>
85
+ <Input
86
+ placeholder="Enter your email"
87
+ type="email"
88
+ />
89
+ <Field.Description>We'll never share your email.</Field.Description>
90
+ </Field.Root>
91
+ </div>
92
+ ),
93
+ };
94
+
95
+ export const WithCustomClass: Story = {
96
+ render: () => (
97
+ <Field.Root className="bg-gray-50 p-4 rounded-lg">
98
+ <Field.Label className="text-blue-600">Custom Field</Field.Label>
99
+ <Input
100
+ className="bg-white border-blue-300"
101
+ placeholder="Custom styled input"
102
+ />
103
+ </Field.Root>
104
+ ),
105
+ };
@@ -0,0 +1,61 @@
1
+ import { render, screen } from '@testing-library/react';
2
+ import { describe, expect, it } from 'vitest';
3
+ import { Field } from './field';
4
+
5
+ describe('Field', () => {
6
+ it('renders FieldRoot with children', () => {
7
+ render(
8
+ <Field.Root>
9
+ <Field.Label>Test Label</Field.Label>
10
+ <Field.Control />
11
+ </Field.Root>,
12
+ );
13
+ expect(screen.getByText('Test Label')).toBeInTheDocument();
14
+ });
15
+
16
+ it('renders FieldDescription', () => {
17
+ render(
18
+ <Field.Root>
19
+ <Field.Description>Test Description</Field.Description>
20
+ </Field.Root>,
21
+ );
22
+ expect(screen.getByText('Test Description')).toBeInTheDocument();
23
+ });
24
+
25
+ it('renders FieldError', () => {
26
+ render(
27
+ <Field.Root invalid>
28
+ <Field.Error match={true}>Test Error</Field.Error>
29
+ </Field.Root>,
30
+ );
31
+ expect(screen.getByText('Test Error')).toBeInTheDocument();
32
+ });
33
+
34
+ it('renders FieldItem with layout', () => {
35
+ render(
36
+ <Field.Item layout="horizontal">
37
+ <span>Test Content</span>
38
+ </Field.Item>,
39
+ );
40
+ expect(screen.getByText('Test Content')).toBeInTheDocument();
41
+ });
42
+
43
+ it('applies custom className to FieldRoot', () => {
44
+ render(
45
+ <Field.Root className="custom-field">
46
+ <Field.Label>Test</Field.Label>
47
+ </Field.Root>,
48
+ );
49
+ const fieldRoot = screen.getByText('Test').parentElement;
50
+ expect(fieldRoot).toHaveClass('custom-field');
51
+ });
52
+
53
+ it('applies variant styles to FieldLabel', () => {
54
+ render(
55
+ <Field.Root>
56
+ <Field.Label variant="error">Error Label</Field.Label>
57
+ </Field.Root>,
58
+ );
59
+ expect(screen.getByText('Error Label')).toHaveClass('text-red-600');
60
+ });
61
+ });
@@ -0,0 +1,186 @@
1
+ import { Field as BaseUIField } from '@base-ui/react/field';
2
+ import { tv } from '@regardio/tailwind/utils';
3
+ import type { ComponentProps, ReactNode } from 'react';
4
+
5
+ const fieldRootVariants = {
6
+ default: [],
7
+ required: ['after:content-["*"]', 'after:ml-1', 'after:text-red-500'],
8
+ } as const;
9
+
10
+ const fieldRoot = tv({
11
+ base: ['space-y-1'],
12
+ defaultVariants: {
13
+ variant: 'default',
14
+ },
15
+ variants: {
16
+ variant: fieldRootVariants,
17
+ },
18
+ });
19
+
20
+ const fieldLabel = tv({
21
+ base: ['block', 'text-sm', 'font-medium', 'text-gray-700', 'mb-1'],
22
+ defaultVariants: {
23
+ variant: 'default',
24
+ },
25
+ variants: {
26
+ variant: {
27
+ default: [],
28
+ error: ['text-red-600'],
29
+ },
30
+ },
31
+ });
32
+
33
+ const fieldDescription = tv({
34
+ base: ['text-sm', 'text-gray-500', 'mt-1'],
35
+ defaultVariants: {
36
+ variant: 'default',
37
+ },
38
+ variants: {
39
+ variant: {
40
+ default: [],
41
+ error: ['text-red-600'],
42
+ },
43
+ },
44
+ });
45
+
46
+ const fieldError = tv({
47
+ base: ['text-sm', 'text-red-600', 'mt-1'],
48
+ });
49
+
50
+ const fieldItem = tv({
51
+ base: ['flex', 'flex-col'],
52
+ defaultVariants: {
53
+ layout: 'default',
54
+ },
55
+ variants: {
56
+ layout: {
57
+ default: [],
58
+ horizontal: ['flex-row', 'items-center', 'gap-2'],
59
+ },
60
+ },
61
+ });
62
+
63
+ export type FieldRootVariant = keyof typeof fieldRootVariants;
64
+ export type FieldLabelVariant = 'default' | 'error';
65
+ export type FieldDescriptionVariant = 'default' | 'error';
66
+ export type FieldItemLayout = 'default' | 'horizontal';
67
+
68
+ export interface FieldRootProps extends Omit<ComponentProps<typeof BaseUIField.Root>, 'className'> {
69
+ className?: string;
70
+ variant?: FieldRootVariant;
71
+ }
72
+
73
+ export interface FieldLabelProps
74
+ extends Omit<ComponentProps<typeof BaseUIField.Label>, 'className'> {
75
+ className?: string;
76
+ variant?: FieldLabelVariant;
77
+ }
78
+
79
+ export interface FieldDescriptionProps
80
+ extends Omit<ComponentProps<typeof BaseUIField.Description>, 'className'> {
81
+ className?: string;
82
+ variant?: FieldDescriptionVariant;
83
+ }
84
+
85
+ export interface FieldErrorProps
86
+ extends Omit<ComponentProps<typeof BaseUIField.Error>, 'className'> {
87
+ className?: string;
88
+ }
89
+
90
+ export interface FieldItemProps extends ComponentProps<'div'> {
91
+ className?: string;
92
+ layout?: FieldItemLayout;
93
+ children: ReactNode;
94
+ }
95
+
96
+ export const FieldRoot = ({ className, variant, ...props }: FieldRootProps): React.JSX.Element => {
97
+ return (
98
+ <BaseUIField.Root
99
+ className={fieldRoot({
100
+ className,
101
+ variant,
102
+ })}
103
+ {...props}
104
+ />
105
+ );
106
+ };
107
+
108
+ export const FieldLabel = ({
109
+ className,
110
+ variant,
111
+ ...props
112
+ }: FieldLabelProps): React.JSX.Element => {
113
+ return (
114
+ <BaseUIField.Label
115
+ className={fieldLabel({
116
+ className,
117
+ variant,
118
+ })}
119
+ {...props}
120
+ />
121
+ );
122
+ };
123
+
124
+ export const FieldDescription = ({
125
+ className,
126
+ variant,
127
+ ...props
128
+ }: FieldDescriptionProps): React.JSX.Element => {
129
+ return (
130
+ <BaseUIField.Description
131
+ className={fieldDescription({
132
+ className,
133
+ variant,
134
+ })}
135
+ {...props}
136
+ />
137
+ );
138
+ };
139
+
140
+ export const FieldError = ({ className, ...props }: FieldErrorProps): React.JSX.Element => {
141
+ return (
142
+ <BaseUIField.Error
143
+ className={fieldError({
144
+ className,
145
+ })}
146
+ {...props}
147
+ />
148
+ );
149
+ };
150
+
151
+ export const FieldItem = ({
152
+ className,
153
+ layout,
154
+ children,
155
+ ...props
156
+ }: FieldItemProps): React.JSX.Element => {
157
+ return (
158
+ <div
159
+ className={fieldItem({
160
+ className,
161
+ layout,
162
+ })}
163
+ {...props}
164
+ >
165
+ {children}
166
+ </div>
167
+ );
168
+ };
169
+
170
+ export const Field: {
171
+ Control: typeof BaseUIField.Control;
172
+ Description: typeof FieldDescription;
173
+ Error: typeof FieldError;
174
+ Item: typeof FieldItem;
175
+ Label: typeof FieldLabel;
176
+ Root: typeof FieldRoot;
177
+ Validity: typeof BaseUIField.Validity;
178
+ } = {
179
+ Control: BaseUIField.Control,
180
+ Description: FieldDescription,
181
+ Error: FieldError,
182
+ Item: FieldItem,
183
+ Label: FieldLabel,
184
+ Root: FieldRoot,
185
+ Validity: BaseUIField.Validity,
186
+ };
@@ -0,0 +1,12 @@
1
+ export type {
2
+ FieldDescriptionProps,
3
+ FieldDescriptionVariant,
4
+ FieldErrorProps,
5
+ FieldItemLayout,
6
+ FieldItemProps,
7
+ FieldLabelProps,
8
+ FieldLabelVariant,
9
+ FieldRootProps,
10
+ FieldRootVariant,
11
+ } from './field';
12
+ export { Field } from './field';