@granto-umbrella/umbrella-components 3.0.34 → 3.0.37

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 (158) hide show
  1. package/README.md +165 -27
  2. package/dist/umbrella-components.css +1 -1
  3. package/dist/umbrella-components.es.js +33627 -28792
  4. package/dist/umbrella-components.umd.js +1169 -1908
  5. package/package.json +136 -106
  6. package/src/assets.d.ts +19 -19
  7. package/src/components/atoms/Badge/Badge.styles.ts +88 -86
  8. package/src/components/atoms/Badge/Badge.tsx +42 -44
  9. package/src/components/atoms/Badge/Badge.types.ts +15 -15
  10. package/src/components/atoms/Breadcrumb/Breadcrumb.styles.ts +43 -43
  11. package/src/components/atoms/Breadcrumb/Breadcrumb.tsx +46 -48
  12. package/src/components/atoms/Breadcrumb/Breadcrumb.types.ts +12 -12
  13. package/src/components/atoms/Button/Button.styles.ts +279 -280
  14. package/src/components/atoms/Button/Button.tsx +76 -76
  15. package/src/components/atoms/Button/Button.types.ts +28 -28
  16. package/src/components/atoms/Button/index.ts +1 -1
  17. package/src/components/atoms/Checkbox/Checkbox.styles.ts +72 -72
  18. package/src/components/atoms/Checkbox/Checkbox.tsx +36 -36
  19. package/src/components/atoms/Checkbox/Checkbox.types.ts +14 -14
  20. package/src/components/atoms/Checkbox/CheckboxGroup.tsx +30 -30
  21. package/src/components/atoms/Checkbox/CheckboxSelectAll.tsx +32 -32
  22. package/src/components/atoms/CodeInput/CodeInput.styles.tsx +38 -39
  23. package/src/components/atoms/CodeInput/CodeInput.tsx +13 -19
  24. package/src/components/atoms/CodeInput/CodeInput.types.ts +3 -3
  25. package/src/components/atoms/CodeInput/index.tsx +1 -1
  26. package/src/components/atoms/DropDownMenu/DropdownMenu.tsx +48 -48
  27. package/src/components/atoms/DropDownMenu/DropdownMenu.types.ts +15 -15
  28. package/src/components/atoms/DropDownMenu/index.tsx +5 -2
  29. package/src/components/atoms/ErrorMessage/ErrorMessage.styles.tsx +28 -28
  30. package/src/components/atoms/ErrorMessage/ErrorMessage.tsx +12 -12
  31. package/src/components/atoms/ErrorMessage/ErrorMessage.types.ts +6 -6
  32. package/src/components/atoms/ErrorMessage/index.tsx +1 -1
  33. package/src/components/atoms/Footer/Footer.styles.tsx +22 -22
  34. package/src/components/atoms/Footer/Footer.tsx +9 -9
  35. package/src/components/atoms/Footer/Footer.types.tsx +5 -5
  36. package/src/components/atoms/Footer/index.tsx +1 -1
  37. package/src/components/atoms/GenericContainer/GenericContainer.styles.tsx +21 -21
  38. package/src/components/atoms/GenericContainer/GenericContainer.tsx +9 -9
  39. package/src/components/atoms/GenericContainer/GenericContainer.types.ts +5 -5
  40. package/src/components/atoms/GenericContainer/index.tsx +1 -1
  41. package/src/components/atoms/Icon/Icon.styles.ts +11 -11
  42. package/src/components/atoms/Icon/Icon.tsx +22 -22
  43. package/src/components/atoms/Icon/Icon.types.ts +6 -6
  44. package/src/components/atoms/Icon/index.ts +1 -1
  45. package/src/components/atoms/Input/Input.styles.ts +106 -101
  46. package/src/components/atoms/Input/index.ts +1 -1
  47. package/src/components/atoms/Label/Label.tsx +16 -16
  48. package/src/components/atoms/Loading/Loading.styles.tsx +25 -25
  49. package/src/components/atoms/Loading/Loading.tsx +8 -8
  50. package/src/components/atoms/LogoContainer/LogoContainer.Types.tsx +5 -5
  51. package/src/components/atoms/LogoContainer/LogoContainer.styles.tsx +11 -11
  52. package/src/components/atoms/LogoContainer/LogoContainer.tsx +11 -11
  53. package/src/components/atoms/LogoContainer/index.tsx +1 -1
  54. package/src/components/atoms/ModalAviso/ModalAviso.styles.tsx +56 -56
  55. package/src/components/atoms/ModalAviso/ModalAviso.tsx +43 -37
  56. package/src/components/atoms/ModalAviso/ModalAviso.types.ts +5 -5
  57. package/src/components/atoms/ModalAviso/index.tsx +1 -1
  58. package/src/components/atoms/MultiSelect/MultiSelect.styles.tsx +100 -92
  59. package/src/components/atoms/MultiSelect/MultiSelect.tsx +346 -346
  60. package/src/components/atoms/MultiSelect/MultiSelect.types.ts +38 -38
  61. package/src/components/atoms/Pill/Pill.styles.ts +46 -46
  62. package/src/components/atoms/Pill/Pill.tsx +35 -36
  63. package/src/components/atoms/Pill/Pill.types.ts +14 -18
  64. package/src/components/atoms/RadioButton/RadioButton.styles.ts +44 -43
  65. package/src/components/atoms/RadioButton/RadioButton.tsx +31 -31
  66. package/src/components/atoms/ResendLink/ResendLink.styles.tsx +19 -20
  67. package/src/components/atoms/ResendLink/ResendLink.tsx +21 -21
  68. package/src/components/atoms/ResendLink/ResendLink.types.ts +8 -9
  69. package/src/components/atoms/ResendLink/index.tsx +1 -2
  70. package/src/components/atoms/Select/Select.styles.ts +153 -149
  71. package/src/components/atoms/Select/Select.tsx +52 -43
  72. package/src/components/atoms/Select/index.tsx +1 -1
  73. package/src/components/atoms/Subtitle/Subtitle.tsx +7 -7
  74. package/src/components/atoms/Subtitle/Subtitle.types.ts +5 -5
  75. package/src/components/atoms/Subtitle/index.tsx +1 -1
  76. package/src/components/atoms/Switch/Switch.tsx +25 -25
  77. package/src/components/atoms/TabBar/TabBar.styles.tsx +64 -57
  78. package/src/components/atoms/TabBar/index.tsx +2 -2
  79. package/src/components/atoms/Text/Text.styles.tsx +35 -35
  80. package/src/components/atoms/Text/Text.tsx +32 -31
  81. package/src/components/atoms/Text/Text.types.ts +8 -8
  82. package/src/components/atoms/Text/index.ts +1 -1
  83. package/src/components/atoms/Textarea/Textarea.styles.ts +52 -52
  84. package/src/components/atoms/Textarea/Textarea.tsx +31 -31
  85. package/src/components/atoms/Title/Title.tsx +7 -7
  86. package/src/components/atoms/Title/Title.types.ts +5 -5
  87. package/src/components/atoms/Title/index.tsx +1 -1
  88. package/src/components/molecules/BannerAjuda/BannerAjuda.styles.tsx +9 -9
  89. package/src/components/molecules/BannerAjuda/BannerAjuda.tsx +18 -19
  90. package/src/components/molecules/BannerAjuda/index.tsx +1 -1
  91. package/src/components/molecules/ButtonGroup/ButtonGroup.styles.ts +10 -10
  92. package/src/components/molecules/ButtonGroup/ButtonGroup.types.ts +22 -22
  93. package/src/components/molecules/Calendar/Calendar.styles.ts +143 -143
  94. package/src/components/molecules/Calendar/Calendar.tsx +31 -31
  95. package/src/components/molecules/CodeInputContainer/CodeInputContainer.styles.tsx +7 -7
  96. package/src/components/molecules/CodeInputContainer/CodeInputContainer.types.ts +13 -13
  97. package/src/components/molecules/CodeInputContainer/index.tsx +1 -3
  98. package/src/components/molecules/ExcludeModal/ExcludeModal.styles.tsx +123 -118
  99. package/src/components/molecules/ExcludeModal/ExcludeModal.tsx +48 -48
  100. package/src/components/molecules/ExcludeModal/ExcludeModal.types.ts +10 -10
  101. package/src/components/molecules/ExcludeModal/index.tsx +1 -1
  102. package/src/components/molecules/FieldSelector/FieldSelector.styles.ts +59 -0
  103. package/src/components/molecules/FieldSelector/FieldSelector.tsx +167 -0
  104. package/src/components/molecules/HighlightsCard/HighlightsCard.styles.tsx +67 -68
  105. package/src/components/molecules/HighlightsCard/HighlightsCard.tsx +35 -26
  106. package/src/components/molecules/HighlightsCard/HighlightsCard.types.ts +10 -10
  107. package/src/components/molecules/HighlightsCard/index.tsx +1 -1
  108. package/src/components/molecules/InsuranceCard/InsuranceCard.styles.tsx +237 -237
  109. package/src/components/molecules/InsuranceCard/index.tsx +1 -1
  110. package/src/components/molecules/PieChartComponent/PieChartComponent.styles.tsx +7 -8
  111. package/src/components/molecules/PieChartComponent/PieChartComponent.tsx +70 -73
  112. package/src/components/molecules/PieChartComponent/PieChartComponent.types.ts +11 -11
  113. package/src/components/molecules/PieChartComponent/index.tsx +1 -1
  114. package/src/components/molecules/Popover/Popover.styles.ts +66 -65
  115. package/src/components/molecules/Popover/Popover.tsx +23 -23
  116. package/src/components/molecules/RadioBoxGroup/RadioBoxGroup.styles.ts +11 -11
  117. package/src/components/molecules/RadioBoxGroup/RadioBoxGroup.tsx +43 -43
  118. package/src/components/molecules/RadioGroupField/RadioGroupField.styles.tsx +65 -64
  119. package/src/components/molecules/RadioGroupField/RadioGroupField.tsx +69 -69
  120. package/src/components/molecules/RadioGroupField/RadioGroupField.types.ts +17 -17
  121. package/src/components/molecules/RadioGroupField/index.tsx +1 -1
  122. package/src/components/molecules/RefuseModal/RefuseModal.styles.tsx +139 -139
  123. package/src/components/molecules/RefuseModal/RefuseModal.tsx +92 -76
  124. package/src/components/molecules/RefuseModal/RefuseModal.types.ts +15 -15
  125. package/src/components/molecules/RefuseModal/index.tsx +2 -2
  126. package/src/components/molecules/ResultsChart/ResultsChart.tsx +23 -19
  127. package/src/components/molecules/ResultsChart/ResultsChart.types.ts +3 -3
  128. package/src/components/molecules/ResultsChart/index.tsx +2 -2
  129. package/src/components/molecules/TabToggle/TabToggle.styles.ts +54 -54
  130. package/src/components/molecules/TabToggle/TabToggle.tsx +35 -35
  131. package/src/components/organisms/AlertDialog/AlertDialog.styles.tsx +61 -61
  132. package/src/components/organisms/AlertDialog/AlertDialog.tsx +70 -70
  133. package/src/components/organisms/Dialog/Dialog.styles.ts +107 -106
  134. package/src/components/organisms/Dialog/Dialog.tsx +69 -69
  135. package/src/components/organisms/DonutEmissionsChart/DonutEmissionsChart.styles.tsx +113 -113
  136. package/src/components/organisms/DonutEmissionsChart/DonutEmissionsChart.tsx +75 -71
  137. package/src/components/organisms/DonutEmissionsChart/DonutEmissionsChart.types.ts +9 -9
  138. package/src/components/organisms/DonutEmissionsChart/index.tsx +5 -2
  139. package/src/components/organisms/ExportExcelModal/ExportExcelModal.styles.ts +59 -0
  140. package/src/components/organisms/ExportExcelModal/ExportExcelModal.tsx +80 -0
  141. package/src/components/organisms/Form/Form.styles.ts +35 -35
  142. package/src/components/organisms/Form/Form.tsx +160 -160
  143. package/src/components/organisms/ListagemUltimasEmissoes/ListagemUltimasEmissoes.styles.tsx +115 -114
  144. package/src/components/organisms/ListagemUltimasEmissoes/ListagemUltimasEmissoes.tsx +89 -89
  145. package/src/components/organisms/ListagemUltimasEmissoes/ListagemUltimasEmissoes.types.ts +16 -16
  146. package/src/components/organisms/ListagemUltimasEmissoes/index.tsx +1 -1
  147. package/src/components/organisms/Navbar/Navbar.styles.tsx +243 -243
  148. package/src/global.d.ts +9 -9
  149. package/src/index.ts +4 -0
  150. package/src/lib/utils.ts +6 -6
  151. package/src/styles/tokens/borders.ts +17 -17
  152. package/src/styles/tokens/index.tsx +6 -6
  153. package/src/styles/tokens/radius.ts +22 -22
  154. package/src/styles/tokens/shadows.ts +22 -22
  155. package/src/styles/tokens/sizes.ts +60 -64
  156. package/src/types/radius.types.ts +1 -1
  157. package/src/types/shadows.types.ts +1 -1
  158. package/src/utils/renderHighlightsCard.tsx +21 -0
