@ttoss/forms 0.14.27 → 0.14.29

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/dist/esm/index.js CHANGED
@@ -39,7 +39,8 @@ import { HelpText } from "@ttoss/ui";
39
39
  import { ErrorMessage as HookFormErrorMessage } from "@hookform/error-message";
40
40
  import { jsx as jsx2 } from "react/jsx-runtime";
41
41
  var ErrorMessage = ({
42
- name
42
+ name,
43
+ disabled
43
44
  }) => {
44
45
  const {
45
46
  formState: {
@@ -50,7 +51,8 @@ var ErrorMessage = ({
50
51
  errors,
51
52
  name,
52
53
  as: /* @__PURE__ */jsx2(HelpText, {
53
- negative: true
54
+ negative: true,
55
+ disabled
54
56
  })
55
57
  });
56
58
  };
@@ -139,15 +141,14 @@ var FormFieldCheckbox = ({
139
141
  };
140
142
 
141
143
  // src/FormFieldInput.tsx
142
- import { Box as Box4, Icon, Input, Label as Label3, Text } from "@ttoss/ui";
144
+ import { Box as Box4, Input, Label as Label3 } from "@ttoss/ui";
143
145
  import { useController as useController3 } from "react-hook-form";
144
- import React3 from "react";
145
146
  import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
146
147
  var FormFieldInput = ({
147
148
  label,
148
149
  name,
149
- tooltipIcon,
150
- showCharacterCounter,
150
+ tooltip,
151
+ onTooltipClick,
151
152
  ...inputProps
152
153
  }) => {
153
154
  const {
@@ -164,42 +165,15 @@ var FormFieldInput = ({
164
165
  name,
165
166
  defaultValue: ""
166
167
  });
167
- const characterCounter = React3.useMemo(() => {
168
- if (!value) {
169
- return 0;
170
- }
171
- return String(value).length;
172
- }, [value]);
173
168
  const id = `form-field-input-${name}`;
174
169
  const hasError = !!errors[name]?.message;
175
170
  return /* @__PURE__ */jsxs3(Box4, {
176
- children: [label && /* @__PURE__ */jsxs3(Label3, {
177
- sx: {
178
- display: "flex",
179
- alignItems: "center"
180
- },
171
+ children: [label && /* @__PURE__ */jsx5(Label3, {
181
172
  "aria-disabled": inputProps.disabled,
182
173
  htmlFor: id,
183
- children: [label, tooltipIcon && /* @__PURE__ */jsx5(Text, {
184
- sx: {
185
- marginLeft: "md",
186
- fontSize: "xs",
187
- lineHeight: 0
188
- },
189
- variant: "tooltip-icon",
190
- children: /* @__PURE__ */jsx5(Icon, {
191
- icon: tooltipIcon
192
- })
193
- }), showCharacterCounter && /* @__PURE__ */jsx5(Text, {
194
- sx: {
195
- marginLeft: "auto",
196
- fontSize: "xs",
197
- lineHeight: 0,
198
- color: "underemphasize"
199
- },
200
- variant: "character-counter",
201
- children: characterCounter
202
- })]
174
+ tooltip,
175
+ onTooltipClick,
176
+ children: label
203
177
  }), /* @__PURE__ */jsx5(Input, {
204
178
  ref,
205
179
  onChange,
@@ -331,4 +305,101 @@ var FormFieldTextarea = ({
331
305
  }
332
306
  });
333
307
  };
334
- export { Form, FormField, FormFieldCheckbox, FormFieldInput, FormFieldRadio, FormFieldSelect, FormFieldTextarea, yup, yupResolver };
308
+
309
+ // src/FormGroup.tsx
310
+ import { Flex as Flex2 } from "@ttoss/ui";
311
+ import React3 from "react";
312
+ import { jsx as jsx9 } from "react/jsx-runtime";
313
+ var FormGroupLevelsManagerContext = /*#__PURE__*/React3.createContext({
314
+ registerChild: () => {
315
+ return null;
316
+ }
317
+ });
318
+ var FormGroupLevelsManager = ({
319
+ children
320
+ }) => {
321
+ const [levelsLength, setLevelsLength] = React3.useState(0);
322
+ const registerChild = React3.useCallback(level => {
323
+ if (level + 1 > levelsLength) {
324
+ setLevelsLength(level + 1);
325
+ }
326
+ }, [levelsLength]);
327
+ return /* @__PURE__ */jsx9(FormGroupLevelsManagerContext.Provider, {
328
+ value: {
329
+ levelsLength,
330
+ registerChild
331
+ },
332
+ children
333
+ });
334
+ };
335
+ var FormGroupContext = /*#__PURE__*/React3.createContext({});
336
+ var useFormGroup = () => {
337
+ const {
338
+ parentLevel
339
+ } = React3.useContext(FormGroupContext);
340
+ const {
341
+ levelsLength
342
+ } = React3.useContext(FormGroupLevelsManagerContext);
343
+ return {
344
+ level: parentLevel,
345
+ levelsLength
346
+ };
347
+ };
348
+ var FormGroupWrapper = ({
349
+ children
350
+ }) => {
351
+ const {
352
+ level,
353
+ levelsLength
354
+ } = useFormGroup();
355
+ const {
356
+ registerChild
357
+ } = React3.useContext(FormGroupLevelsManagerContext);
358
+ React3.useEffect(() => {
359
+ if (typeof level === "number") {
360
+ registerChild(level);
361
+ }
362
+ }, [level, registerChild]);
363
+ const sx = React3.useMemo(() => {
364
+ return {
365
+ flexDirection: "column",
366
+ width: "100%",
367
+ gap: "md",
368
+ paddingLeft: ({
369
+ space
370
+ }) => {
371
+ if (!level || !levelsLength) {
372
+ return 0;
373
+ }
374
+ const value = levelsLength / level;
375
+ return `calc(${space["lg"]} / ${value})`;
376
+ }
377
+ };
378
+ }, [level, levelsLength]);
379
+ return /* @__PURE__ */jsx9(Flex2, {
380
+ "aria-level": level,
381
+ sx,
382
+ children
383
+ });
384
+ };
385
+ var FormGroup = ({
386
+ children
387
+ }) => {
388
+ const {
389
+ level
390
+ } = useFormGroup();
391
+ const currentLevel = level === void 0 ? 0 : level + 1;
392
+ return /* @__PURE__ */jsx9(FormGroupContext.Provider, {
393
+ value: {
394
+ parentLevel: currentLevel
395
+ },
396
+ children: currentLevel === 0 ? /* @__PURE__ */jsx9(FormGroupLevelsManager, {
397
+ children: /* @__PURE__ */jsx9(FormGroupWrapper, {
398
+ children
399
+ })
400
+ }) : /* @__PURE__ */jsx9(FormGroupWrapper, {
401
+ children
402
+ })
403
+ });
404
+ };
405
+ export { Form, FormField, FormFieldCheckbox, FormFieldInput, FormFieldRadio, FormFieldSelect, FormFieldTextarea, FormGroup, useFormGroup, yup, yupResolver };
package/dist/index.d.ts CHANGED
@@ -5,7 +5,9 @@ export * from 'react-hook-form';
5
5
  import * as yup from 'yup';
6
6
  export { yup };
7
7
  import * as React from 'react';
8
- import { BoxProps, CheckboxProps, IconType, RadioProps, TextareaProps } from '@ttoss/ui';
8
+ import React__default from 'react';
9
+ import * as _ttoss_ui from '@ttoss/ui';
10
+ import { BoxProps, CheckboxProps, LabelProps, RadioProps, TextareaProps } from '@ttoss/ui';
9
11
  import * as theme_ui from 'theme-ui';
10
12
 
11
13
  declare const Form: <TFieldValues extends FieldValues = FieldValues>({ children, onSubmit, sx, ...formMethods }: {
@@ -29,15 +31,13 @@ declare const FormFieldCheckbox: <TFieldValues extends FieldValues = FieldValues
29
31
  name: FieldPath<TFieldValues>;
30
32
  } & CheckboxProps) => JSX.Element;
31
33
 
32
- declare const FormFieldInput: <TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>>({ label, name, tooltipIcon, showCharacterCounter, ...inputProps }: {
34
+ declare const FormFieldInput: <TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>>({ label, name, tooltip, onTooltipClick, ...inputProps }: {
33
35
  label?: string | undefined;
34
36
  name: TName;
35
- tooltipIcon?: IconType | undefined;
36
- showCharacterCounter?: boolean | undefined;
37
37
  } & theme_ui.InputProps & {
38
- leadingIcon?: IconType | undefined;
39
- trailingIcon?: IconType | undefined;
40
- }) => JSX.Element;
38
+ leadingIcon?: _ttoss_ui.IconType | undefined;
39
+ trailingIcon?: _ttoss_ui.IconType | undefined;
40
+ } & Pick<LabelProps, "tooltip" | "onTooltipClick">) => JSX.Element;
41
41
 
42
42
  type FormRadioOption$1 = {
43
43
  value: string | number;
@@ -64,4 +64,13 @@ declare const FormFieldTextarea: <TFieldValues extends FieldValues = FieldValues
64
64
  name: TName;
65
65
  } & TextareaProps) => JSX.Element;
66
66
 
67
- export { Form, FormField, FormFieldCheckbox, FormFieldInput, FormFieldRadio, FormFieldSelect, FormFieldTextarea };
67
+ declare const useFormGroup: () => {
68
+ level: number | undefined;
69
+ levelsLength: number | undefined;
70
+ };
71
+ type FormGroupProps = {
72
+ children: React__default.ReactNode;
73
+ };
74
+ declare const FormGroup: ({ children }: FormGroupProps) => JSX.Element;
75
+
76
+ export { Form, FormField, FormFieldCheckbox, FormFieldInput, FormFieldRadio, FormFieldSelect, FormFieldTextarea, FormGroup, useFormGroup };
package/dist/index.js CHANGED
@@ -46,6 +46,8 @@ __export(src_exports, {
46
46
  FormFieldRadio: () => FormFieldRadio,
47
47
  FormFieldSelect: () => FormFieldSelect,
48
48
  FormFieldTextarea: () => FormFieldTextarea,
49
+ FormGroup: () => FormGroup,
50
+ useFormGroup: () => useFormGroup,
49
51
  yup: () => yup,
50
52
  yupResolver: () => import_yup.yupResolver
51
53
  });
@@ -88,7 +90,8 @@ var import_ui2 = require("@ttoss/ui");
88
90
  var import_error_message = require("@hookform/error-message");
89
91
  var import_jsx_runtime2 = require("react/jsx-runtime");
90
92
  var ErrorMessage = ({
91
- name
93
+ name,
94
+ disabled
92
95
  }) => {
93
96
  const {
94
97
  formState: {
@@ -99,7 +102,8 @@ var ErrorMessage = ({
99
102
  errors,
100
103
  name,
101
104
  as: /* @__PURE__ */(0, import_jsx_runtime2.jsx)(import_ui2.HelpText, {
102
- negative: true
105
+ negative: true,
106
+ disabled
103
107
  })
104
108
  });
105
109
  };
@@ -190,13 +194,12 @@ var FormFieldCheckbox = ({
190
194
  // src/FormFieldInput.tsx
191
195
  var import_ui5 = require("@ttoss/ui");
192
196
  var import_react_hook_form5 = require("react-hook-form");
193
- var import_react = __toESM(require("react"));
194
197
  var import_jsx_runtime5 = require("react/jsx-runtime");
195
198
  var FormFieldInput = ({
196
199
  label,
197
200
  name,
198
- tooltipIcon,
199
- showCharacterCounter,
201
+ tooltip,
202
+ onTooltipClick,
200
203
  ...inputProps
201
204
  }) => {
202
205
  const {
@@ -213,42 +216,15 @@ var FormFieldInput = ({
213
216
  name,
214
217
  defaultValue: ""
215
218
  });
216
- const characterCounter = import_react.default.useMemo(() => {
217
- if (!value) {
218
- return 0;
219
- }
220
- return String(value).length;
221
- }, [value]);
222
219
  const id = `form-field-input-${name}`;
223
220
  const hasError = !!errors[name]?.message;
224
221
  return /* @__PURE__ */(0, import_jsx_runtime5.jsxs)(import_ui5.Box, {
225
- children: [label && /* @__PURE__ */(0, import_jsx_runtime5.jsxs)(import_ui5.Label, {
226
- sx: {
227
- display: "flex",
228
- alignItems: "center"
229
- },
222
+ children: [label && /* @__PURE__ */(0, import_jsx_runtime5.jsx)(import_ui5.Label, {
230
223
  "aria-disabled": inputProps.disabled,
231
224
  htmlFor: id,
232
- children: [label, tooltipIcon && /* @__PURE__ */(0, import_jsx_runtime5.jsx)(import_ui5.Text, {
233
- sx: {
234
- marginLeft: "md",
235
- fontSize: "xs",
236
- lineHeight: 0
237
- },
238
- variant: "tooltip-icon",
239
- children: /* @__PURE__ */(0, import_jsx_runtime5.jsx)(import_ui5.Icon, {
240
- icon: tooltipIcon
241
- })
242
- }), showCharacterCounter && /* @__PURE__ */(0, import_jsx_runtime5.jsx)(import_ui5.Text, {
243
- sx: {
244
- marginLeft: "auto",
245
- fontSize: "xs",
246
- lineHeight: 0,
247
- color: "underemphasize"
248
- },
249
- variant: "character-counter",
250
- children: characterCounter
251
- })]
225
+ tooltip,
226
+ onTooltipClick,
227
+ children: label
252
228
  }), /* @__PURE__ */(0, import_jsx_runtime5.jsx)(import_ui5.Input, {
253
229
  ref,
254
230
  onChange,
@@ -380,6 +356,103 @@ var FormFieldTextarea = ({
380
356
  }
381
357
  });
382
358
  };
359
+
360
+ // src/FormGroup.tsx
361
+ var import_ui9 = require("@ttoss/ui");
362
+ var import_react = __toESM(require("react"));
363
+ var import_jsx_runtime9 = require("react/jsx-runtime");
364
+ var FormGroupLevelsManagerContext = import_react.default.createContext({
365
+ registerChild: () => {
366
+ return null;
367
+ }
368
+ });
369
+ var FormGroupLevelsManager = ({
370
+ children
371
+ }) => {
372
+ const [levelsLength, setLevelsLength] = import_react.default.useState(0);
373
+ const registerChild = import_react.default.useCallback(level => {
374
+ if (level + 1 > levelsLength) {
375
+ setLevelsLength(level + 1);
376
+ }
377
+ }, [levelsLength]);
378
+ return /* @__PURE__ */(0, import_jsx_runtime9.jsx)(FormGroupLevelsManagerContext.Provider, {
379
+ value: {
380
+ levelsLength,
381
+ registerChild
382
+ },
383
+ children
384
+ });
385
+ };
386
+ var FormGroupContext = import_react.default.createContext({});
387
+ var useFormGroup = () => {
388
+ const {
389
+ parentLevel
390
+ } = import_react.default.useContext(FormGroupContext);
391
+ const {
392
+ levelsLength
393
+ } = import_react.default.useContext(FormGroupLevelsManagerContext);
394
+ return {
395
+ level: parentLevel,
396
+ levelsLength
397
+ };
398
+ };
399
+ var FormGroupWrapper = ({
400
+ children
401
+ }) => {
402
+ const {
403
+ level,
404
+ levelsLength
405
+ } = useFormGroup();
406
+ const {
407
+ registerChild
408
+ } = import_react.default.useContext(FormGroupLevelsManagerContext);
409
+ import_react.default.useEffect(() => {
410
+ if (typeof level === "number") {
411
+ registerChild(level);
412
+ }
413
+ }, [level, registerChild]);
414
+ const sx = import_react.default.useMemo(() => {
415
+ return {
416
+ flexDirection: "column",
417
+ width: "100%",
418
+ gap: "md",
419
+ paddingLeft: ({
420
+ space
421
+ }) => {
422
+ if (!level || !levelsLength) {
423
+ return 0;
424
+ }
425
+ const value = levelsLength / level;
426
+ return `calc(${space["lg"]} / ${value})`;
427
+ }
428
+ };
429
+ }, [level, levelsLength]);
430
+ return /* @__PURE__ */(0, import_jsx_runtime9.jsx)(import_ui9.Flex, {
431
+ "aria-level": level,
432
+ sx,
433
+ children
434
+ });
435
+ };
436
+ var FormGroup = ({
437
+ children
438
+ }) => {
439
+ const {
440
+ level
441
+ } = useFormGroup();
442
+ const currentLevel = level === void 0 ? 0 : level + 1;
443
+ return /* @__PURE__ */(0, import_jsx_runtime9.jsx)(FormGroupContext.Provider, {
444
+ value: {
445
+ parentLevel: currentLevel
446
+ },
447
+ children: currentLevel === 0 ? /* @__PURE__ */(0, import_jsx_runtime9.jsx)(FormGroupLevelsManager, {
448
+ children: /* @__PURE__ */(0, import_jsx_runtime9.jsx)(FormGroupWrapper, {
449
+ children
450
+ })
451
+ }) : /* @__PURE__ */(0, import_jsx_runtime9.jsx)(FormGroupWrapper, {
452
+ children
453
+ })
454
+ });
455
+ };
383
456
  // Annotate the CommonJS export names for ESM import in node:
384
457
  0 && (module.exports = {
385
458
  Form,
@@ -389,6 +462,8 @@ var FormFieldTextarea = ({
389
462
  FormFieldRadio,
390
463
  FormFieldSelect,
391
464
  FormFieldTextarea,
465
+ FormGroup,
466
+ useFormGroup,
392
467
  yup,
393
468
  yupResolver,
394
469
  ...require("react-hook-form")
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ttoss/forms",
3
- "version": "0.14.27",
3
+ "version": "0.14.29",
4
4
  "license": "UNLICENSED",
5
5
  "author": "ttoss",
6
6
  "contributors": [
@@ -20,26 +20,26 @@
20
20
  "typings": "dist/index.d.ts",
21
21
  "dependencies": {
22
22
  "@hookform/error-message": "^2.0.1",
23
- "@hookform/resolvers": "^2.9.11",
24
- "react-hook-form": "^7.43.2",
25
- "yup": "^1.0.0"
23
+ "@hookform/resolvers": "^3.0.1",
24
+ "react-hook-form": "^7.43.9",
25
+ "yup": "^1.1.0"
26
26
  },
27
27
  "peerDependencies": {
28
- "@ttoss/ui": "^1.30.2",
28
+ "@ttoss/ui": "^1.31.15",
29
29
  "react": "^18.2.0"
30
30
  },
31
31
  "devDependencies": {
32
32
  "@ttoss/config": "^1.29.3",
33
33
  "@ttoss/test-utils": "^1.21.2",
34
- "@ttoss/ui": "^1.31.14",
34
+ "@ttoss/ui": "^1.31.15",
35
35
  "@types/jest": "^29.5.0",
36
36
  "jest": "^29.5.0",
37
37
  "react": "^18.2.0",
38
- "react-hook-form": "^7.43.2",
39
- "yup": "^1.0.0"
38
+ "react-hook-form": "^7.43.9",
39
+ "yup": "^1.1.0"
40
40
  },
41
41
  "publishConfig": {
42
42
  "access": "public"
43
43
  },
44
- "gitHead": "8572bc7e98343a9780146a604b0d2f04ca4388e6"
44
+ "gitHead": "8ef9fc83abcc00169860b2b6391bbb4d7374d911"
45
45
  }
@@ -4,8 +4,10 @@ import { ErrorMessage as HookFormErrorMessage } from '@hookform/error-message';
4
4
 
5
5
  export const ErrorMessage = <TFieldValues extends FieldValues = FieldValues>({
6
6
  name,
7
+ disabled,
7
8
  }: {
8
9
  name: FieldName<TFieldValues>;
10
+ disabled?: boolean;
9
11
  }) => {
10
12
  const {
11
13
  formState: { errors },
@@ -15,7 +17,7 @@ export const ErrorMessage = <TFieldValues extends FieldValues = FieldValues>({
15
17
  <HookFormErrorMessage
16
18
  errors={errors}
17
19
  name={name as any}
18
- as={<HelpText negative />}
20
+ as={<HelpText negative disabled={disabled} />}
19
21
  />
20
22
  );
21
23
  };
@@ -1,15 +1,6 @@
1
- import {
2
- Box,
3
- Icon,
4
- type IconType,
5
- Input,
6
- type InputProps,
7
- Label,
8
- Text,
9
- } from '@ttoss/ui';
1
+ import { Box, Input, type InputProps, Label, type LabelProps } from '@ttoss/ui';
10
2
  import { ErrorMessage } from './ErrorMessage';
11
3
  import { FieldPath, FieldValues, useController } from 'react-hook-form';
12
- import React from 'react';
13
4
 
14
5
  export const FormFieldInput = <
15
6
  TFieldValues extends FieldValues = FieldValues,
@@ -17,15 +8,14 @@ export const FormFieldInput = <
17
8
  >({
18
9
  label,
19
10
  name,
20
- tooltipIcon,
21
- showCharacterCounter,
11
+ tooltip,
12
+ onTooltipClick,
22
13
  ...inputProps
23
14
  }: {
24
15
  label?: string;
25
16
  name: TName;
26
- tooltipIcon?: IconType;
27
- showCharacterCounter?: boolean;
28
- } & InputProps) => {
17
+ } & InputProps &
18
+ Pick<LabelProps, 'tooltip' | 'onTooltipClick'>) => {
29
19
  const {
30
20
  field: { onChange, onBlur, value, ref },
31
21
  formState: { errors },
@@ -34,14 +24,6 @@ export const FormFieldInput = <
34
24
  defaultValue: '',
35
25
  });
36
26
 
37
- const characterCounter = React.useMemo(() => {
38
- if (!value) {
39
- return 0;
40
- }
41
-
42
- return String(value).length;
43
- }, [value]);
44
-
45
27
  const id = `form-field-input-${name}`;
46
28
 
47
29
  const hasError = !!errors[name]?.message;
@@ -50,33 +32,12 @@ export const FormFieldInput = <
50
32
  <Box>
51
33
  {label && (
52
34
  <Label
53
- sx={{ display: 'flex', alignItems: 'center' }}
54
35
  aria-disabled={inputProps.disabled}
55
36
  htmlFor={id}
37
+ tooltip={tooltip}
38
+ onTooltipClick={onTooltipClick}
56
39
  >
57
40
  {label}
58
- {tooltipIcon && (
59
- <Text
60
- sx={{ marginLeft: 'md', fontSize: 'xs', lineHeight: 0 }}
61
- variant="tooltip-icon"
62
- >
63
- <Icon icon={tooltipIcon} />
64
- </Text>
65
- )}
66
-
67
- {showCharacterCounter && (
68
- <Text
69
- sx={{
70
- marginLeft: 'auto',
71
- fontSize: 'xs',
72
- lineHeight: 0,
73
- color: 'underemphasize',
74
- }}
75
- variant="character-counter"
76
- >
77
- {characterCounter}
78
- </Text>
79
- )}
80
41
  </Label>
81
42
  )}
82
43
 
@@ -0,0 +1,116 @@
1
+ import { Flex, FlexProps } from '@ttoss/ui';
2
+ import React from 'react';
3
+
4
+ type FormGroupLevelsManagerContextType = {
5
+ levelsLength?: number;
6
+ registerChild: (level: number) => void;
7
+ };
8
+
9
+ const FormGroupLevelsManagerContext =
10
+ React.createContext<FormGroupLevelsManagerContextType>({
11
+ registerChild: () => {
12
+ return null;
13
+ },
14
+ });
15
+
16
+ const FormGroupLevelsManager = ({
17
+ children,
18
+ }: {
19
+ children: React.ReactNode;
20
+ }) => {
21
+ const [levelsLength, setLevelsLength] = React.useState(0);
22
+
23
+ const registerChild = React.useCallback(
24
+ (level: number) => {
25
+ if (level + 1 > levelsLength) {
26
+ setLevelsLength(level + 1);
27
+ }
28
+ },
29
+ [levelsLength]
30
+ );
31
+
32
+ return (
33
+ <FormGroupLevelsManagerContext.Provider
34
+ value={{ levelsLength, registerChild }}
35
+ >
36
+ {children}
37
+ </FormGroupLevelsManagerContext.Provider>
38
+ );
39
+ };
40
+
41
+ type FormGroupContextType = {
42
+ parentLevel?: number;
43
+ };
44
+
45
+ const FormGroupContext = React.createContext<FormGroupContextType>({});
46
+
47
+ export const useFormGroup = () => {
48
+ const { parentLevel } = React.useContext(FormGroupContext);
49
+ const { levelsLength } = React.useContext(FormGroupLevelsManagerContext);
50
+
51
+ return {
52
+ level: parentLevel,
53
+ levelsLength,
54
+ };
55
+ };
56
+
57
+ type FormGroupProps = {
58
+ children: React.ReactNode;
59
+ };
60
+
61
+ const FormGroupWrapper = ({ children }: { children: React.ReactNode }) => {
62
+ const { level, levelsLength } = useFormGroup();
63
+
64
+ const { registerChild } = React.useContext(FormGroupLevelsManagerContext);
65
+
66
+ React.useEffect(() => {
67
+ /**
68
+ * We can't use if(level) because level can be 0 and we want to register
69
+ * it anyway.
70
+ */
71
+ if (typeof level === 'number') {
72
+ registerChild(level);
73
+ }
74
+ }, [level, registerChild]);
75
+
76
+ const sx: FlexProps['sx'] = React.useMemo(() => {
77
+ return {
78
+ flexDirection: 'column',
79
+ width: '100%',
80
+ gap: 'md',
81
+ paddingLeft: ({ space }: any) => {
82
+ if (!level || !levelsLength) {
83
+ return 0;
84
+ }
85
+
86
+ const value = levelsLength / level;
87
+
88
+ return `calc(${space['lg']} / ${value})`;
89
+ },
90
+ };
91
+ }, [level, levelsLength]);
92
+
93
+ return (
94
+ <Flex aria-level={level} sx={sx}>
95
+ {children}
96
+ </Flex>
97
+ );
98
+ };
99
+
100
+ export const FormGroup = ({ children }: FormGroupProps) => {
101
+ const { level } = useFormGroup();
102
+
103
+ const currentLevel = level === undefined ? 0 : level + 1;
104
+
105
+ return (
106
+ <FormGroupContext.Provider value={{ parentLevel: currentLevel }}>
107
+ {currentLevel === 0 ? (
108
+ <FormGroupLevelsManager>
109
+ <FormGroupWrapper>{children}</FormGroupWrapper>
110
+ </FormGroupLevelsManager>
111
+ ) : (
112
+ <FormGroupWrapper>{children}</FormGroupWrapper>
113
+ )}
114
+ </FormGroupContext.Provider>
115
+ );
116
+ };
package/src/index.ts CHANGED
@@ -9,3 +9,4 @@ export { FormFieldInput } from './FormFieldInput';
9
9
  export { FormFieldRadio } from './FormFieldRadio';
10
10
  export { FormFieldSelect } from './FormFieldSelect';
11
11
  export { FormFieldTextarea } from './FormFieldTextarea';
12
+ export { FormGroup, useFormGroup } from './FormGroup';