@foi/design-system 0.0.15 → 0.0.17

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/README.md CHANGED
@@ -42,20 +42,21 @@ npm publish --access public
42
42
 
43
43
  ### Atoms
44
44
 
45
- | Component | Description |
46
- | ------------ | ------------------------------------------------------------------- |
47
- | `Button` | Primary action button with variant/size/color support |
48
- | `Checkbox` | Single checkbox — standalone, RHF, or inside a group |
49
- | `DatePicker` | Date input with calendar menu, integrates with RHF |
50
- | `Icon` | Font-based icon using Material Symbols Rounded — pass a `name` prop |
51
- | `IconButton` | Clickable icon with button semantics |
52
- | `Input` | Text input field with label, helper text, and error state |
53
- | `Pagination` | Page navigation bar with first/prev/next/last buttons and optional rows-per-page selector |
54
- | `Radio` | Single radio button — used inside `RadioGroup` |
55
- | `Select` | Dropdown select with RHF integration |
56
- | `Skeleton` | Animated placeholder shown while content is loading — rectangular or circular |
57
- | `Slider` | Range slider with RHF integration |
58
- | `Switch` | Toggle switch — boolean RHF field |
45
+ | Component | Description |
46
+ | ------------- | ------------------------------------------------------------------------------------------ |
47
+ | `Button` | Primary action button with variant/size/color support |
48
+ | `Checkbox` | Single checkbox — standalone, RHF, or inside a group |
49
+ | `DatePicker` | Date input with calendar menu, integrates with RHF |
50
+ | `Icon` | Font-based icon using Material Symbols Rounded — pass a `name` prop |
51
+ | `IconButton` | Clickable icon with button semantics |
52
+ | `NumberField` | Numeric input with increment/decrement buttons, min/max/step support, and two layout modes |
53
+ | `Pagination` | Page navigation bar with first/prev/next/last buttons and optional rows-per-page selector |
54
+ | `Radio` | Single radio button — used inside `RadioGroup` |
55
+ | `Select` | Dropdown select with RHF integration |
56
+ | `Skeleton` | Animated placeholder shown while content is loading — rectangular or circular |
57
+ | `Slider` | Range slider with RHF integration |
58
+ | `Switch` | Toggle switch — boolean RHF field |
59
+ | `TextField` | Text input (text, password, email) with label, helper text, and error state |
59
60
 
60
61
  ### Molecules
61
62
 
@@ -80,12 +81,13 @@ All field components share the same integration pattern. Define a Zod schema, pa
80
81
  import { useForm } from 'react-hook-form';
81
82
  import { zodResolver } from '@hookform/resolvers/zod';
82
83
  import { z } from 'zod';
83
- import Input from '@components/atoms/Input';
84
+ import TextField from '@components/atoms/TextField';
85
+ import NumberField from '@components/atoms/NumberField';
84
86
  import Button from '@components/atoms/Button';
85
87
 
86
88
  const schema = z.object({
87
89
  email: z.string().email('Invalid email'),
88
- age: z.number().min(18, 'Must be 18 or older'),
90
+ age: z.number({ message: 'Required' }).min(18, 'Must be 18 or older'),
89
91
  });
90
92
 
91
93
  type FormValues = z.infer<typeof schema>;
