@a-type/ui 6.0.22 → 6.0.23

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 (50) hide show
  1. package/dist/components/forms/CheckboxField.d.ts +3 -1
  2. package/dist/components/forms/CheckboxField.js +5 -6
  3. package/dist/components/forms/CheckboxField.js.map +1 -1
  4. package/dist/components/forms/EmojiField.d.ts +3 -1
  5. package/dist/components/forms/EmojiField.js +10 -11
  6. package/dist/components/forms/EmojiField.js.map +1 -1
  7. package/dist/components/forms/Field.d.ts +16 -0
  8. package/dist/components/forms/Field.js +37 -0
  9. package/dist/components/forms/Field.js.map +1 -0
  10. package/dist/components/forms/Field.module.css +51 -0
  11. package/dist/components/forms/Form.module.css +1 -1
  12. package/dist/components/forms/FormikForm.d.ts +2 -2
  13. package/dist/components/forms/FormikForm.stories.d.ts +2 -2
  14. package/dist/components/forms/FormikForm.stories.js +1 -1
  15. package/dist/components/forms/FormikForm.stories.js.map +1 -1
  16. package/dist/components/forms/NumberStepperField.d.ts +3 -1
  17. package/dist/components/forms/NumberStepperField.js +6 -9
  18. package/dist/components/forms/NumberStepperField.js.map +1 -1
  19. package/dist/components/forms/SwitchField.d.ts +3 -1
  20. package/dist/components/forms/SwitchField.js +5 -6
  21. package/dist/components/forms/SwitchField.js.map +1 -1
  22. package/dist/components/forms/TextField.d.ts +7 -5
  23. package/dist/components/forms/TextField.js +5 -7
  24. package/dist/components/forms/TextField.js.map +1 -1
  25. package/dist/components/forms/ToggleGroupField.d.ts +3 -1
  26. package/dist/components/forms/ToggleGroupField.js +10 -11
  27. package/dist/components/forms/ToggleGroupField.js.map +1 -1
  28. package/dist/components/forms/index.d.ts +1 -1
  29. package/dist/components/forms/index.js +1 -1
  30. package/dist/components/forms/index.js.map +1 -1
  31. package/dist/components/switch/Switch.module.css +1 -1
  32. package/package.json +1 -1
  33. package/src/components/forms/CheckboxField.tsx +23 -15
  34. package/src/components/forms/EmojiField.tsx +50 -33
  35. package/src/components/forms/Field.module.css +51 -0
  36. package/src/components/forms/Field.tsx +43 -0
  37. package/src/components/forms/Form.module.css +1 -1
  38. package/src/components/forms/FormikForm.stories.tsx +25 -5
  39. package/src/components/forms/NumberStepperField.tsx +24 -17
  40. package/src/components/forms/SwitchField.tsx +23 -15
  41. package/src/components/forms/TextField.tsx +49 -25
  42. package/src/components/forms/ToggleGroupField.tsx +29 -19
  43. package/src/components/forms/index.tsx +1 -1
  44. package/src/components/switch/Switch.module.css +1 -1
  45. package/dist/components/forms/FieldLabel.d.ts +0 -2
  46. package/dist/components/forms/FieldLabel.js +0 -5
  47. package/dist/components/forms/FieldLabel.js.map +0 -1
  48. package/dist/components/forms/FieldLabel.module.css +0 -20
  49. package/src/components/forms/FieldLabel.module.css +0 -20
  50. package/src/components/forms/FieldLabel.tsx +0 -9
@@ -1,8 +1,8 @@
1
1
  import { useField } from 'formik';
2
+ import { ReactNode } from 'react';
2
3
  import { useIdOrGenerated } from '../../hooks/useIdOrGenerated.js';
3
- import { Box } from '../box/Box.js';
4
4
  import { Checkbox } from '../checkbox/index.js';
5
- import { HorizontalFieldLabel } from './FieldLabel.js';
5
+ import { Field } from './Field.js';
6
6
 