@@ -0,0 +1,80 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ import * as Dialog from '@radix-ui/react-dialog';
3
+ import { X } from 'lucide-react';
4
+ import {
5
+ CloseIcon,
6
+ Content,
7
+ Header,
8
+ Overlay,
9
+ Panel,
10
+ } from './ExportExcelModal.styles';
11
+ import FieldSelector from '../../molecules/FieldSelector/FieldSelector';
12
+ import ButtonGroup from '@/components/molecules/ButtonGroup/ButtonGroup';
13
+ export const ExportExcelModal = ({
14
+ open,
15
+ onOpenChange,
16
+ onClose,
17
+ data,
18
+ title,
19
+ description,
20
+ onExport,
21
+ onSave,
22
+ }: {
23
+ open: boolean;
24
+ onOpenChange: (open: boolean) => void;
25
+ onClose: () => void;
26
+ onRetry?: () => void;
27
+ data: any;
28
+ title: string;
29
+ description: string;
30
+ onExport?: (data: any) => void;
31
+ onSave?: (data: any) => void;
32
+ }) => {
33
+ return (
34
+ <Dialog.Root open={open} onOpenChange={onOpenChange}>
35
+ <Overlay />
36
+ <Content>
37
+ <Panel>
38
+ <Header>
39
+ <div>
40
+ <Dialog.Title>{title}</Dialog.Title>
41
+ <Dialog.Description>{description}</Dialog.Description>
42
+ </div>
43
+
44
+ <CloseIcon aria-label="Fechar" onClick={onClose}>
45
+ <X size={28} color="#BDBDBD" />
46
+ </CloseIcon>
47
+ </Header>
48
+
49
+ <FieldSelector
50
+ availableFields={data.available}
51
+ selectedFields={data.selected}
52
+ setAvailableFields={data.setAvailable}
53
+ setSelectedFields={data.setSelected}
54
+ handleSave={(data) => console.log('Nova ordem:', data)}
55
+ />
56
+
57
+ <ButtonGroup
58
+ buttons={[
59
+ {
60
+ label: 'Salvar e exportar planilha',
61
+ variant: 'primary',
62
+ onClick: () => {
63
+ if (onExport) onExport(data.selected);
64
+ },
65
+ },
66
+ {
67
+ label: 'Salvar configurações',
68
+ variant: 'outline',
69
+ onClick: () => {
70
+ if (onSave) onSave(data.selected);
71
+ },
72
+ },
73
+ ]}
74
+ orientation="horizontal"
75
+ />
76
+ </Panel>
77
+ </Content>
78
+ </Dialog.Root>
79
+ );
80
+ };
@@ -1,35 +1,35 @@
1
- // Form.styled.tsx
2
- import styled from "styled-components";
3
-
4
- /* Container para cada item do formulário */
5
- export const StyledFormItem = styled.div`
6
- display: flex;
7
- flex-direction: column;
8
- gap: 0.5rem; /* Aproximadamente o "space-y-2" do Tailwind */
9
- `;
10
-
11
- /* Estilo para o label do formulário; a propriedade "error" permite alterar a cor se necessário */
12
- export const StyledFormLabel = styled.label<{ error?: boolean }>`
13
- font-size: 0.875rem; /* text-sm */
14
- font-weight: 500; /* font-medium */
15
- line-height: 1; /* leading-none */
16
- color: ${(props) => (props.error ? "#dc2626" : "inherit")};
17
- `;
18
-
19
- /* Estilo para o container de controle de formulário (por exemplo, input) */
20
- export const StyledFormControl = styled.div`
21
- /* Adicione aqui quaisquer estilos específicos para o container do input, se necessário */
22
- `;
23
-
24
- /* Estilo para a descrição do formulário */
25
- export const StyledFormDescription = styled.p`
26
- font-size: 0.875rem; /* text-sm */
27
- color: #6b7280; /* text-muted-foreground */
28
- `;
29
-
30
- /* Estilo para a mensagem (geralmente de erro) */
31
- export const StyledFormMessage = styled.p`
32
- font-size: 0.875rem; /* text-sm */
33
- font-weight: 500; /* font-medium */
34
- color: #dc2626; /* text-destructive */
35
- `;
1
+ // Form.styled.tsx
2
+ import styled from 'styled-components';
3
+
4
+ /* Container para cada item do formulário */
5
+ export const StyledFormItem = styled.div`
6
+ display: flex;
7
+ flex-direction: column;
8
+ gap: 0.5rem; /* Aproximadamente o "space-y-2" do Tailwind */
9
+ `;
10
+
11
+ /* Estilo para o label do formulário; a propriedade "error" permite alterar a cor se necessário */
12
+ export const StyledFormLabel = styled.label<{ error?: boolean }>`
13
+ font-size: 0.875rem; /* text-sm */
14
+ font-weight: 500; /* font-medium */
15
+ line-height: 1; /* leading-none */
16
+ color: ${(props) => (props.error ? '#dc2626' : 'inherit')};
17
+ `;
18
+
19
+ /* Estilo para o container de controle de formulário (por exemplo, input) */
20
+ export const StyledFormControl = styled.div`
21
+ /* Adicione aqui quaisquer estilos específicos para o container do input, se necessário */
22
+ `;
23
+
24
+ /* Estilo para a descrição do formulário */
25
+ export const StyledFormDescription = styled.p`
26
+ font-size: 0.875rem; /* text-sm */
27
+ color: #6b7280; /* text-muted-foreground */
28
+ `;
29
+
30
+ /* Estilo para a mensagem (geralmente de erro) */
31
+ export const StyledFormMessage = styled.p`
32
+ font-size: 0.875rem; /* text-sm */
33
+ font-weight: 500; /* font-medium */
34
+ color: #dc2626; /* text-destructive */
35
+ `;
@@ -1,160 +1,160 @@
1
- /* eslint-disable react-refresh/only-export-components */
2
- // Form.tsx
3
- import * as React from "react";
4
- import { Slot } from "@radix-ui/react-slot";
5
- import {
6
- Controller,
7
- ControllerProps,
8
- FieldPath,
9
- FieldValues,
10
- FormProvider,
11
- useFormContext,
12
- } from "react-hook-form";
13
- import {
14
- StyledFormItem,
15
- StyledFormLabel,
16
- StyledFormDescription,
17
- StyledFormMessage,
18
- } from "./Form.styles";
19
-
20
- /* Reexporta o FormProvider como Form para facilitar o uso */
21
- const Form = FormProvider;
22
-
23
- type FormFieldContextValue<
24
- TFieldValues extends FieldValues = FieldValues,
25
- TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>
26
- > = {
27
- name: TName;
28
- };
29
-
30
- const FormFieldContext = React.createContext<FormFieldContextValue>(
31
- {} as FormFieldContextValue
32
- );
33
-
34
- const FormField = <
35
- TFieldValues extends FieldValues = FieldValues,
36
- TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>
37
- >({
38
- ...props
39
- }: ControllerProps<TFieldValues, TName>) => {
40
- return (
41
- <FormFieldContext.Provider value={{ name: props.name }}>
42
- <Controller {...props} />
43
- </FormFieldContext.Provider>
44
- );
45
- };
46
-
47
- type FormItemContextValue = { id: string };
48
-
49
- const FormItemContext = React.createContext<FormItemContextValue>(
50
- {} as FormItemContextValue
51
- );
52
-
53
- const FormItem = React.forwardRef<
54
- HTMLDivElement,
55
- React.HTMLAttributes<HTMLDivElement>
56
- >(({ ...props }, ref) => {
57
- const id = React.useId();
58
- return (
59
- <FormItemContext.Provider value={{ id }}>
60
- <StyledFormItem ref={ref} {...props} />
61
- </FormItemContext.Provider>
62
- );
63
- });
64
- FormItem.displayName = "FormItem";
65
-
66
- const useFormField = () => {
67
- const fieldContext = React.useContext(FormFieldContext);
68
- const itemContext = React.useContext(FormItemContext);
69
- const { getFieldState, formState } = useFormContext();
70
-
71
- const fieldState = getFieldState(fieldContext.name, formState);
72
-
73
- if (!fieldContext) {
74
- throw new Error("useFormField should be used within <FormField>");
75
- }
76
-
77
- const { id } = itemContext;
78
- return {
79
- id,
80
- name: fieldContext.name,
81
- formItemId: `${id}-form-item`,
82
- formDescriptionId: `${id}-form-item-description`,
83
- formMessageId: `${id}-form-item-message`,
84
- ...fieldState,
85
- };
86
- };
87
-
88
- const FormLabel = React.forwardRef<
89
- HTMLLabelElement,
90
- React.ComponentPropsWithoutRef<"label">
91
- >(({ children, ...props }, ref) => {
92
- const { error, formItemId } = useFormField();
93
- return (
94
- <StyledFormLabel ref={ref} htmlFor={formItemId} error={!!error} {...props}>
95
- {children}
96
- </StyledFormLabel>
97
- );
98
- });
99
- FormLabel.displayName = "FormLabel";
100
-
101
- const FormControl = React.forwardRef<
102
- React.ElementRef<typeof Slot>,
103
- React.ComponentPropsWithoutRef<typeof Slot>
104
- >(({ ...props }, ref) => {
105
- const { error, formItemId, formDescriptionId, formMessageId } =
106
- useFormField();
107
- return (
108
- <Slot
109
- ref={ref}
110
- id={formItemId}
111
- aria-describedby={
112
- !error
113
- ? `${formDescriptionId}`
114
- : `${formDescriptionId} ${formMessageId}`
115
- }
116
- aria-invalid={!!error}
117
- {...props}
118
- />
119
- );
120
- });
121
- FormControl.displayName = "FormControl";
122
-
123
- const FormDescription = React.forwardRef<
124
- HTMLParagraphElement,
125
- React.HTMLAttributes<HTMLParagraphElement>
126
- >(({ children, ...props }, ref) => {
127
- const { formDescriptionId } = useFormField();
128
- return (
129
- <StyledFormDescription ref={ref} id={formDescriptionId} {...props}>
130
- {children}
131
- </StyledFormDescription>
132
- );
133
- });
134
- FormDescription.displayName = "FormDescription";
135
-
136
- const FormMessage = React.forwardRef<
137
- HTMLParagraphElement,
138
- React.HTMLAttributes<HTMLParagraphElement>
139
- >(({ children, ...props }, ref) => {
140
- const { error, formMessageId } = useFormField();
141
- const body = error ? String(error?.message) : children;
142
- if (!body) return null;
143
- return (
144
- <StyledFormMessage ref={ref} id={formMessageId} {...props}>
145
- {body}
146
- </StyledFormMessage>
147
- );
148
- });
149
- FormMessage.displayName = "FormMessage";
150
-
151
- export {
152
- useFormField,
153
- Form,
154
- FormItem,
155
- FormLabel,
156
- FormControl,
157
- FormDescription,
158
- FormMessage,
159
- FormField,
160
- };
1
+ /* eslint-disable react-refresh/only-export-components */
2
+ // Form.tsx
3
+ import * as React from 'react';
4
+ import { Slot } from '@radix-ui/react-slot';
5
+ import {
6
+ Controller,
7
+ ControllerProps,
8
+ FieldPath,
9
+ FieldValues,
10
+ FormProvider,
11
+ useFormContext,
12
+ } from 'react-hook-form';
13
+ import {
14
+ StyledFormItem,
15
+ StyledFormLabel,
16
+ StyledFormDescription,
17
+ StyledFormMessage,
18
+ } from './Form.styles';
19
+
20
+ /* Reexporta o FormProvider como Form para facilitar o uso */
21
+ const Form = FormProvider;
22
+
23
+ type FormFieldContextValue<
24
+ TFieldValues extends FieldValues = FieldValues,
25
+ TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
26
+ > = {
27
+ name: TName;
28
+ };
29
+
30
+ const FormFieldContext = React.createContext<FormFieldContextValue>(
31
+ {} as FormFieldContextValue
32
+ );
33
+
34
+ const FormField = <
35
+ TFieldValues extends FieldValues = FieldValues,
36
+ TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
37
+ >({
38
+ ...props
39
+ }: ControllerProps<TFieldValues, TName>) => {
40
+ return (
41
+ <FormFieldContext.Provider value={{ name: props.name }}>
42
+ <Controller {...props} />
43
+ </FormFieldContext.Provider>
44
+ );
45
+ };
46
+
47
+ type FormItemContextValue = { id: string };
48
+
49
+ const FormItemContext = React.createContext<FormItemContextValue>(
50
+ {} as FormItemContextValue
51
+ );
52
+
53
+ const FormItem = React.forwardRef<
54
+ HTMLDivElement,
55
+ React.HTMLAttributes<HTMLDivElement>
56
+ >(({ ...props }, ref) => {
57
+ const id = React.useId();
58
+ return (
59
+ <FormItemContext.Provider value={{ id }}>
60
+ <StyledFormItem ref={ref} {...props} />
61
+ </FormItemContext.Provider>
62
+ );
63
+ });
64
+ FormItem.displayName = 'FormItem';
65
+
66
+ const useFormField = () => {
67
+ const fieldContext = React.useContext(FormFieldContext);
68
+ const itemContext = React.useContext(FormItemContext);
69
+ const { getFieldState, formState } = useFormContext();
70
+
71
+ const fieldState = getFieldState(fieldContext.name, formState);
72
+
73
+ if (!fieldContext) {
74
+ throw new Error('useFormField should be used within <FormField>');
75
+ }
76
+
77
+ const { id } = itemContext;
78
+ return {
79
+ id,
80
+ name: fieldContext.name,
81
+ formItemId: `${id}-form-item`,
82
+ formDescriptionId: `${id}-form-item-description`,
83
+ formMessageId: `${id}-form-item-message`,
84
+ ...fieldState,
85
+ };
86
+ };
87
+
88
+ const FormLabel = React.forwardRef<
89
+ HTMLLabelElement,
90
+ React.ComponentPropsWithoutRef<'label'>
91
+ >(({ children, ...props }, ref) => {
92
+ const { error, formItemId } = useFormField();
93
+ return (
94
+ <StyledFormLabel ref={ref} htmlFor={formItemId} error={!!error} {...props}>
95
+ {children}
96
+ </StyledFormLabel>
97
+ );
98
+ });
99
+ FormLabel.displayName = 'FormLabel';
100
+
101
+ const FormControl = React.forwardRef<
102
+ React.ElementRef<typeof Slot>,
103
+ React.ComponentPropsWithoutRef<typeof Slot>
104
+ >(({ ...props }, ref) => {
105
+ const { error, formItemId, formDescriptionId, formMessageId } =
106
+ useFormField();
107
+ return (
108
+ <Slot
109
+ ref={ref}
110
+ id={formItemId}
111
+ aria-describedby={
112
+ !error
113
+ ? `${formDescriptionId}`
114
+ : `${formDescriptionId} ${formMessageId}`
115
+ }
116
+ aria-invalid={!!error}
117
+ {...props}
118
+ />
119
+ );
120
+ });
121
+ FormControl.displayName = 'FormControl';
122
+
123
+ const FormDescription = React.forwardRef<
124
+ HTMLParagraphElement,
125
+ React.HTMLAttributes<HTMLParagraphElement>
126
+ >(({ children, ...props }, ref) => {
127
+ const { formDescriptionId } = useFormField();
128
+ return (
129
+ <StyledFormDescription ref={ref} id={formDescriptionId} {...props}>
130
+ {children}
131
+ </StyledFormDescription>
132
+ );
133
+ });
134
+ FormDescription.displayName = 'FormDescription';
135
+
136
+ const FormMessage = React.forwardRef<
137
+ HTMLParagraphElement,
138
+ React.HTMLAttributes<HTMLParagraphElement>
139
+ >(({ children, ...props }, ref) => {
140
+ const { error, formMessageId } = useFormField();
141
+ const body = error ? String(error?.message) : children;
142
+ if (!body) return null;
143
+ return (
144
+ <StyledFormMessage ref={ref} id={formMessageId} {...props}>
145
+ {body}
146
+ </StyledFormMessage>
147
+ );
148
+ });
149
+ FormMessage.displayName = 'FormMessage';
150
+
151
+ export {
152
+ useFormField,
153
+ Form,
154
+ FormItem,
155
+ FormLabel,
156
+ FormControl,
157
+ FormDescription,
158
+ FormMessage,
159
+ FormField,
160
+ };