@@ -97,8 +99,8 @@ const MyForm = () => {
97
99
 
98
100
  return (
99
101
  <form onSubmit={handleSubmit(console.log)}>
100
- <Input name='email' control={control} label='Email' />
101
- <Input name='age' control={control} label='Age' type='number' />
102
+ <TextField name='email' control={control} label='Email' />
103
+ <NumberField name='age' control={control} label='Age' min={18} />
102
104
  <Button type='submit' label='Submit' />
103
105
  </form>
104
106
  );
@@ -131,6 +133,103 @@ const [agreed, setAgreed] = useState(false);
131
133
  <Checkbox checked={agreed} onChecked={setAgreed} label='I agree to the terms' />;
132
134
  ```
133
135
 
136
+ ## TextField
137
+
138
+ A text input field with a floating label, helper text, and full error state integration. Only accepts `text`, `password`, and `email` as input types. For numeric input use `NumberField`.
139
+
140
+ ### Props
141
+
142
+ | Prop | Type | Default | Description |
143
+ | --------------- | ----------------------------------------- | ---------- | ---------------------------------------------------- |
144
+ | `name` | `string` | — | Field name, used by RHF |
145
+ | `label` | `string` | — | Floating label text |
146
+ | `control` | `Control` | — | RHF control object; omit for uncontrolled mode |
147
+ | `value` | `string` | — | Value in uncontrolled mode |
148
+ | `onValueChange` | `(value: string) => void` | — | Change handler in uncontrolled mode |
149
+ | `type` | `'text' \| 'password' \| 'email'` | `'text'` | HTML input type |
150
+ | `width` | `'small' \| 'medium' \| 'large' \| 'full'` | — | Preset width |
151
+ | `helperText` | `string` | — | Hint text shown below the field when there is no error |
152
+ | `showErrorText` | `boolean` | `true` | Show the validation error message below the field |
153
+ | `hasPadding` | `boolean` | `false` | Add bottom padding to reserve space for helper/error text |
154
+ | `startAdornment`| `JSX.Element` | — | Element rendered to the left of the input |
155
+ | `endAdornment` | `JSX.Element` | — | Element rendered to the right of the input |
156
+ | `regex` | `RegExp` | — | Block keystrokes that don't match the pattern |
157
+ | `format` | `(value: string) => string` | — | Transform the value before it is stored |
158
+ | `disabled` | `boolean` | `false` | Disable the field |
159
+ | `theme` | `EVENTS` | — | One-off token override for this instance |
160
+ | `variant` | `string` | `'default'`| Theme variant name |
161
+
162
+ ### Example
163
+
164
+ ```tsx
165
+ import TextField from '@components/atoms/TextField';
166
+ import Icon from '@components/atoms/Icon';
167
+
168
+ <TextField
169
+ name='email'
170
+ control={control}
171
+ label='Email'
172
+ type='email'
173
+ startAdornment={<Icon name='mail' />}
174
+ helperText='We will never share your email'
175
+ />
176
+ ```
177
+
178
+ ## NumberField
179
+
180
+ A numeric input that stores a `number` in RHF (or `undefined` when empty). The field always renders increment/decrement buttons; their position depends on the `display` prop.
181
+
182
+ ### Props
183
+
184
+ All `TextField` props apply except `type`, `endAdornment`, and `startAdornment` (in `spinner` mode). The following props are specific to `NumberField`:
185
+
186
+ | Prop | Type | Default | Description |
187
+ | --------- | ----------------------------- | ------------ | ------------------------------------------------------------------------ |
188
+ | `min` | `number` | — | Minimum allowed value; decrement button disables at this bound |
189
+ | `max` | `number` | — | Maximum allowed value; increment button disables at this bound |
190
+ | `step` | `number` | `1` | Amount added or subtracted on each button click |
191
+ | `display` | `'standard' \| 'spinner'` | `'standard'` | `standard`: both buttons on the right; `spinner`: remove left, input centre, add right |
192
+
193
+ ### Display modes
194
+
195
+ **`standard`** (default) — both buttons grouped on the right:
196
+
197
+ ```
198
+ [startAdornment?] [ input ] [− +]
199
+ ```
200
+
201
+ **`spinner`** — decrement on the left, input centred, increment on the right:
202
+
203
+ ```
204
+ [−] [ input ] [+]
205
+ ```
206
+
207
+ ### Example
208
+
209
+ ```tsx
210
+ import NumberField from '@components/atoms/NumberField';
211
+
212
+ // Standard — quantity picker with bounds
213
+ <NumberField
214
+ name='quantity'
215
+ control={control}
216
+ label='Quantity'
217
+ min={1}
218
+ max={99}
219
+ step={1}
220
+ />
221
+
222
+ // Spinner layout
223
+ <NumberField
224
+ name='quantity'
225
+ control={control}
226
+ label='Quantity'
227
+ display='spinner'
228
+ min={0}
229
+ max={100}
230
+ />
231
+ ```
232
+
134
233
  ## Theming
135
234
 
136
235
  Wrap your app in `ThemeProvider` and pass one or more named themes. The active theme is selected by the `theme` prop and its tokens are injected as CSS custom properties that every component consumes.
@@ -230,7 +329,7 @@ interface Product { id: number; name: string; price: number; }
230
329
  const columns: DataGridColumn<Product>[] = [
231
330
  {
232
331
  key: 'name',
233
- label: 'Product',
332
+ label: 'Product', // string → wrapped in the themed --DATAGRID-thLabel span
234
333
  type: 'text',
235
334
  filter: { type: 'search' },
236
335
  },
@@ -243,6 +342,23 @@ const columns: DataGridColumn<Product>[] = [
243
342
  ];
244
343
  ```
245
344
 
345
+ `label` accepts any `ReactNode`. A plain string is automatically wrapped in the themed `--DATAGRID-thLabel` span so it inherits the header typography. Pass a custom node to render icons, badges, or anything else without that wrapper:
346
+
347
+ ```tsx
348
+ import Icon from '@components/atoms/Icon';
349
+
350
+ {
351
+ key: 'price',
352
+ label: (
353
+ <span style={{ display: 'flex', alignItems: 'center', gap: '6px' }}>
354
+ <Icon name='payments' size='sm' />
355
+ Price
356
+ </span>
357
+ ),
358
+ type: 'number',
359
+ }
360
+ ```
361
+
246
362
  ### The `onFetch` contract
247
363
 
248
364
  `onFetch` receives `{ page, pageSize, sort?, filters? }` and must return `{ data, total }`. It is called automatically whenever the page, sort, or any filter changes.
@@ -0,0 +1,456 @@
1
+ import { i as e, n as t, r as n } from "./emotion-react-jsx-runtime.browser.esm-Ch-DwUYg.js";
2
+ import { r } from "./theme-D01EcUA9.js";
3
+ import { a as i, i as a, n as o, o as s, r as c, s as l, t as u } from "./RadioGroup.context-Bu218uUX.js";
4
+ import d, { useEffect as f, useMemo as p, useRef as m } from "react";
5
+ import { css as h } from "@emotion/react";
6
+ import { useController as g } from "react-hook-form";
7
+ import { createPortal as _ } from "react-dom";
8
+ //#region src/components/molecules/CheckboxGroup/CheckboxGroup.emotion.ts
9
+ var v = (e, t) => `
10
+ .--CHECKBOXGROUP-label {
11
+ ${r(e, "color", `--CHECKBOXGROUP-EVENTS-${t}-COLOR-PRIMARY`)}
12
+ }
13
+
14
+ .--CHECKBOXGROUP-helperText {
15
+ ${r(e, "color", `--CHECKBOXGROUP-EVENTS-${t}-COLOR-SECONDARY`)}
16
+ }
17
+ `, y = (e) => h`
18
+ &.--CHECKBOXGROUP {
19
+ display: flex;
20
+ flex-direction: column;
21
+ gap: 8px;
22
+ width: fit-content;
23
+
24
+ // ENABLED
25
+ ${v(e, "ENABLED")};
26
+
27
+ // ERROR
28
+ &.--CHECKBOXGROUP-error {
29
+ ${v(e, "ERROR")};
30
+ }
31
+
32
+ // DISABLED
33
+ &.--CHECKBOXGROUP-disabled {
34
+ ${v(e, "DISABLED")};
35
+ }
36
+
37
+ .--CHECKBOXGROUP-items {
38
+ display: flex;
39
+ flex-direction: column;
40
+ gap: 16px;
41
+ }
42
+
43
+ &.--CHECKBOXGROUP--horizontal .--CHECKBOXGROUP-items {
44
+ flex-direction: row;
45
+ flex-wrap: wrap;
46
+ }
47
+
48
+ .--CHECKBOXGROUP-label {
49
+ // FONT
50
+ font-family: ${e["--FONTFAMILY-PRIMARY"]};
51
+ font-size: 0.875rem;
52
+ font-weight: 500;
53
+ line-height: 1;
54
+ }
55
+
56
+ .--CHECKBOXGROUP-helperText {
57
+ // FONT
58
+ font-family: ${e["--FONTFAMILY-PRIMARY"]};
59
+ font-size: 13px;
60
+ line-height: 16px;
61
+ margin-left: 14px;
62
+ }
63
+ }
64
+ `, b = "--CHECKBOXGROUP", x = ({ name: e, control: r, children: a, label: o, helperText: s, showErrorText: c = !0, disabled: l, direction: u = "vertical", style: d, className: f }) => {
65
+ let { field: p, fieldState: m } = g({
66
+ control: r,
67
+ name: e
68
+ }), h = Array.isArray(p.value) ? p.value : [], _ = m.error;
69
+ return /* @__PURE__ */ t(i.Provider, {
70
+ value: {
71
+ checkedValues: h,
72
+ onChange: (e, t) => {
73
+ let n = t ? [...h, e] : h.filter((t) => t !== e);
74
+ p.onChange(n), p.onBlur();
75
+ },
76
+ disabled: l,
77
+ error: _
78
+ },
79
+ children: /* @__PURE__ */ n("div", {
80
+ className: [
81
+ b,
82
+ `${b}--${u}`,
83
+ c && _?.message && `${b}-error`,
84
+ l && `${b}-disabled`,
85
+ f || ""
86
+ ].join(" "),
87
+ css: y(d),
88
+ "data-testid": b,
89
+ children: [
90
+ o && /* @__PURE__ */ t("span", {
91
+ className: `${b}-label`,
92
+ "data-testid": `${b}-label`,
93
+ children: o
94
+ }),
95
+ /* @__PURE__ */ t("div", {
96
+ className: `${b}-items`,
97
+ "data-testid": `${b}-items`,
98
+ children: a
99
+ }),
100
+ /* @__PURE__ */ n("span", {
101
+ className: `${b}-helperText`,
102
+ "data-testid": `${b}-helperText`,
103
+ children: [s && (!_ || !c) && s, c && _ && _.message]
104
+ })
105
+ ]
106
+ })
107
+ });
108
+ }, S = ({ theme: n, variant: r = "default", ...i }) => {
109
+ let { componentStyles: a } = e([l.CHECKBOXGROUP], n, r.toUpperCase());
110
+ return /* @__PURE__ */ t(x, {
111
+ ...i,
112
+ style: a
113
+ });
114
+ }, C = (e) => h`
115
+ &.--CHECKBOXTREE {
116
+ display: flex;
117
+ flex-direction: column;
118
+ gap: 8px;
119
+ width: fit-content;
120
+
121
+ .--CHECKBOXTREE-children {
122
+ display: flex;
123
+ flex-direction: column;
124
+ padding-left: 36px;
125
+ gap: 16px;
126
+ }
127
+
128
+ .--CHECKBOXTREE-helperText {
129
+ font-family: ${e["--FONTFAMILY-PRIMARY"]};
130
+ font-size: 13px;
131
+ line-height: 16px;
132
+ margin-left: 14px;
133
+ ${r(e, "color", "--CHECKBOXTREE-EVENTS-ENABLED-COLOR-SECONDARY")}
134
+
135
+ &:empty {
136
+ display: none;
137
+ }
138
+ }
139
+
140
+ &.--CHECKBOXTREE-error {
141
+ .--CHECKBOXTREE-helperText {
142
+ ${r(e, "color", "--CHECKBOXTREE-EVENTS-ERROR-COLOR-SECONDARY")}
143
+ }
144
+ }
145
+
146
+ &.--CHECKBOXTREE-disabled {
147
+ .--CHECKBOXTREE-helperText {
148
+ ${r(e, "color", "--CHECKBOXTREE-EVENTS-DISABLED-COLOR-SECONDARY")}
149
+ }
150
+ }
151
+ }
152
+ `, w = "--CHECKBOXTREE", T = ({ name: e, control: r, children: i, label: o, iconChecked: l = /* @__PURE__ */ t(s, { name: "check" }), iconIndeterminate: u = /* @__PURE__ */ t(s, { name: "remove" }), helperText: h, showErrorText: _ = !0, disabled: v, style: y, className: b }) => {
153
+ let { field: x, fieldState: S } = g({
154
+ control: r,
155
+ name: e
156
+ }), T = Array.isArray(x.value) ? x.value : [], E = S.error, D = p(() => d.Children.toArray(i).map((e) => {
157
+ let t = e;
158
+ return t.props?.value ?? t.props?.name ?? "";
159
+ }).filter(Boolean), [i]), O = D.length > 0 && D.every((e) => T.includes(e)), k = !O && D.some((e) => T.includes(e)), A = m(null);
160
+ return f(() => {
161
+ let e = A.current?.querySelectorAll("input[type=\"checkbox\"]")[0];
162
+ e && (e.indeterminate = k);
163
+ }, [k]), /* @__PURE__ */ n("div", {
164
+ ref: A,
165
+ className: [
166
+ w,
167
+ _ && E?.message ? `${w}-error` : "",
168
+ v ? `${w}-disabled` : "",
169
+ b || ""
170
+ ].join(" "),
171
+ css: C(y),
172
+ "data-testid": w,
173
+ children: [
174
+ /* @__PURE__ */ t(c, {
175
+ checked: O || k,
176
+ onChecked: (e) => {
177
+ let t = e ? [...D] : [];
178
+ x.onChange(t), x.onBlur();
179
+ },
180
+ label: o,
181
+ icon: k ? u : l,
182
+ disabled: v,
183
+ showErrorText: !1,
184
+ helperText: void 0
185
+ }),
186
+ /* @__PURE__ */ t(a.Provider, {
187
+ value: {
188
+ checkedValues: T,
189
+ onChange: (e, t) => {
190
+ let n = t ? [...T, e] : T.filter((t) => t !== e);
191
+ x.onChange(n), x.onBlur();
192
+ },
193
+ disabled: v,
194
+ error: E
195
+ },
196
+ children: /* @__PURE__ */ t("div", {
197
+ className: `${w}-children`,
198
+ "data-testid": `${w}-children`,
199
+ children: i
200
+ })
201
+ }),
202
+ /* @__PURE__ */ n("span", {
203
+ className: `${w}-helperText`,
204
+ "data-testid": `${w}-helperText`,
205
+ children: [h && (!E || !_) && h, _ && E && E.message]
206
+ })
207
+ ]
208
+ });
209
+ }, E = ({ theme: n, variant: r = "default", ...i }) => {
210
+ let { componentStyles: a } = e([l.CHECKBOXTREE], n, r.toUpperCase());
211
+ return /* @__PURE__ */ t(T, {
212
+ ...i,
213
+ style: a
214
+ });
215
+ }, D = (e, t) => `
216
+ // BACKGROUNDS
217
+ ${r(e, "background-color", `--MODAL-${t}-BACKGROUND-COLOR`)}
218
+
219
+ // BORDERS
220
+ ${r(e, "border-color", `--MODAL-${t}-BORDER-COLOR`)}
221
+ ${r(e, "border-width", `--MODAL-${t}-BORDER-WIDTH`)}
222
+ ${r(e, "border-style", `--MODAL-${t}-BORDER-STYLE`)}
223
+ ${r(e, "border-radius", `--MODAL-${t}-BORDER-RADIUS`)}
224
+ `, O = (e) => h`
225
+ &.--MODAL-scrim {
226
+ position: fixed;
227
+ inset: 0;
228
+ background-color: rgba(0, 0, 0, 0.5);
229
+ display: flex;
230
+ align-items: center;
231
+ justify-content: center;
232
+ z-index: 1000;
233
+ }
234
+
235
+ .--MODAL {
236
+ display: flex;
237
+ flex-direction: column;
238
+ width: 480px;
239
+ max-width: calc(100vw - 48px);
240
+ max-height: calc(100vh - 64px);
241
+ overflow: hidden;
242
+ box-shadow:
243
+ rgba(0, 0, 0, 0.2) 0px 5px 5px -3px,
244
+ rgba(0, 0, 0, 0.14) 0px 8px 10px 1px,
245
+ rgba(0, 0, 0, 0.12) 0px 3px 14px 2px;
246
+
247
+ ${D(e, "ROOT")}
248
+
249
+ &.--MODAL-lg {
250
+ width: 720px;
251
+ }
252
+
253
+ .--MODAL-header {
254
+ display: flex;
255
+ align-items: center;
256
+ gap: 8px;
257
+ padding: 16px 20px;
258
+ flex-shrink: 0;
259
+ }
260
+
261
+ .--MODAL-title {
262
+ flex: 1;
263
+ margin: 0;
264
+
265
+ ${r(e, "color", "--MODAL-EVENTS-ENABLED-COLOR-PRIMARY")};
266
+
267
+ font-family: ${e["--FONTFAMILY-PRIMARY"]};
268
+ font-size: 1rem;
269
+ font-weight: 600;
270
+ line-height: 1.25;
271
+ }
272
+
273
+ .--MODAL-body {
274
+ flex: 1;
275
+ padding: 20px;
276
+ overflow-y: auto;
277
+
278
+ ${r(e, "color", "--MODAL-EVENTS-ENABLED-COLOR-SECONDARY")};
279
+
280
+ font-family: ${e["--FONTFAMILY-PRIMARY"]};
281
+ font-size: 0.875rem;
282
+ line-height: 1.5;
283
+ }
284
+
285
+ .--MODAL-footer {
286
+ display: flex;
287
+ justify-content: flex-end;
288
+ gap: 8px;
289
+ padding: 16px 20px;
290
+ flex-shrink: 0;
291
+ }
292
+ }
293
+ `, k = "--MODAL", A = ({ open: e, onClose: r, header: i, showCloseButton: a = !0, size: c = "md", children: l, footer: u, staticBackdrop: d = !1, className: p, style: m }) => (f(() => {
294
+ if (!e || d) return;
295
+ let t = (e) => {
296
+ e.key === "Escape" && r();
297
+ };
298
+ return document.addEventListener("keydown", t), () => document.removeEventListener("keydown", t);
299
+ }, [
300
+ e,
301
+ r,
302
+ d
303
+ ]), e ? _(/* @__PURE__ */ t("div", {
304
+ className: `${k}-scrim`,
305
+ css: O(m),
306
+ role: "dialog",
307
+ "aria-modal": "true",
308
+ onClick: (e) => {
309
+ !d && e.target === e.currentTarget && r();
310
+ },
311
+ children: /* @__PURE__ */ n("div", {
312
+ className: [
313
+ k,
314
+ c === "lg" ? `${k}-lg` : "",
315
+ p || ""
316
+ ].filter(Boolean).join(" "),
317
+ children: [
318
+ (i !== void 0 || a) && /* @__PURE__ */ n("header", {
319
+ className: `${k}-header`,
320
+ children: [i, a && /* @__PURE__ */ t(o, {
321
+ icon: /* @__PURE__ */ t(s, { name: "close" }),
322
+ onClick: r,
323
+ "aria-label": "Cerrar modal"
324
+ })]
325
+ }),
326
+ l !== void 0 && /* @__PURE__ */ t("div", {
327
+ className: `${k}-body`,
328
+ children: l
329
+ }),
330
+ u && /* @__PURE__ */ t("footer", {
331
+ className: `${k}-footer`,
332
+ children: u
333
+ })
334
+ ]
335
+ })
336
+ }), document.body) : null);
337
+ A.displayName = "Modal";
338
+ //#endregion
339
+ //#region src/components/molecules/Modal/index.tsx
340
+ var j = ({ theme: n, variant: r = "default", ...i }) => {
341
+ let { componentStyles: a } = e([l.MODAL], n, r.toUpperCase());
342
+ return /* @__PURE__ */ t(A, {
343
+ ...i,
344
+ style: a
345
+ });
346
+ }, M = (e, t) => `
347
+ .--RADIOGROUP-label {
348
+ ${r(e, "color", `--RADIOGROUP-EVENTS-${t}-COLOR-PRIMARY`)}
349
+ }
350
+
351
+ .--RADIOGROUP-helperText {
352
+ ${r(e, "color", `--RADIOGROUP-EVENTS-${t}-COLOR-SECONDARY`)}
353
+ }
354
+ `, N = (e) => h`
355
+ &.--RADIOGROUP {
356
+ display: flex;
357
+ flex-direction: column;
358
+ gap: 8px;
359
+ width: fit-content;
360
+
361
+ // ENABLED
362
+ ${M(e, "ENABLED")};
363
+
364
+ // ERROR
365
+ &.--RADIOGROUP-error {
366
+ ${M(e, "ERROR")};
367
+ }
368
+
369
+ // DISABLED
370
+ &.--RADIOGROUP-disabled {
371
+ ${M(e, "DISABLED")};
372
+ }
373
+
374
+ .--RADIOGROUP-items {
375
+ display: flex;
376
+ flex-direction: column;
377
+ gap: 16px;
378
+ }
379
+
380
+ &.--RADIOGROUP--horizontal .--RADIOGROUP-items {
381
+ flex-direction: row;
382
+ flex-wrap: wrap;
383
+ }
384
+
385
+ .--RADIOGROUP-label {
386
+ // FONT
387
+ font-family: ${e["--FONTFAMILY-PRIMARY"]};
388
+ font-size: 0.875rem;
389
+ font-weight: 500;
390
+ line-height: 1;
391
+ }
392
+
393
+ .--RADIOGROUP-helperText {
394
+ // FONT
395
+ font-family: ${e["--FONTFAMILY-PRIMARY"]};
396
+ font-size: 13px;
397
+ line-height: 16px;
398
+ margin-left: 14px;
399
+ }
400
+ }
401
+ `, P = "--RADIOGROUP", F = ({ name: e, control: r, children: i, label: a, helperText: o, showErrorText: s = !0, disabled: c, direction: l = "vertical", style: f, className: p }) => {
402
+ let { field: m, fieldState: h } = g({
403
+ control: r,
404
+ name: e
405
+ }), _ = typeof m.value == "string" ? m.value : "", v = h.error, y = (e) => {
406
+ m.onChange(e), m.onBlur();
407
+ }, b = d.Children.toArray(i).find((e) => d.isValidElement(e) && !e.props.disabled)?.props.value ?? "";
408
+ return /* @__PURE__ */ t(u.Provider, {
409
+ value: {
410
+ name: e,
411
+ selectedValue: _,
412
+ onChange: y,
413
+ disabled: c,
414
+ error: v,
415
+ firstValue: b
416
+ },
417
+ children: /* @__PURE__ */ n("div", {
418
+ className: [
419
+ P,
420
+ `${P}--${l}`,
421
+ s && v?.message && `${P}-error`,
422
+ c && `${P}-disabled`,
423
+ p || ""
424
+ ].join(" "),
425
+ css: N(f),
426
+ "data-testid": P,
427
+ children: [
428
+ a && /* @__PURE__ */ t("span", {
429
+ className: `${P}-label`,
430
+ "data-testid": `${P}-label`,
431
+ children: a
432
+ }),
433
+ /* @__PURE__ */ t("div", {
434
+ className: `${P}-items`,
435
+ "data-testid": `${P}-items`,
436
+ children: i
437
+ }),
438
+ /* @__PURE__ */ n("span", {
439
+ className: `${P}-helperText`,
440
+ "data-testid": `${P}-helperText`,
441
+ children: [o && (!v || !s) && o, s && v && v.message]
442
+ })
443
+ ]
444
+ })
445
+ });
446
+ }, I = ({ theme: n, variant: r = "default", ...i }) => {
447
+ let { componentStyles: a } = e([l.RADIOGROUP], n, r.toUpperCase());
448
+ return /* @__PURE__ */ t(F, {
449
+ ...i,
450
+ style: a
451
+ });
452
+ };
453
+ //#endregion
454
+ export { S as i, j as n, E as r, I as t };
455
+
456
+ //# sourceMappingURL=RadioGroup-DzEJw4WJ.js.map