7
7
  export interface CheckboxFieldProps {
8
8
  name: string;
@@ -10,6 +10,7 @@ export interface CheckboxFieldProps {
10
10
  required?: boolean;
11
11
  className?: string;
12
12
  id?: string;
13
+ description?: ReactNode;
13
14
  }
14
15
 
15
16
  export function CheckboxField({
@@ -18,24 +19,31 @@ export function CheckboxField({
18
19
  className,
19
20
  required,
20
21
  id: providedId,
22
+ description,
21
23
  ...rest
22
24
  }: CheckboxFieldProps) {
23
25
  const [props, _, tools] = useField({ name, required, type: 'checkbox' });
24
26
  const id = useIdOrGenerated(providedId);
25
27
  return (
26
- <Box gap="md" className={className}>
27
- <Checkbox
28
- {...props}
29
- checked={props.checked}
30
- onCheckedChange={(v) => {
31
- tools.setValue(!!v);
32
- }}
33
- id={id}
34
- {...rest}
35
- />
36
- {label && (
37
- <HorizontalFieldLabel htmlFor={id}>{label}</HorizontalFieldLabel>
28
+ <Field horizontal className={className}>
29
+ <Field.Control>
30
+ <Checkbox
31
+ {...props}
32
+ checked={props.checked}
33
+ onCheckedChange={(v) => {
34
+ tools.setValue(!!v);
35
+ }}
36
+ id={id}
37
+ aria-describedby={description ? `${id}-description` : undefined}
38
+ {...rest}
39
+ />
40
+ </Field.Control>
41
+ {label && <Field.Label htmlFor={id}>{label}</Field.Label>}
42
+ {description && (
43
+ <Field.Description id={`${id}-description`}>
44
+ {description}
45
+ </Field.Description>
38
46
  )}
39
- </Box>
47
+ </Field>
40
48
  );
41
49
  }
@@ -1,19 +1,19 @@
1
1
  import { useField } from 'formik';
2
- import { useState } from 'react';
2
+ import { ReactNode, useState } from 'react';
3
3
  import { useIdOrGenerated } from '../../hooks/useIdOrGenerated.js';
4
- import { Box } from '../box/Box.js';
5
4
  import { Button, ButtonProps } from '../button/Button.js';
6
5
  import { EmojiPicker } from '../emojiPicker/EmojiPicker.js';
7
6
  import { Icon } from '../icon/Icon.js';
8
7
  import { Popover } from '../popover/Popover.js';
9
8
  import cls from './EmojiField.module.css';
10
- import { HorizontalFieldLabel } from './FieldLabel.js';
9
+ import { Field } from './Field.js';
11
10
 
12
11
  export type EmojiFieldProps = Omit<ButtonProps, 'className'> & {
13
12
  name: string;
14
13
  label?: string;
15
14
  required?: string;
16
15
  className?: string;
16
+ description?: ReactNode;
17
17
  };
18
18
 
19
19
  export function EmojiField({
@@ -22,44 +22,61 @@ export function EmojiField({
22
22
  className,
23
23
  required,
24
24
  id: providedId,
25
+ description,
25
26
  ...rest
26
27
  }: EmojiFieldProps) {
27
28
  const [props, _, tools] = useField({ name });
28
29
  const id = useIdOrGenerated(providedId);
29
30
  const [open, setOpen] = useState(false);
30
31
  return (
31
- <Box gap="md" className={className}>
32
- <Popover open={open} onOpenChange={setOpen}>
33
- <Popover.Trigger
34
- render={
35
- <Button id={id} aria-label="Select emoji" size="wrapper" {...rest}>
36
- <Button.Icon className={cls.triggerIcon}>
37
- {props.value || <Icon name="smile" />}
38
- </Button.Icon>
39
- </Button>
40
- }
41
- />
42
- <Popover.Content>
43
- <EmojiPicker
44
- onValueChange={(v) => {
45
- tools.setValue(v);
46
- setOpen(false);
47
- }}
48
- onClear={
49
- required
50
- ? undefined
51
- : () => {
52
- tools.setValue('');
53
- setOpen(false);
54
- }
55
- }
32
+ <Field horizontal className={className}>
33
+ <Field.Control>
34
+ <Popover open={open} onOpenChange={setOpen}>
35
+ <input
36
+ type="hidden"
37
+ {...props}
56
38
  id={id}
39
+ aria-describedby={description ? `${id}-description` : undefined}
40
+ />
41
+ <Popover.Trigger
42
+ render={
43
+ <Button
44
+ id={`${id}-trigger`}
45
+ aria-label="Select emoji"
46
+ size="wrapper"
47
+ {...rest}
48
+ >
49
+ <Button.Icon className={cls.triggerIcon}>
50
+ {props.value || <Icon name="smile" />}
51
+ </Button.Icon>
52
+ </Button>
53
+ }
57
54
  />
58
- </Popover.Content>
59
- </Popover>
60
- {label && (
61
- <HorizontalFieldLabel htmlFor={id}>{label}</HorizontalFieldLabel>
55
+ <Popover.Content>
56
+ <EmojiPicker
57
+ onValueChange={(v) => {
58
+ tools.setValue(v);
59
+ setOpen(false);
60
+ }}
61
+ onClear={
62
+ required
63
+ ? undefined
64
+ : () => {
65
+ tools.setValue('');
66
+ setOpen(false);
67
+ }
68
+ }
69
+ id={id}
70
+ />
71
+ </Popover.Content>
72
+ </Popover>
73
+ </Field.Control>
74
+ {label && <Field.Label htmlFor={id}>{label}</Field.Label>}
75
+ {description && (
76
+ <Field.Description id={`${id}-description`}>
77
+ {description}
78
+ </Field.Description>
62
79
  )}
63
- </Box>
80
+ </Field>
64
81
  );
65
82
  }
@@ -0,0 +1,51 @@
1
+ .root {
2
+ display: grid;
3
+ grid-template-areas: 'label' 'control' 'description';
4
+ justify-content: start;
5
+
6
+ &[data-horizontal] {
7
+ flex-direction: row;
8
+ align-items: center;
9
+ grid-template-areas: 'control label' 'description description';
10
+ grid-template-columns: auto 1fr;
11
+ }
12
+
13
+ &[data-stretch] {
14
+ align-self: stretch;
15
+ justify-content: stretch;
16
+ }
17
+ }
18
+
19
+ .control {
20
+ grid-area: control;
21
+ }
22
+ :where(.control) {
23
+ display: flex;
24
+ flex-direction: column;
25
+ align-items: center;
26
+ gap: var(--m-space-sm);
27
+ }
28
+
29
+ .label {
30
+ grid-area: label;
31
+ @apply --mx-prose-ambient;
32
+ @apply --mx-fg(var(--m-color-neutral-heavy));
33
+ font-weight: var(--m-text-weight-bold);
34
+ margin-bottom: var(--m-space-xs);
35
+ margin-left: calc(var(--m-global-shape-roundness) * var(--m-space-md));
36
+
37
+ [data-horizontal] & {
38
+ @apply --mx-fg(var(--m-color-neutral-ink));
39
+ font-weight: var(--m-text-weight-normal);
40
+ margin-block-start: --fn-literal(5px);
41
+ }
42
+ }
43
+
44
+ .description {
45
+ grid-area: description;
46
+ @apply --mx-prose-ambient;
47
+ @apply --mx-fg(var(--m-color-neutral-heavy));
48
+ font-style: italic;
49
+ margin-top: var(--m-space-sm);
50
+ margin-left: calc(var(--m-global-shape-roundness) * var(--m-space-md));
51
+ }
@@ -0,0 +1,43 @@
1
+ import clsx from 'clsx';
2
+ import { ComponentProps } from 'react';
3
+ import { SlotDiv } from '../utility/SlotDiv.js';
4
+ import cls from './Field.module.css';
5
+
6
+ export interface FieldRootProps extends ComponentProps<'div'> {
7
+ horizontal?: boolean;
8
+ stretch?: boolean;
9
+ }
10
+
11
+ function FieldRoot({ className, horizontal, ...props }: FieldRootProps) {
12
+ return (
13
+ <SlotDiv
14
+ className={clsx(cls.root, className)}
15
+ data-horizontal={horizontal ? '' : undefined}
16
+ data-stretch={props.stretch ? '' : undefined}
17
+ {...props}
18
+ />
19
+ );
20
+ }
21
+
22
+ function FieldControl({ className, ...props }: ComponentProps<typeof SlotDiv>) {
23
+ return <SlotDiv className={clsx(cls.control, className)} {...props} />;
24
+ }
25
+
26
+ function FieldLabel({ className, ...props }: ComponentProps<'label'>) {
27
+ return <label className={clsx(cls.label, className)} {...props} />;
28
+ }
29
+
30
+ function FieldDescription({ className, ...props }: ComponentProps<'div'>) {
31
+ return (
32
+ <div
33
+ className={clsx('@mode-dense', cls.description, className)}
34
+ {...props}
35
+ />
36
+ );
37
+ }
38
+
39
+ export const Field = Object.assign(FieldRoot, {
40
+ Label: FieldLabel,
41
+ Description: FieldDescription,
42
+ Control: FieldControl,
43
+ });
@@ -2,5 +2,5 @@
2
2
  display: flex;
3
3
  align-items: start;
4
4
  flex-direction: column;
5
- gap: var(--m-space-md);
5
+ gap: var(--m-space-lg);
6
6
  }
@@ -47,19 +47,39 @@ export const Default: Story = {
47
47
  label="Email"
48
48
  placeholder="you@example.com"
49
49
  />
50
- <TextField name="password" type="password" label="Password" />
51
- <NumberStepperField name="age" label="Age" min={13} max={100} />
52
- <CheckboxField name="tos" label="I agree" />
53
- <SwitchField name="newsletter" label="Subscribe to newsletter" />
50
+ <TextField
51
+ name="password"
52
+ type="password"
53
+ label="Password"
54
+ description="Make it a good one"
55
+ />
56
+ <NumberStepperField
57
+ name="age"
58
+ label="Age"
59
+ min={13}
60
+ max={100}
61
+ description="You can mail your government ID to us, don't worry, we're the good guys"
62
+ />
63
+ <CheckboxField
64
+ name="tos"
65
+ label="I agree"
66
+ description="To what? Not telling."
67
+ />
68
+ <SwitchField
69
+ name="newsletter"
70
+ label="Subscribe to newsletter"
71
+ description="Don't worry, we don't bother you much"
72
+ />
54
73
  <ToggleGroupField
55
74
  type="single"
56
75
  name="plan"
57
76
  label="Select your plan"
58
77
  required
78
+ description="Please do the expensive one!!!"
59
79
  >
60
80
  <ToggleGroupField.Item value="basic">Basic</ToggleGroupField.Item>
61
81
  <ToggleGroupField.Item value="pro">Pro</ToggleGroupField.Item>
62
- <ToggleGroupField.Item value="enterprise">
82
+ <ToggleGroupField.Item value="enterprise" className="@mode-accent">
63
83
  Enterprise
64
84
  </ToggleGroupField.Item>
65
85
  </ToggleGroupField>
@@ -1,12 +1,11 @@
1
1
  import { useField } from 'formik';
2
- import { withClassName } from '../../hooks.js';
2
+ import { ReactNode } from 'react';
3
3
  import { useIdOrGenerated } from '../../hooks/useIdOrGenerated.js';
4
4
  import {
5
5
  NumberStepper,
6
6
  NumberStepperProps,
7
7
  } from '../numberStepper/NumberStepper.js';
8
- import { FieldLabel } from './FieldLabel.js';
9
- import cls from './NumberStepperField.module.css';
8
+ import { Field } from './Field.js';
10
9
 
11
10
  export interface NumberStepperFieldProps
12
11
  extends Omit<NumberStepperProps, 'value' | 'onChange'> {
@@ -15,6 +14,7 @@ export interface NumberStepperFieldProps
15
14
  className?: string;
16
15
  id?: string;
17
16
  onChange?: (value: number) => void;
17
+ description?: ReactNode;
18
18
  }
19
19
 
20
20
  export function NumberStepperField({
@@ -23,24 +23,31 @@ export function NumberStepperField({
23
23
  className,
24
24
  id: providedId,
25
25
  onChange,
26
+ description,
26
27
  ...rest
27
28
  }: NumberStepperFieldProps) {
28
29
  const [_, field, tools] = useField({ name });
29
30
  const id = useIdOrGenerated(providedId);
30
31
  return (
31
- <FieldRoot className={className}>
32
- {label && <FieldLabel htmlFor={id}>{label}</FieldLabel>}
33
- <NumberStepper
34
- value={field.value}
35
- onChange={(v) => {
36
- tools.setValue(v);
37
- onChange?.(v);
38
- }}
39
- id={id}
40
- {...rest}
41
- />
42
- </FieldRoot>
32
+ <Field className={className} horizontal>
33
+ {label && <Field.Label htmlFor={id}>{label}</Field.Label>}
34
+ <Field.Control>
35
+ <NumberStepper
36
+ value={field.value}
37
+ onChange={(v) => {
38
+ tools.setValue(v);
39
+ onChange?.(v);
40
+ }}
41
+ id={id}
42
+ aria-describedby={description ? `${id}-description` : undefined}
43
+ {...rest}
44
+ />
45
+ </Field.Control>
46
+ {description && (
47
+ <Field.Description id={`${id}-description`}>
48
+ {description}
49
+ </Field.Description>
50
+ )}
51
+ </Field>
43
52
  );
44
53
  }
45
-
46
- const FieldRoot = withClassName('div', cls.root);
@@ -1,8 +1,8 @@
1
1
  import { useField } from 'formik';
2
+ import { ReactNode } from 'react';
2
3
  import { useIdOrGenerated } from '../../hooks/useIdOrGenerated.js';
3
- import { Box } from '../box/Box.js';
4
4
  import { Switch } from '../switch/Switch.js';
5
- import { HorizontalFieldLabel } from './FieldLabel.js';
5
+ import { Field } from './Field.js';
6
6
 
7
7
  export interface SwitchFieldProps {
8
8
  name: string;
@@ -10,6 +10,7 @@ export interface SwitchFieldProps {
10
10
  required?: boolean;
11
11
  className?: string;
12
12
  id?: string;
13
+ description?: ReactNode;
13
14
  }
14
15
 
15
16
  export function SwitchField({
@@ -18,24 +19,31 @@ export function SwitchField({
18
19
  className,
19
20
  required,
20
21
  id: providedId,
22
+ description,
21
23
  ...rest
22
24
  }: SwitchFieldProps) {
23
25
  const [props, _, tools] = useField({ name, required, type: 'checkbox' });
24
26
  const id = useIdOrGenerated(providedId);
25
27
  return (
26
- <Box gap="md" className={className}>
27
- <Switch
28
- {...props}
29
- checked={props.checked}
30
- onCheckedChange={(v) => {
31
- tools.setValue(!!v);
32
- }}
33
- id={id}
34
- {...rest}
35
- />
36
- {label && (
37
- <HorizontalFieldLabel htmlFor={id}>{label}</HorizontalFieldLabel>
28
+ <Field horizontal className={className}>
29
+ <Field.Control>
30
+ <Switch
31
+ {...props}
32
+ checked={props.checked}
33
+ onCheckedChange={(v) => {
34
+ tools.setValue(!!v);
35
+ }}
36
+ id={id}
37
+ aria-describedby={description ? `${id}-description` : undefined}
38
+ {...rest}
39
+ />
40
+ </Field.Control>
41
+ {label && <Field.Label htmlFor={id}>{label}</Field.Label>}
42
+ {description && (
43
+ <Field.Description id={`${id}-description`}>
44
+ {description}
45
+ </Field.Description>
38
46
  )}
39
- </Box>
47
+ </Field>
40
48
  );
41
49
  }
@@ -3,17 +3,17 @@ import { useField, useFormikContext } from 'formik';
3
3
  import {
4
4
  InputHTMLAttributes,
5
5
  KeyboardEvent,
6
+ ReactNode,
6
7
  Ref,
7
8
  useCallback,
8
9
  useEffect,
9
10
  useRef,
10
11
  } from 'react';
11
- import { withClassName } from '../../hooks.js';
12
12
  import { useIdOrGenerated } from '../../hooks/useIdOrGenerated.js';
13
13
  import useMergedRef from '../../hooks/useMergedRef.js';
14
14
  import { Input, InputProps } from '../input/Input.js';
15
15
  import { TextArea, TextAreaProps } from '../textArea/TextArea.js';
16
- import { FieldLabel } from './FieldLabel.js';
16
+ import { Field } from './Field.js';
17
17
  import cls from './TextField.module.css';
18
18
 
19
19
  export type TextFieldProps = {
@@ -24,6 +24,7 @@ export type TextFieldProps = {
24
24
  inputRef?: Ref<HTMLInputElement>;
25
25
  inputClassName?: string;
26
26
  ref?: Ref<HTMLDivElement>;
27
+ description?: ReactNode;
27
28
  } & Omit<InputProps, 'ref'>;
28
29
 
29
30
  const emptyRef = (() => {}) as any;
@@ -41,6 +42,7 @@ export const TextField = function TextField({
41
42
  onBlur,
42
43
  id: providedId,
43
44
  inputClassName,
45
+ description,
44
46
  ...rest
45
47
  }: TextFieldProps) {
46
48
  const [props] = useField({
@@ -61,17 +63,27 @@ export const TextField = function TextField({
61
63
  }, [autoFocusDelay]);
62
64
 
63
65
  return (
64
- <FieldRoot className={className} ref={ref}>
65
- {label && <FieldLabel htmlFor={id}>{label}</FieldLabel>}
66
- <Input
67
- {...props}
68
- {...rest}
69
- id={id}
70
- autoFocus={autoFocus}
71
- className={clsx(cls.input, inputClassName)}
72
- ref={useMergedRef(innerInputRef, inputRef || emptyRef)}
66
+ <Field className={className} stretch ref={ref}>
67
+ {label && <Field.Label htmlFor={id}>{label}</Field.Label>}
68
+ <Field.Control
69
+ render={
70
+ <Input
71
+ {...props}
72
+ {...rest}
73
+ id={id}
74
+ autoFocus={autoFocus}
75
+ className={clsx(cls.input, inputClassName)}
76
+ ref={useMergedRef(innerInputRef, inputRef || emptyRef)}
77
+ aria-describedby={description ? `${id}-description` : undefined}
78
+ />
79
+ }
73
80
  />
74
- </FieldRoot>
81
+ {description && (
82
+ <Field.Description id={`${id}-description`}>
83
+ {description}
84
+ </Field.Description>
85
+ )}
86
+ </Field>
75
87
  );
76
88
  };
77
89
 
@@ -85,7 +97,9 @@ export type TextAreaFieldProps = {
85
97
  inputRef?: Ref<HTMLTextAreaElement>;
86
98
  submitOnEnter?: boolean;
87
99
  textAreaClassName?: string;
88
- } & TextAreaProps;
100
+ description?: ReactNode;
101
+ ref?: Ref<HTMLDivElement>;
102
+ } & Omit<TextAreaProps, 'ref'>;
89
103
 
90
104
  export function TextAreaField({
91
105
  name,
@@ -96,6 +110,8 @@ export function TextAreaField({
96
110
  submitOnEnter,
97
111
  id: providedId,
98
112
  textAreaClassName,
113
+ description,
114
+ ref,
99
115
  ...rest
100
116
  }: TextAreaFieldProps) {
101
117
  const [props] = useField(name);
@@ -113,18 +129,26 @@ export function TextAreaField({
113
129
  const id = useIdOrGenerated(providedId);
114
130
 
115
131
  return (
116
- <FieldRoot className={className}>
117
- {label && <FieldLabel htmlFor={id}>{label}</FieldLabel>}
118
- <TextArea
119
- ref={inputRef as any}
120
- {...props}
121
- {...rest}
122
- className={clsx('layer-composed:w-full', textAreaClassName)}
123
- id={id}
124
- onKeyDown={onKeyDownInner}
132
+ <Field stretch className={className} ref={ref}>
133
+ {label && <Field.Label htmlFor={id}>{label}</Field.Label>}
134
+ <Field.Control
135
+ render={
136
+ <TextArea
137
+ ref={inputRef as any}
138
+ {...props}
139
+ {...rest}
140
+ className={clsx(cls.input, textAreaClassName)}
141
+ id={id}
142
+ onKeyDown={onKeyDownInner}
143
+ aria-describedby={description ? `${id}-description` : undefined}
144
+ />
145
+ }
125
146
  />
126
- </FieldRoot>
147
+ {description && (
148
+ <Field.Description id={`${id}-description`}>
149
+ {description}
150
+ </Field.Description>
151
+ )}
152
+ </Field>
127
153
  );
128
154
  }
129
-
130
- export const FieldRoot = withClassName('div', cls.root);
@@ -1,7 +1,7 @@
1
1
  import { useField } from 'formik';
2
+ import { ReactNode } from 'react';
2
3
  import { ToggleGroup, ToggleGroupProps } from '../toggleGroup/toggleGroup.js';
3
- import { FieldLabel } from './FieldLabel.js';
4
- import { FieldRoot } from './TextField.js';
4
+ import { Field } from './Field.js';
5
5
 
6
6
  export type ToggleGroupFieldProps<Value extends string> =
7
7
  ToggleGroupProps<Value> & {
@@ -11,6 +11,7 @@ export type ToggleGroupFieldProps<Value extends string> =
11
11
  className?: string;
12
12
  id?: string;
13
13
  type?: 'single' | 'multiple';
14
+ description?: ReactNode;
14
15
  };
15
16
 
16
17
  function ToggleGroupFieldDefault({
@@ -20,29 +21,38 @@ function ToggleGroupFieldDefault({
20
21
  className,
21
22
  type = 'single',
22
23
  multiple,
24
+ description,
23
25
  id,
24
26
  ...props
25
27
  }: ToggleGroupFieldProps<string>) {
26
28
  const [fieldProps, _, tools] = useField({ name, required, ...props });
27
29
 
28
30
  return (
29
- <FieldRoot>
30
- {label && <FieldLabel htmlFor={id}>{label}</FieldLabel>}
31
- <ToggleGroup
32
- {...fieldProps}
33
- onValueChange={(v) => {
34
- if (multiple || type === 'multiple') {
35
- tools.setValue(v);
36
- } else {
37
- tools.setValue(v[0]);
38
- }
39
- }}
40
- multiple={multiple || type === 'multiple'}
41
- {...props}
42
- id={id}
43
- className={className}
44
- />
45
- </FieldRoot>
31
+ <Field>
32
+ {label && <Field.Label htmlFor={id}>{label}</Field.Label>}
33
+ <Field.Control>
34
+ <ToggleGroup
35
+ {...fieldProps}
36
+ onValueChange={(v) => {
37
+ if (multiple || type === 'multiple') {
38
+ tools.setValue(v);
39
+ } else {
40
+ tools.setValue(v[0]);
41
+ }
42
+ }}
43
+ multiple={multiple || type === 'multiple'}
44
+ {...props}
45
+ id={id}
46
+ className={className}
47
+ aria-describedby={description ? `${id}-description` : undefined}
48
+ />
49
+ </Field.Control>
50
+ {description && (
51
+ <Field.Description id={`${id}-description`}>
52
+ {description}
53
+ </Field.Description>
54
+ )}
55
+ </Field>
46
56
  );
47
57
  }
48
58
 
@@ -1,5 +1,5 @@
1
1
  export * from './CheckboxField.js';
2
- export * from './FieldLabel.js';
2
+ export * from './Field.js';
3
3
  export * from './Form.js';
4
4
  export * from './FormikForm.js';
5
5
  export * from './hooks.js';
@@ -15,7 +15,7 @@
15
15
  --mx-shadow-value: inset var(--m-shadow-sm);
16
16
 
17
17
  @apply --mx-bg(var(--m-control-bg));
18
- @apply --mx-borderColor(var(--m-control-border));
18
+ @apply --mx-borderColor(var(--m-control-borderColor));
19
19
  border-radius: var(--m-radius-lg);
20
20
 
21
21
  &[data-checked] {