@panneau/ui 5.0.0-alpha.5 → 5.0.0-alpha.6
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 +54 -1
- package/dist/index.d.ts +5 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -2
- package/dist/menu/Menu.css +84 -0
- package/dist/menu/Menu.d.ts +33 -6
- package/dist/menu/Menu.d.ts.map +1 -1
- package/dist/menu/Menu.js +110 -25
- package/dist/menu/Menu.js.map +1 -1
- package/dist/menu/Menu.module.js +22 -0
- package/dist/menu/Menu.module.js.map +1 -0
- package/dist/menu/tokens.d.ts +3 -0
- package/dist/menu/tokens.d.ts.map +1 -0
- package/dist/menu/tokens.js +31 -0
- package/dist/menu/tokens.js.map +1 -0
- package/dist/number-input/NumberInput.css +18 -0
- package/dist/number-input/NumberInput.js +1 -1
- package/dist/number-input/NumberInput.js.map +1 -1
- package/dist/number-input/NumberInput.module.js +3 -1
- package/dist/number-input/NumberInput.module.js.map +1 -1
- package/dist/pill-trigger/PillTrigger.css +104 -0
- package/dist/pill-trigger/PillTrigger.d.ts +20 -0
- package/dist/pill-trigger/PillTrigger.d.ts.map +1 -0
- package/dist/pill-trigger/PillTrigger.js +38 -0
- package/dist/pill-trigger/PillTrigger.js.map +1 -0
- package/dist/pill-trigger/PillTrigger.module.js +18 -0
- package/dist/pill-trigger/PillTrigger.module.js.map +1 -0
- package/dist/pill-trigger/tokens.d.ts +3 -0
- package/dist/pill-trigger/tokens.d.ts.map +1 -0
- package/dist/pill-trigger/tokens.js +37 -0
- package/dist/pill-trigger/tokens.js.map +1 -0
- package/dist/radio-group/RadioGroup.css +90 -0
- package/dist/radio-group/RadioGroup.d.ts +22 -3
- package/dist/radio-group/RadioGroup.d.ts.map +1 -1
- package/dist/radio-group/RadioGroup.js +42 -21
- package/dist/radio-group/RadioGroup.js.map +1 -1
- package/dist/radio-group/RadioGroup.module.js +12 -2
- package/dist/radio-group/RadioGroup.module.js.map +1 -1
- package/dist/radio-group/tokens.d.ts +2 -2
- package/dist/radio-group/tokens.d.ts.map +1 -1
- package/dist/radio-group/tokens.js +22 -2
- package/dist/radio-group/tokens.js.map +1 -1
- package/dist/select/ListBox.css +15 -0
- package/dist/select/ListBox.module.js.map +1 -1
- package/dist/slider/Slider.css +84 -0
- package/dist/slider/Slider.d.ts +20 -0
- package/dist/slider/Slider.d.ts.map +1 -0
- package/dist/slider/Slider.js +70 -0
- package/dist/slider/Slider.js.map +1 -0
- package/dist/slider/Slider.module.js +20 -0
- package/dist/slider/Slider.module.js.map +1 -0
- package/dist/tags-input/TagsInput.css +60 -0
- package/dist/tags-input/TagsInput.d.ts +32 -0
- package/dist/tags-input/TagsInput.d.ts.map +1 -0
- package/dist/tags-input/TagsInput.js +160 -0
- package/dist/tags-input/TagsInput.js.map +1 -0
- package/dist/tags-input/TagsInput.module.js +20 -0
- package/dist/tags-input/TagsInput.module.js.map +1 -0
- package/dist/theme/components.d.ts +3 -1
- package/dist/theme/components.d.ts.map +1 -1
- package/dist/theme/components.js +4 -0
- package/dist/theme/components.js.map +1 -1
- package/package.json +3 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NumberInput.js","names":["fieldStyles","styles"],"sources":["../../src/number-input/NumberInput.tsx"],"sourcesContent":["import { ChevronDown, ChevronUp } from 'lucide-react';\nimport type { ReactNode } from 'react';\nimport {\n type NumberFieldProps as AriaNumberFieldProps,\n Button,\n Group,\n Input,\n NumberField,\n} from 'react-aria-components';\n\nimport {\n type FieldChromeProps,\n FieldDescription,\n FieldErrors,\n FieldLabel,\n fieldStyles,\n} from '../field/FieldParts';\nimport { Icon } from '../icon/Icon';\nimport { cx } from '../utils/cx';\nimport styles from './NumberInput.module.css';\n\nexport interface NumberInputProps\n extends\n Omit<\n AriaNumberFieldProps,\n | 'className'\n | 'style'\n | 'children'\n | 'isInvalid'\n | 'validate'\n | 'value'\n | 'defaultValue'\n | 'onChange'\n >,\n FieldChromeProps {\n /** The number, or `null` when empty. */\n value?: number | null;\n defaultValue?: number | null;\n /** Called with the number, or `null` when the input is cleared. */\n onChange?: (value: number | null) => void;\n placeholder?: string;\n /** Content after the number, inside the control: a unit. */\n suffix?: ReactNode;\n controlClassName?: string;\n inputClassName?: string;\n}\n\nfunction toAria(value: number | null | undefined): number | undefined {\n return value === null ? Number.NaN : value;\n}\n\n/**\n * A number input, formatted for the locale, with steppers and arrow keys. An empty input is\n * `null`, not `NaN`.\n */\nexport function NumberInput({\n label,\n description,\n errors = [],\n value,\n defaultValue,\n onChange,\n placeholder,\n suffix,\n className,\n labelClassName,\n descriptionClassName,\n errorsClassName,\n controlClassName,\n inputClassName,\n isRequired,\n isReadOnly,\n ...props\n}: NumberInputProps) {\n const invalid = errors.length > 0;\n return (\n <NumberField\n {...props}\n value={toAria(value)}\n defaultValue={toAria(defaultValue)}\n onChange={(next) => onChange?.(Number.isNaN(next) ? null : next)}\n isRequired={isRequired}\n isReadOnly={isReadOnly}\n isInvalid={invalid}\n validationBehavior=\"aria\"\n className={cx('panneau-number-input', fieldStyles.field, className)}\n >\n <FieldLabel isRequired={isRequired} className={labelClassName}>\n {label}\n </FieldLabel>\n <Group\n className={cx(fieldStyles.control, styles.control, controlClassName)}\n data-invalid={invalid || undefined}\n data-readonly={isReadOnly || undefined}\n >\n <Input\n placeholder={placeholder}\n className={cx(fieldStyles.bare, styles.input, inputClassName)}\n />\n {suffix !== undefined ? (\n <span className={fieldStyles.adornment}>{suffix}</span>\n ) : null}\n {isReadOnly !== true ? (\n <span className={styles.steppers}>\n <Button slot=\"increment\" className={styles.stepper}>\n <Icon icon={ChevronUp} size=\"xs\" />\n </Button>\n <Button slot=\"decrement\" className={styles.stepper}>\n <Icon icon={ChevronDown} size=\"xs\" />\n </Button>\n </span>\n ) : null}\n </Group>\n <FieldDescription className={descriptionClassName}>{description}</FieldDescription>\n <FieldErrors errors={errors} className={errorsClassName} />\n </NumberField>\n );\n}\n"],"mappings":";;;;;;;;;AA+CA,SAAS,OAAO,OAAsD;CAClE,OAAO,UAAU,OAAO,MAAa;AACzC;;;;;AAMA,SAAgB,YAAY,EACxB,OACA,aACA,SAAS,CAAA,GACT,OACA,cACA,UACA,aACA,QACA,WACA,gBACA,sBACA,iBACA,kBACA,gBACA,YACA,YACA,GAAG,SACc;CACjB,MAAM,UAAU,OAAO,SAAS;CAChC,OACI,qBAAC,aAAD;EACI,GAAI;EACJ,OAAO,OAAO,KAAK;EACnB,cAAc,OAAO,YAAY;EACjC,WAAW,SAAS,WAAW,OAAO,MAAM,IAAI,IAAI,OAAO,IAAI;EACnD;EACA;EACZ,WAAW;EACX,oBAAmB;EACnB,WAAW,GAAG,wBAAwBA,qBAAY,OAAO,SAAS;EATtE,UAAA;GAWI,oBAAC,YAAD;IAAwB;IAAY,WAAW;IAC1C,UAAA;GACO,CAAA;GACZ,qBAAC,OAAD;IACI,WAAW,GAAGA,qBAAY,SAASC,2BAAO,SAAS,gBAAgB;IACnE,gBAAc,WAAW,KAAA;IACzB,iBAAe,cAAc,KAAA;IAHjC,UAAA;KAKI,oBAAC,OAAD;MACiB;MACb,WAAW,GAAGD,qBAAY,MAAMC,2BAAO,OAAO,cAAc;KAAE,CAAA;KAEjE,WAAW,KAAA,IACR,oBAAC,QAAD;MAAM,
|
|
1
|
+
{"version":3,"file":"NumberInput.js","names":["fieldStyles","styles"],"sources":["../../src/number-input/NumberInput.tsx"],"sourcesContent":["import { ChevronDown, ChevronUp } from 'lucide-react';\nimport type { ReactNode } from 'react';\nimport {\n type NumberFieldProps as AriaNumberFieldProps,\n Button,\n Group,\n Input,\n NumberField,\n} from 'react-aria-components';\n\nimport {\n type FieldChromeProps,\n FieldDescription,\n FieldErrors,\n FieldLabel,\n fieldStyles,\n} from '../field/FieldParts';\nimport { Icon } from '../icon/Icon';\nimport { cx } from '../utils/cx';\nimport styles from './NumberInput.module.css';\n\nexport interface NumberInputProps\n extends\n Omit<\n AriaNumberFieldProps,\n | 'className'\n | 'style'\n | 'children'\n | 'isInvalid'\n | 'validate'\n | 'value'\n | 'defaultValue'\n | 'onChange'\n >,\n FieldChromeProps {\n /** The number, or `null` when empty. */\n value?: number | null;\n defaultValue?: number | null;\n /** Called with the number, or `null` when the input is cleared. */\n onChange?: (value: number | null) => void;\n placeholder?: string;\n /** Content after the number, inside the control: a unit. */\n suffix?: ReactNode;\n controlClassName?: string;\n inputClassName?: string;\n}\n\nfunction toAria(value: number | null | undefined): number | undefined {\n return value === null ? Number.NaN : value;\n}\n\n/**\n * A number input, formatted for the locale, with steppers and arrow keys. An empty input is\n * `null`, not `NaN`.\n */\nexport function NumberInput({\n label,\n description,\n errors = [],\n value,\n defaultValue,\n onChange,\n placeholder,\n suffix,\n className,\n labelClassName,\n descriptionClassName,\n errorsClassName,\n controlClassName,\n inputClassName,\n isRequired,\n isReadOnly,\n ...props\n}: NumberInputProps) {\n const invalid = errors.length > 0;\n return (\n <NumberField\n {...props}\n value={toAria(value)}\n defaultValue={toAria(defaultValue)}\n onChange={(next) => onChange?.(Number.isNaN(next) ? null : next)}\n isRequired={isRequired}\n isReadOnly={isReadOnly}\n isInvalid={invalid}\n validationBehavior=\"aria\"\n className={cx('panneau-number-input', fieldStyles.field, className)}\n >\n <FieldLabel isRequired={isRequired} className={labelClassName}>\n {label}\n </FieldLabel>\n <Group\n className={cx(fieldStyles.control, styles.control, controlClassName)}\n data-invalid={invalid || undefined}\n data-readonly={isReadOnly || undefined}\n >\n <Input\n placeholder={placeholder}\n className={cx(fieldStyles.bare, styles.input, inputClassName)}\n />\n {suffix !== undefined ? (\n <span className={cx(fieldStyles.adornment, styles.suffix)}>{suffix}</span>\n ) : null}\n {isReadOnly !== true ? (\n <span className={styles.steppers}>\n <Button slot=\"increment\" className={styles.stepper}>\n <Icon icon={ChevronUp} size=\"xs\" />\n </Button>\n <Button slot=\"decrement\" className={styles.stepper}>\n <Icon icon={ChevronDown} size=\"xs\" />\n </Button>\n </span>\n ) : null}\n </Group>\n <FieldDescription className={descriptionClassName}>{description}</FieldDescription>\n <FieldErrors errors={errors} className={errorsClassName} />\n </NumberField>\n );\n}\n"],"mappings":";;;;;;;;;AA+CA,SAAS,OAAO,OAAsD;CAClE,OAAO,UAAU,OAAO,MAAa;AACzC;;;;;AAMA,SAAgB,YAAY,EACxB,OACA,aACA,SAAS,CAAA,GACT,OACA,cACA,UACA,aACA,QACA,WACA,gBACA,sBACA,iBACA,kBACA,gBACA,YACA,YACA,GAAG,SACc;CACjB,MAAM,UAAU,OAAO,SAAS;CAChC,OACI,qBAAC,aAAD;EACI,GAAI;EACJ,OAAO,OAAO,KAAK;EACnB,cAAc,OAAO,YAAY;EACjC,WAAW,SAAS,WAAW,OAAO,MAAM,IAAI,IAAI,OAAO,IAAI;EACnD;EACA;EACZ,WAAW;EACX,oBAAmB;EACnB,WAAW,GAAG,wBAAwBA,qBAAY,OAAO,SAAS;EATtE,UAAA;GAWI,oBAAC,YAAD;IAAwB;IAAY,WAAW;IAC1C,UAAA;GACO,CAAA;GACZ,qBAAC,OAAD;IACI,WAAW,GAAGA,qBAAY,SAASC,2BAAO,SAAS,gBAAgB;IACnE,gBAAc,WAAW,KAAA;IACzB,iBAAe,cAAc,KAAA;IAHjC,UAAA;KAKI,oBAAC,OAAD;MACiB;MACb,WAAW,GAAGD,qBAAY,MAAMC,2BAAO,OAAO,cAAc;KAAE,CAAA;KAEjE,WAAW,KAAA,IACR,oBAAC,QAAD;MAAM,WAAW,GAAGD,qBAAY,WAAWC,2BAAO,MAAM;MAAI,UAAA;KAAa,CAAA,IACzE;KACH,eAAe,OACZ,qBAAC,QAAD;MAAM,WAAWA,2BAAO;MAAxB,UAAA,CACI,oBAAC,QAAD;OAAQ,MAAK;OAAY,WAAWA,2BAAO;OACvC,UAAA,oBAAC,MAAD;QAAM,MAAM;QAAW,MAAK;OAAI,CAAA;MAC5B,CAAA,GACR,oBAAC,QAAD;OAAQ,MAAK;OAAY,WAAWA,2BAAO;OACvC,UAAA,oBAAC,MAAD;QAAM,MAAM;QAAa,MAAK;OAAI,CAAA;MAC9B,CAAA,CACN;KACN,CAAA,IAAA;IACD;;GACP,oBAAC,kBAAD;IAAkB,WAAW;IAAuB,UAAA;GAA8B,CAAA;GAClF,oBAAC,aAAD;IAAqB;IAAQ,WAAW;GAAgB,CAAA;EAC/C;;AAErB"}
|
|
@@ -2,15 +2,17 @@ import "./NumberInput.css";
|
|
|
2
2
|
//#region src/number-input/NumberInput.module.css
|
|
3
3
|
var control = "panneau-number-input-control";
|
|
4
4
|
var input = "panneau-number-input-input";
|
|
5
|
+
var suffix = "panneau-number-input-suffix";
|
|
5
6
|
var steppers = "panneau-number-input-steppers";
|
|
6
7
|
var stepper = "panneau-number-input-stepper";
|
|
7
8
|
var NumberInput_module_default = {
|
|
8
9
|
control,
|
|
9
10
|
input,
|
|
11
|
+
suffix,
|
|
10
12
|
steppers,
|
|
11
13
|
stepper
|
|
12
14
|
};
|
|
13
15
|
//#endregion
|
|
14
|
-
export { control, NumberInput_module_default as default, input, stepper, steppers };
|
|
16
|
+
export { control, NumberInput_module_default as default, input, stepper, steppers, suffix };
|
|
15
17
|
|
|
16
18
|
//# sourceMappingURL=NumberInput.module.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NumberInput.module.js","names":[],"sources":["../../src/number-input/NumberInput.module.css"],"sourcesContent":[".control.control {\n padding-inline-end: 0;\n overflow: hidden;\n}\n\n.input {\n font-variant-numeric: var(--panneau-font-numeric);\n}\n\n.steppers {\n display: flex;\n flex-direction: column;\n align-self: stretch;\n border-inline-start: var(--panneau-border-width) solid var(--panneau-color-border);\n}\n\n.stepper {\n display: flex;\n flex: 1 1 0;\n align-items: center;\n justify-content: center;\n width: var(--panneau-number-input-stepper-width, 1.75rem);\n padding: 0;\n color: var(--panneau-color-text-muted);\n cursor: pointer;\n background: transparent;\n border: 0;\n}\n\n.stepper + .stepper {\n border-top: var(--panneau-border-width) solid var(--panneau-color-border);\n}\n\n.stepper[data-hovered] {\n color: var(--panneau-color-text);\n background-color: var(--panneau-color-hover);\n}\n\n.stepper[data-pressed] {\n background-color: var(--panneau-color-pressed);\n}\n\n.stepper[data-disabled] {\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n/* Touch screens have their own keyboard for numbers: the steppers would be too small. */\n@media (pointer: coarse) {\n .steppers {\n display: none;\n }\n\n .control.control {\n padding-inline-end: var(--panneau-space-3);\n }\n}\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"NumberInput.module.js","names":[],"sources":["../../src/number-input/NumberInput.module.css"],"sourcesContent":[".control.control {\n padding-inline-end: 0;\n overflow: hidden;\n}\n\n/* Without steppers, the control has its padding back. */\n.control.control[data-readonly] {\n padding-inline-end: var(--panneau-input-padding-x, var(--panneau-control-padding-x));\n}\n\n.input {\n font-variant-numeric: var(--panneau-font-numeric);\n}\n\n/* The suffix sits between the value and the steppers, which have no padding of their own. */\n.suffix.suffix {\n margin-inline: var(--panneau-space-2);\n}\n\n.control[data-readonly] .suffix {\n margin-inline-end: 0;\n}\n\n.steppers {\n display: flex;\n flex-direction: column;\n align-self: stretch;\n border-inline-start: var(--panneau-border-width) solid var(--panneau-color-border);\n}\n\n.stepper {\n display: flex;\n flex: 1 1 0;\n align-items: center;\n justify-content: center;\n width: var(--panneau-number-input-stepper-width, 1.75rem);\n padding: 0;\n color: var(--panneau-color-text-muted);\n cursor: pointer;\n background: transparent;\n border: 0;\n}\n\n.stepper + .stepper {\n border-top: var(--panneau-border-width) solid var(--panneau-color-border);\n}\n\n.stepper[data-hovered] {\n color: var(--panneau-color-text);\n background-color: var(--panneau-color-hover);\n}\n\n.stepper[data-pressed] {\n background-color: var(--panneau-color-pressed);\n}\n\n.stepper[data-disabled] {\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n/* Touch screens have their own keyboard for numbers: the steppers would be too small. */\n@media (pointer: coarse) {\n .steppers {\n display: none;\n }\n\n .control.control {\n padding-inline-end: var(--panneau-space-3);\n }\n\n .suffix.suffix {\n margin-inline-end: 0;\n }\n}\n"],"mappings":""}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/* A compact rounded button that shows a current value: the trigger of a menu or a popover. */
|
|
2
|
+
|
|
3
|
+
.panneau-pill-trigger {
|
|
4
|
+
display: inline-flex;
|
|
5
|
+
flex: 0 1 auto;
|
|
6
|
+
align-items: center;
|
|
7
|
+
gap: var(--panneau-pill-trigger-gap, var(--panneau-space-2));
|
|
8
|
+
max-width: 100%;
|
|
9
|
+
min-height: var(--panneau-control-height);
|
|
10
|
+
padding: 0 var(--panneau-pill-trigger-padding-x, var(--panneau-space-3));
|
|
11
|
+
font-family: inherit;
|
|
12
|
+
font-size: var(--panneau-pill-trigger-font-size, var(--panneau-font-size-md));
|
|
13
|
+
font-weight: var(--panneau-pill-trigger-font-weight, var(--panneau-font-weight-medium));
|
|
14
|
+
line-height: var(--panneau-line-height-tight);
|
|
15
|
+
color: var(--panneau-pill-trigger-color, var(--panneau-color-text));
|
|
16
|
+
text-align: start;
|
|
17
|
+
white-space: nowrap;
|
|
18
|
+
cursor: pointer;
|
|
19
|
+
user-select: none;
|
|
20
|
+
background-color: var(--panneau-pill-trigger-bg, var(--panneau-color-surface-sunken));
|
|
21
|
+
border: var(--panneau-border-width) solid var(--panneau-pill-trigger-border-color, transparent);
|
|
22
|
+
border-radius: var(--panneau-pill-trigger-radius, var(--panneau-radius-full));
|
|
23
|
+
transition: background-color var(--panneau-duration);
|
|
24
|
+
-webkit-tap-highlight-color: transparent;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.panneau-pill-trigger[data-hovered],
|
|
28
|
+
.panneau-pill-trigger[data-pressed],
|
|
29
|
+
.panneau-pill-trigger[aria-expanded='true'] {
|
|
30
|
+
background-color: var(
|
|
31
|
+
--panneau-pill-trigger-bg-hover,
|
|
32
|
+
color-mix(in srgb, var(--panneau-color-text) 8%, var(--panneau-color-surface-sunken))
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.panneau-pill-trigger[data-focus-visible] {
|
|
37
|
+
outline: var(--panneau-focus-width) solid var(--panneau-color-focus);
|
|
38
|
+
outline-offset: 2px;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.panneau-pill-trigger[data-disabled] {
|
|
42
|
+
cursor: not-allowed;
|
|
43
|
+
opacity: 0.55;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/* With media, the media sits as far from the start as from the top and the bottom. */
|
|
47
|
+
.panneau-pill-trigger:has(.panneau-pill-trigger-media) {
|
|
48
|
+
padding-inline-start: calc(
|
|
49
|
+
(var(--panneau-control-height) - var(--panneau-pill-trigger-media-size, 1.5rem)) / 2 -
|
|
50
|
+
var(--panneau-border-width)
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.panneau-pill-trigger-sm {
|
|
55
|
+
min-height: var(--panneau-control-height-sm);
|
|
56
|
+
padding: 0 var(--panneau-pill-trigger-padding-x-sm, var(--panneau-space-2));
|
|
57
|
+
font-size: var(--panneau-pill-trigger-font-size-sm, var(--panneau-font-size-sm));
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.panneau-pill-trigger-sm:has(.panneau-pill-trigger-media) {
|
|
61
|
+
padding-inline-start: calc(
|
|
62
|
+
(var(--panneau-control-height-sm) - var(--panneau-pill-trigger-media-size-sm, 1.25rem)) /
|
|
63
|
+
2 - var(--panneau-border-width)
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.panneau-pill-trigger-media {
|
|
68
|
+
display: inline-flex;
|
|
69
|
+
flex: 0 0 auto;
|
|
70
|
+
align-items: center;
|
|
71
|
+
justify-content: center;
|
|
72
|
+
width: var(--panneau-pill-trigger-media-size, 1.5rem);
|
|
73
|
+
height: var(--panneau-pill-trigger-media-size, 1.5rem);
|
|
74
|
+
overflow: hidden;
|
|
75
|
+
border-radius: var(--panneau-pill-trigger-media-radius, var(--panneau-radius-full));
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.panneau-pill-trigger-sm .panneau-pill-trigger-media {
|
|
79
|
+
width: var(--panneau-pill-trigger-media-size-sm, 1.25rem);
|
|
80
|
+
height: var(--panneau-pill-trigger-media-size-sm, 1.25rem);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.panneau-pill-trigger-media > :is(img, svg, video, picture) {
|
|
84
|
+
width: 100%;
|
|
85
|
+
height: 100%;
|
|
86
|
+
object-fit: cover;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.panneau-pill-trigger-value {
|
|
90
|
+
flex: 0 1 auto;
|
|
91
|
+
min-width: 0;
|
|
92
|
+
overflow: hidden;
|
|
93
|
+
text-overflow: ellipsis;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.panneau-pill-trigger-chevron {
|
|
97
|
+
flex: 0 0 auto;
|
|
98
|
+
color: var(--panneau-color-text-muted);
|
|
99
|
+
transition: rotate var(--panneau-duration);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.panneau-pill-trigger[aria-expanded='true'] .panneau-pill-trigger-chevron {
|
|
103
|
+
rotate: 180deg;
|
|
104
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { CSSProperties, ReactNode } from 'react';
|
|
2
|
+
import { type ButtonProps as AriaButtonProps } from 'react-aria-components';
|
|
3
|
+
export interface PillTriggerProps extends Omit<AriaButtonProps, 'className' | 'style' | 'children'> {
|
|
4
|
+
/** The current value, shown inline. */
|
|
5
|
+
children?: ReactNode;
|
|
6
|
+
/** Leading media, such as an avatar or an image, clipped to a circle by default. */
|
|
7
|
+
media?: ReactNode;
|
|
8
|
+
/** Defaults to `md`, the height of a control. */
|
|
9
|
+
size?: 'sm' | 'md';
|
|
10
|
+
className?: string;
|
|
11
|
+
style?: CSSProperties;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* A compact rounded button that shows a current value, with an optional leading media and a
|
|
15
|
+
* chevron: the trigger of a `Menu` (in a `MenuTrigger`) or a `Popover` (in a `PopoverTrigger`).
|
|
16
|
+
* Its accessible name is its value: give it an `aria-label` that contains the value when the
|
|
17
|
+
* value alone doesn't say what it picks.
|
|
18
|
+
*/
|
|
19
|
+
export declare function PillTrigger({ children, media, size, className, ...props }: PillTriggerProps): import("react").JSX.Element;
|
|
20
|
+
//# sourceMappingURL=PillTrigger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PillTrigger.d.ts","sourceRoot":"","sources":["../../src/pill-trigger/PillTrigger.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACtD,OAAO,EAAwB,KAAK,WAAW,IAAI,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAMlG,MAAM,WAAW,gBAAiB,SAAQ,IAAI,CAC1C,eAAe,EACf,WAAW,GAAG,OAAO,GAAG,UAAU,CACrC;IACG,uCAAuC;IACvC,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,oFAAoF;IACpF,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,iDAAiD;IACjD,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,aAAa,CAAC;CACzB;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,EACxB,QAAQ,EACR,KAAK,EACL,IAAW,EACX,SAAS,EACT,GAAG,KAAK,EACX,EAAE,gBAAgB,+BAkBlB"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { cx } from "../utils/cx.js";
|
|
2
|
+
import { Icon } from "../icon/Icon.js";
|
|
3
|
+
import PillTrigger_module_default from "./PillTrigger.module.js";
|
|
4
|
+
import { ChevronDown } from "lucide-react";
|
|
5
|
+
import { Button } from "react-aria-components";
|
|
6
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
+
//#region src/pill-trigger/PillTrigger.tsx
|
|
8
|
+
/**
|
|
9
|
+
* A compact rounded button that shows a current value, with an optional leading media and a
|
|
10
|
+
* chevron: the trigger of a `Menu` (in a `MenuTrigger`) or a `Popover` (in a `PopoverTrigger`).
|
|
11
|
+
* Its accessible name is its value: give it an `aria-label` that contains the value when the
|
|
12
|
+
* value alone doesn't say what it picks.
|
|
13
|
+
*/
|
|
14
|
+
function PillTrigger({ children, media, size = "md", className, ...props }) {
|
|
15
|
+
return /* @__PURE__ */ jsxs(Button, {
|
|
16
|
+
...props,
|
|
17
|
+
className: cx("panneau-pill-trigger", PillTrigger_module_default.pillTrigger, size === "sm" && PillTrigger_module_default.sm, className),
|
|
18
|
+
children: [
|
|
19
|
+
media !== void 0 && media !== null ? /* @__PURE__ */ jsx("span", {
|
|
20
|
+
className: PillTrigger_module_default.media,
|
|
21
|
+
children: media
|
|
22
|
+
}) : null,
|
|
23
|
+
/* @__PURE__ */ jsx("span", {
|
|
24
|
+
className: PillTrigger_module_default.value,
|
|
25
|
+
children
|
|
26
|
+
}),
|
|
27
|
+
/* @__PURE__ */ jsx(Icon, {
|
|
28
|
+
icon: ChevronDown,
|
|
29
|
+
size: "sm",
|
|
30
|
+
className: PillTrigger_module_default.chevron
|
|
31
|
+
})
|
|
32
|
+
]
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
//#endregion
|
|
36
|
+
export { PillTrigger };
|
|
37
|
+
|
|
38
|
+
//# sourceMappingURL=PillTrigger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PillTrigger.js","names":["AriaButton","styles"],"sources":["../../src/pill-trigger/PillTrigger.tsx"],"sourcesContent":["import { ChevronDown } from 'lucide-react';\nimport type { CSSProperties, ReactNode } from 'react';\nimport { Button as AriaButton, type ButtonProps as AriaButtonProps } from 'react-aria-components';\n\nimport { Icon } from '../icon/Icon';\nimport { cx } from '../utils/cx';\nimport styles from './PillTrigger.module.css';\n\nexport interface PillTriggerProps extends Omit<\n AriaButtonProps,\n 'className' | 'style' | 'children'\n> {\n /** The current value, shown inline. */\n children?: ReactNode;\n /** Leading media, such as an avatar or an image, clipped to a circle by default. */\n media?: ReactNode;\n /** Defaults to `md`, the height of a control. */\n size?: 'sm' | 'md';\n className?: string;\n style?: CSSProperties;\n}\n\n/**\n * A compact rounded button that shows a current value, with an optional leading media and a\n * chevron: the trigger of a `Menu` (in a `MenuTrigger`) or a `Popover` (in a `PopoverTrigger`).\n * Its accessible name is its value: give it an `aria-label` that contains the value when the\n * value alone doesn't say what it picks.\n */\nexport function PillTrigger({\n children,\n media,\n size = 'md',\n className,\n ...props\n}: PillTriggerProps) {\n return (\n <AriaButton\n {...props}\n className={cx(\n 'panneau-pill-trigger',\n styles.pillTrigger,\n size === 'sm' && styles.sm,\n className,\n )}\n >\n {media !== undefined && media !== null ? (\n <span className={styles.media}>{media}</span>\n ) : null}\n <span className={styles.value}>{children}</span>\n <Icon icon={ChevronDown} size=\"sm\" className={styles.chevron} />\n </AriaButton>\n );\n}\n"],"mappings":";;;;;;;;;;;;;AA4BA,SAAgB,YAAY,EACxB,UACA,OACA,OAAO,MACP,WACA,GAAG,SACc;CACjB,OACI,qBAACA,QAAD;EACI,GAAI;EACJ,WAAW,GACP,wBACAC,2BAAO,aACP,SAAS,QAAQA,2BAAO,IACxB,SACJ;EAPJ,UAAA;GASK,UAAU,KAAA,KAAa,UAAU,OAC9B,oBAAC,QAAD;IAAM,WAAWA,2BAAO;IAAQ,UAAA;GAAY,CAAA,IAC5C;GACJ,oBAAC,QAAD;IAAM,WAAWA,2BAAO;IAAQ;GAAe,CAAA;GAC/C,oBAAC,MAAD;IAAM,MAAM;IAAa,MAAK;IAAK,WAAWA,2BAAO;GAAQ,CAAA;EACrD;;AAEpB"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import "./PillTrigger.css";
|
|
2
|
+
//#region src/pill-trigger/PillTrigger.module.css
|
|
3
|
+
var pillTrigger = "panneau-pill-trigger";
|
|
4
|
+
var media = "panneau-pill-trigger-media";
|
|
5
|
+
var sm = "panneau-pill-trigger-sm";
|
|
6
|
+
var value = "panneau-pill-trigger-value";
|
|
7
|
+
var chevron = "panneau-pill-trigger-chevron";
|
|
8
|
+
var PillTrigger_module_default = {
|
|
9
|
+
pillTrigger,
|
|
10
|
+
media,
|
|
11
|
+
sm,
|
|
12
|
+
value,
|
|
13
|
+
chevron
|
|
14
|
+
};
|
|
15
|
+
//#endregion
|
|
16
|
+
export { chevron, PillTrigger_module_default as default, media, pillTrigger, sm, value };
|
|
17
|
+
|
|
18
|
+
//# sourceMappingURL=PillTrigger.module.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PillTrigger.module.js","names":[],"sources":["../../src/pill-trigger/PillTrigger.module.css"],"sourcesContent":["/* A compact rounded button that shows a current value: the trigger of a menu or a popover. */\n\n.pillTrigger {\n display: inline-flex;\n flex: 0 1 auto;\n align-items: center;\n gap: var(--panneau-pill-trigger-gap, var(--panneau-space-2));\n max-width: 100%;\n min-height: var(--panneau-control-height);\n padding: 0 var(--panneau-pill-trigger-padding-x, var(--panneau-space-3));\n font-family: inherit;\n font-size: var(--panneau-pill-trigger-font-size, var(--panneau-font-size-md));\n font-weight: var(--panneau-pill-trigger-font-weight, var(--panneau-font-weight-medium));\n line-height: var(--panneau-line-height-tight);\n color: var(--panneau-pill-trigger-color, var(--panneau-color-text));\n text-align: start;\n white-space: nowrap;\n cursor: pointer;\n user-select: none;\n background-color: var(--panneau-pill-trigger-bg, var(--panneau-color-surface-sunken));\n border: var(--panneau-border-width) solid var(--panneau-pill-trigger-border-color, transparent);\n border-radius: var(--panneau-pill-trigger-radius, var(--panneau-radius-full));\n transition: background-color var(--panneau-duration);\n -webkit-tap-highlight-color: transparent;\n}\n\n.pillTrigger[data-hovered],\n.pillTrigger[data-pressed],\n.pillTrigger[aria-expanded='true'] {\n background-color: var(\n --panneau-pill-trigger-bg-hover,\n color-mix(in srgb, var(--panneau-color-text) 8%, var(--panneau-color-surface-sunken))\n );\n}\n\n.pillTrigger[data-focus-visible] {\n outline: var(--panneau-focus-width) solid var(--panneau-color-focus);\n outline-offset: 2px;\n}\n\n.pillTrigger[data-disabled] {\n cursor: not-allowed;\n opacity: 0.55;\n}\n\n/* With media, the media sits as far from the start as from the top and the bottom. */\n.pillTrigger:has(.media) {\n padding-inline-start: calc(\n (var(--panneau-control-height) - var(--panneau-pill-trigger-media-size, 1.5rem)) / 2 -\n var(--panneau-border-width)\n );\n}\n\n.sm {\n min-height: var(--panneau-control-height-sm);\n padding: 0 var(--panneau-pill-trigger-padding-x-sm, var(--panneau-space-2));\n font-size: var(--panneau-pill-trigger-font-size-sm, var(--panneau-font-size-sm));\n}\n\n.sm:has(.media) {\n padding-inline-start: calc(\n (var(--panneau-control-height-sm) - var(--panneau-pill-trigger-media-size-sm, 1.25rem)) /\n 2 - var(--panneau-border-width)\n );\n}\n\n.media {\n display: inline-flex;\n flex: 0 0 auto;\n align-items: center;\n justify-content: center;\n width: var(--panneau-pill-trigger-media-size, 1.5rem);\n height: var(--panneau-pill-trigger-media-size, 1.5rem);\n overflow: hidden;\n border-radius: var(--panneau-pill-trigger-media-radius, var(--panneau-radius-full));\n}\n\n.sm .media {\n width: var(--panneau-pill-trigger-media-size-sm, 1.25rem);\n height: var(--panneau-pill-trigger-media-size-sm, 1.25rem);\n}\n\n.media > :is(img, svg, video, picture) {\n width: 100%;\n height: 100%;\n object-fit: cover;\n}\n\n.value {\n flex: 0 1 auto;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.chevron {\n flex: 0 0 auto;\n color: var(--panneau-color-text-muted);\n transition: rotate var(--panneau-duration);\n}\n\n.pillTrigger[aria-expanded='true'] .chevron {\n rotate: 180deg;\n}\n"],"mappings":""}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
/** Tokens of PillTrigger. */
|
|
2
|
+
export declare const pillTriggerTokens: import("..").ComponentTokens<"pill-trigger", "panneau-pill-trigger-color" | "panneau-pill-trigger-radius" | "panneau-pill-trigger-gap" | "panneau-pill-trigger-padding-x" | "panneau-pill-trigger-font-size" | "panneau-pill-trigger-font-weight" | "panneau-pill-trigger-padding-x-sm" | "panneau-pill-trigger-font-size-sm" | "panneau-pill-trigger-bg" | "panneau-pill-trigger-border-color" | "panneau-pill-trigger-media-size" | "panneau-pill-trigger-media-radius" | "panneau-pill-trigger-bg-hover" | "panneau-pill-trigger-media-size-sm">;
|
|
3
|
+
//# sourceMappingURL=tokens.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../../src/pill-trigger/tokens.ts"],"names":[],"mappings":"AAEA,6BAA6B;AAC7B,eAAO,MAAM,iBAAiB,qhBA8B5B,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { defineComponentTokens } from "../theme/componentTokens.js";
|
|
2
|
+
//#region src/pill-trigger/tokens.ts
|
|
3
|
+
/** Tokens of PillTrigger. */
|
|
4
|
+
var pillTriggerTokens = defineComponentTokens("pill-trigger", {
|
|
5
|
+
/** Background. */
|
|
6
|
+
bg: "var(--panneau-color-surface-sunken)",
|
|
7
|
+
/** Background of a hovered, pressed or open trigger. */
|
|
8
|
+
"bg-hover": "color-mix(in srgb, var(--panneau-color-text) 8%, var(--panneau-color-surface-sunken))",
|
|
9
|
+
/** Color of the value. */
|
|
10
|
+
color: "var(--panneau-color-text)",
|
|
11
|
+
/** Color of the border: none by default. */
|
|
12
|
+
"border-color": "transparent",
|
|
13
|
+
/** Corner radius. */
|
|
14
|
+
radius: "var(--panneau-radius-full)",
|
|
15
|
+
/** Space between the media, the value and the chevron. */
|
|
16
|
+
gap: "var(--panneau-space-2)",
|
|
17
|
+
/** Horizontal padding. */
|
|
18
|
+
"padding-x": "var(--panneau-space-3)",
|
|
19
|
+
/** Horizontal padding of the small size. */
|
|
20
|
+
"padding-x-sm": "var(--panneau-space-2)",
|
|
21
|
+
/** Font size of the value. */
|
|
22
|
+
"font-size": "var(--panneau-font-size-md)",
|
|
23
|
+
/** Font size of the value, small size. */
|
|
24
|
+
"font-size-sm": "var(--panneau-font-size-sm)",
|
|
25
|
+
/** Font weight of the value. */
|
|
26
|
+
"font-weight": "var(--panneau-font-weight-medium)",
|
|
27
|
+
/** Size of the leading media. */
|
|
28
|
+
"media-size": "1.5rem",
|
|
29
|
+
/** Size of the leading media, small size. */
|
|
30
|
+
"media-size-sm": "1.25rem",
|
|
31
|
+
/** Corner radius of the leading media: its content is clipped to it. */
|
|
32
|
+
"media-radius": "var(--panneau-radius-full)"
|
|
33
|
+
});
|
|
34
|
+
//#endregion
|
|
35
|
+
export { pillTriggerTokens };
|
|
36
|
+
|
|
37
|
+
//# sourceMappingURL=tokens.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tokens.js","names":[],"sources":["../../src/pill-trigger/tokens.ts"],"sourcesContent":["import { defineComponentTokens } from '../theme/componentTokens';\n\n/** Tokens of PillTrigger. */\nexport const pillTriggerTokens = defineComponentTokens('pill-trigger', {\n /** Background. */\n bg: 'var(--panneau-color-surface-sunken)',\n /** Background of a hovered, pressed or open trigger. */\n 'bg-hover':\n 'color-mix(in srgb, var(--panneau-color-text) 8%, var(--panneau-color-surface-sunken))',\n /** Color of the value. */\n color: 'var(--panneau-color-text)',\n /** Color of the border: none by default. */\n 'border-color': 'transparent',\n /** Corner radius. */\n radius: 'var(--panneau-radius-full)',\n /** Space between the media, the value and the chevron. */\n gap: 'var(--panneau-space-2)',\n /** Horizontal padding. */\n 'padding-x': 'var(--panneau-space-3)',\n /** Horizontal padding of the small size. */\n 'padding-x-sm': 'var(--panneau-space-2)',\n /** Font size of the value. */\n 'font-size': 'var(--panneau-font-size-md)',\n /** Font size of the value, small size. */\n 'font-size-sm': 'var(--panneau-font-size-sm)',\n /** Font weight of the value. */\n 'font-weight': 'var(--panneau-font-weight-medium)',\n /** Size of the leading media. */\n 'media-size': '1.5rem',\n /** Size of the leading media, small size. */\n 'media-size-sm': '1.25rem',\n /** Corner radius of the leading media: its content is clipped to it. */\n 'media-radius': 'var(--panneau-radius-full)',\n});\n"],"mappings":";;;AAGA,IAAa,oBAAoB,sBAAsB,gBAAgB;;CAEnE,IAAI;;CAEJ,YACI;;CAEJ,OAAO;;CAEP,gBAAgB;;CAEhB,QAAQ;;CAER,KAAK;;CAEL,aAAa;;CAEb,gBAAgB;;CAEhB,aAAa;;CAEb,gBAAgB;;CAEhB,eAAe;;CAEf,cAAc;;CAEd,iBAAiB;;CAEjB,gBAAgB;AACpB,CAAC"}
|
|
@@ -67,11 +67,101 @@
|
|
|
67
67
|
min-width: 0;
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
+
.panneau-radio-group-option-label {
|
|
71
|
+
overflow-wrap: anywhere;
|
|
72
|
+
}
|
|
73
|
+
|
|
70
74
|
.panneau-radio-group-description {
|
|
71
75
|
font-size: var(--panneau-font-size-sm);
|
|
72
76
|
color: var(--panneau-color-text-muted);
|
|
73
77
|
}
|
|
74
78
|
|
|
79
|
+
/* Leading media of an option, between the radio and the label. */
|
|
80
|
+
.panneau-radio-group-media {
|
|
81
|
+
display: inline-flex;
|
|
82
|
+
flex: 0 0 auto;
|
|
83
|
+
align-items: center;
|
|
84
|
+
justify-content: center;
|
|
85
|
+
width: var(--panneau-radio-media-size, 2rem);
|
|
86
|
+
height: var(--panneau-radio-media-size, 2rem);
|
|
87
|
+
overflow: hidden;
|
|
88
|
+
border-radius: var(--panneau-radio-media-radius, var(--panneau-radius-full));
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.panneau-radio-group-media > :is(img, svg, video, picture) {
|
|
92
|
+
width: 100%;
|
|
93
|
+
height: 100%;
|
|
94
|
+
object-fit: cover;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/*
|
|
98
|
+
* Cards: the options in a grid of --_panneau-radio-group-columns columns, inside a size container
|
|
99
|
+
* of their own, so that they become a single column when the group is narrow, wherever it is.
|
|
100
|
+
*/
|
|
101
|
+
|
|
102
|
+
.panneau-radio-group-grid {
|
|
103
|
+
container-type: inline-size;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.panneau-radio-group-cards .panneau-radio-group-options {
|
|
107
|
+
display: grid;
|
|
108
|
+
grid-template-columns: repeat(var(--_panneau-radio-group-columns, 2), minmax(0, 1fr));
|
|
109
|
+
gap: var(--panneau-radio-card-gap, var(--panneau-space-2));
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
@container (max-width: 28rem) {
|
|
113
|
+
.panneau-radio-group-cards .panneau-radio-group-options {
|
|
114
|
+
grid-template-columns: minmax(0, 1fr);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.panneau-radio-group-card {
|
|
119
|
+
display: flex;
|
|
120
|
+
align-items: center;
|
|
121
|
+
gap: var(--panneau-space-3);
|
|
122
|
+
padding: var(--panneau-radio-card-padding, var(--panneau-space-3));
|
|
123
|
+
background-color: var(--panneau-radio-card-bg, var(--panneau-color-surface));
|
|
124
|
+
border: var(--panneau-border-width) solid
|
|
125
|
+
var(--panneau-radio-card-border-color, var(--panneau-color-border));
|
|
126
|
+
border-radius: var(--panneau-radio-card-radius, var(--panneau-radius-md));
|
|
127
|
+
transition:
|
|
128
|
+
border-color var(--panneau-duration),
|
|
129
|
+
box-shadow var(--panneau-duration);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.panneau-radio-group-card .panneau-radio-group-circle {
|
|
133
|
+
margin-top: 0;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
.panneau-radio-group-card .panneau-radio-group-option-label {
|
|
137
|
+
font-weight: var(--panneau-radio-card-label-font-weight, var(--panneau-font-weight-medium));
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
.panneau-radio-group-card[data-hovered] {
|
|
141
|
+
border-color: var(--panneau-radio-card-border-color-hover, var(--panneau-color-border-control));
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/* The selected card: a border of twice the width, drawn inside so that nothing moves. */
|
|
145
|
+
.panneau-radio-group-card[data-selected] {
|
|
146
|
+
border-color: var(--panneau-radio-card-border-color-selected, var(--panneau-color-accent));
|
|
147
|
+
box-shadow: inset 0 0 0 var(--panneau-border-width)
|
|
148
|
+
var(--panneau-radio-card-border-color-selected, var(--panneau-color-accent));
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
.panneau-radio-group-card[data-invalid] {
|
|
152
|
+
border-color: var(--panneau-color-danger);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/* A card shows the focus ring around itself, instead of around its radio. */
|
|
156
|
+
.panneau-radio-group-card[data-focus-visible] {
|
|
157
|
+
outline: var(--panneau-focus-width) solid var(--panneau-color-focus);
|
|
158
|
+
outline-offset: 2px;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
.panneau-radio-group-card[data-focus-visible] .panneau-radio-group-circle {
|
|
162
|
+
outline: none;
|
|
163
|
+
}
|
|
164
|
+
|
|
75
165
|
@media (pointer: coarse) {
|
|
76
166
|
.panneau-radio-group-radio {
|
|
77
167
|
min-height: 2.75rem;
|
|
@@ -1,12 +1,31 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
1
2
|
import { type RadioGroupProps as AriaRadioGroupProps } from 'react-aria-components';
|
|
2
3
|
import { type FieldChromeProps } from '../field/FieldParts';
|
|
3
4
|
import type { OptionValue, SelectOption } from '../select/Select';
|
|
5
|
+
/** An option of a `RadioGroup`: a `SelectOption`, with an optional leading media. */
|
|
6
|
+
export interface RadioGroupOption extends SelectOption {
|
|
7
|
+
/** Leading media, such as an avatar or an image, between the radio and the label. */
|
|
8
|
+
media?: ReactNode;
|
|
9
|
+
}
|
|
10
|
+
/** How a `RadioGroup` shows its options: a list of radios, or bordered cards in a grid. */
|
|
11
|
+
export type RadioGroupAppearance = 'list' | 'cards';
|
|
4
12
|
export interface RadioGroupProps extends Omit<AriaRadioGroupProps, 'className' | 'style' | 'children' | 'isInvalid' | 'validate' | 'value' | 'defaultValue' | 'onChange'>, FieldChromeProps {
|
|
5
|
-
options: readonly
|
|
13
|
+
options: readonly RadioGroupOption[];
|
|
6
14
|
value?: OptionValue | null;
|
|
7
15
|
onChange?: (value: OptionValue) => void;
|
|
16
|
+
/**
|
|
17
|
+
* `list` (default) shows the options as radios, one under the other or side by side with
|
|
18
|
+
* `orientation="horizontal"`. `cards` shows them as bordered cards in a grid of `columns`, which
|
|
19
|
+
* becomes a single column in a narrow container. The selected card has a stronger border.
|
|
20
|
+
*/
|
|
21
|
+
appearance?: RadioGroupAppearance;
|
|
22
|
+
/** Columns of cards, with `appearance="cards"`. Defaults to 2. */
|
|
23
|
+
columns?: number;
|
|
8
24
|
radioClassName?: string;
|
|
9
25
|
}
|
|
10
|
-
/**
|
|
11
|
-
|
|
26
|
+
/**
|
|
27
|
+
* A set of options where one can be picked, all visible at once, as a list of radios or as cards
|
|
28
|
+
* (`appearance="cards"`). Arrow keys move between options in both appearances.
|
|
29
|
+
*/
|
|
30
|
+
export declare function RadioGroup({ options, value, onChange, label, description, errors, orientation, appearance, columns, isRequired, className, labelClassName, descriptionClassName, errorsClassName, radioClassName, ...props }: RadioGroupProps): import("react").JSX.Element;
|
|
12
31
|
//# sourceMappingURL=RadioGroup.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RadioGroup.d.ts","sourceRoot":"","sources":["../../src/radio-group/RadioGroup.tsx"],"names":[],"mappings":"AAAA,OAAO,EAEH,KAAK,eAAe,IAAI,mBAAmB,EAE9C,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EACH,KAAK,gBAAgB,EAKxB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAIlE,MAAM,WAAW,eACb,SACI,IAAI,CACA,mBAAmB,EACjB,WAAW,GACX,OAAO,GACP,UAAU,GACV,WAAW,GACX,UAAU,GACV,OAAO,GACP,cAAc,GACd,UAAU,CACf,EACD,gBAAgB;IACpB,OAAO,EAAE,SAAS,
|
|
1
|
+
{"version":3,"file":"RadioGroup.d.ts","sourceRoot":"","sources":["../../src/radio-group/RadioGroup.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAiB,SAAS,EAAE,MAAM,OAAO,CAAC;AACtD,OAAO,EAEH,KAAK,eAAe,IAAI,mBAAmB,EAE9C,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EACH,KAAK,gBAAgB,EAKxB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAIlE,qFAAqF;AACrF,MAAM,WAAW,gBAAiB,SAAQ,YAAY;IAClD,qFAAqF;IACrF,KAAK,CAAC,EAAE,SAAS,CAAC;CACrB;AAED,2FAA2F;AAC3F,MAAM,MAAM,oBAAoB,GAAG,MAAM,GAAG,OAAO,CAAC;AAEpD,MAAM,WAAW,eACb,SACI,IAAI,CACA,mBAAmB,EACjB,WAAW,GACX,OAAO,GACP,UAAU,GACV,WAAW,GACX,UAAU,GACV,OAAO,GACP,cAAc,GACd,UAAU,CACf,EACD,gBAAgB;IACpB,OAAO,EAAE,SAAS,gBAAgB,EAAE,CAAC;IACrC,KAAK,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;IAC3B,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC;IACxC;;;;OAIG;IACH,UAAU,CAAC,EAAE,oBAAoB,CAAC;IAClC,kEAAkE;IAClE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,EACvB,OAAO,EACP,KAAK,EACL,QAAQ,EACR,KAAK,EACL,WAAW,EACX,MAAW,EACX,WAAwB,EACxB,UAAmB,EACnB,OAAW,EACX,UAAU,EACV,SAAS,EACT,cAAc,EACd,oBAAoB,EACpB,eAAe,EACf,cAAc,EACd,GAAG,KAAK,EACX,EAAE,eAAe,+BA0EjB"}
|
|
@@ -5,8 +5,36 @@ import RadioGroup_module_default from "./RadioGroup.module.js";
|
|
|
5
5
|
import { Radio, RadioGroup } from "react-aria-components";
|
|
6
6
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
7
|
//#region src/radio-group/RadioGroup.tsx
|
|
8
|
-
/**
|
|
9
|
-
|
|
8
|
+
/**
|
|
9
|
+
* A set of options where one can be picked, all visible at once, as a list of radios or as cards
|
|
10
|
+
* (`appearance="cards"`). Arrow keys move between options in both appearances.
|
|
11
|
+
*/
|
|
12
|
+
function RadioGroup$1({ options, value, onChange, label, description, errors = [], orientation = "vertical", appearance = "list", columns = 2, isRequired, className, labelClassName, descriptionClassName, errorsClassName, radioClassName, ...props }) {
|
|
13
|
+
const radios = options.map((option, position) => /* @__PURE__ */ jsxs(Radio, {
|
|
14
|
+
value: String(position),
|
|
15
|
+
isDisabled: option.disabled,
|
|
16
|
+
className: cx("panneau-radio", RadioGroup_module_default.radio, appearance === "cards" && RadioGroup_module_default.card, radioClassName),
|
|
17
|
+
children: [
|
|
18
|
+
/* @__PURE__ */ jsx("span", {
|
|
19
|
+
className: RadioGroup_module_default.circle,
|
|
20
|
+
"aria-hidden": "true"
|
|
21
|
+
}),
|
|
22
|
+
option.media !== void 0 && option.media !== null ? /* @__PURE__ */ jsx("span", {
|
|
23
|
+
className: RadioGroup_module_default.media,
|
|
24
|
+
children: option.media
|
|
25
|
+
}) : null,
|
|
26
|
+
/* @__PURE__ */ jsxs("span", {
|
|
27
|
+
className: RadioGroup_module_default.text,
|
|
28
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
29
|
+
className: RadioGroup_module_default.optionLabel,
|
|
30
|
+
children: option.label
|
|
31
|
+
}), option.description !== void 0 ? /* @__PURE__ */ jsx("span", {
|
|
32
|
+
className: RadioGroup_module_default.description,
|
|
33
|
+
children: option.description
|
|
34
|
+
}) : null]
|
|
35
|
+
})
|
|
36
|
+
]
|
|
37
|
+
}, position));
|
|
10
38
|
const index = value === void 0 ? void 0 : options.findIndex((o) => o.value === value);
|
|
11
39
|
return /* @__PURE__ */ jsxs(RadioGroup, {
|
|
12
40
|
...props,
|
|
@@ -14,35 +42,28 @@ function RadioGroup$1({ options, value, onChange, label, description, errors = [
|
|
|
14
42
|
isRequired,
|
|
15
43
|
value: index === void 0 ? void 0 : index === -1 ? null : String(index),
|
|
16
44
|
onChange: (key) => {
|
|
17
|
-
const
|
|
18
|
-
if (
|
|
45
|
+
const option_0 = options[Number(key)];
|
|
46
|
+
if (option_0 !== void 0) onChange?.(option_0.value);
|
|
19
47
|
},
|
|
20
48
|
isInvalid: errors.length > 0,
|
|
21
49
|
validationBehavior: "aria",
|
|
22
|
-
className: cx("panneau-radio-group", Field_module_default.field, orientation === "horizontal" && RadioGroup_module_default.horizontal, className),
|
|
50
|
+
className: cx("panneau-radio-group", Field_module_default.field, appearance === "cards" ? RadioGroup_module_default.cards : orientation === "horizontal" && RadioGroup_module_default.horizontal, className),
|
|
23
51
|
children: [
|
|
24
52
|
/* @__PURE__ */ jsx(FieldLabel, {
|
|
25
53
|
isRequired,
|
|
26
54
|
className: labelClassName,
|
|
27
55
|
children: label
|
|
28
56
|
}),
|
|
29
|
-
/* @__PURE__ */ jsx("div", {
|
|
57
|
+
appearance === "cards" ? /* @__PURE__ */ jsx("div", {
|
|
58
|
+
className: RadioGroup_module_default.grid,
|
|
59
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
60
|
+
className: RadioGroup_module_default.options,
|
|
61
|
+
style: { "--_panneau-radio-group-columns": String(Math.max(1, Math.floor(columns))) },
|
|
62
|
+
children: radios
|
|
63
|
+
})
|
|
64
|
+
}) : /* @__PURE__ */ jsx("div", {
|
|
30
65
|
className: RadioGroup_module_default.options,
|
|
31
|
-
children:
|
|
32
|
-
value: String(position),
|
|
33
|
-
isDisabled: option_0.disabled,
|
|
34
|
-
className: cx("panneau-radio", RadioGroup_module_default.radio, radioClassName),
|
|
35
|
-
children: [/* @__PURE__ */ jsx("span", {
|
|
36
|
-
className: RadioGroup_module_default.circle,
|
|
37
|
-
"aria-hidden": "true"
|
|
38
|
-
}), /* @__PURE__ */ jsxs("span", {
|
|
39
|
-
className: RadioGroup_module_default.text,
|
|
40
|
-
children: [/* @__PURE__ */ jsx("span", { children: option_0.label }), option_0.description !== void 0 ? /* @__PURE__ */ jsx("span", {
|
|
41
|
-
className: RadioGroup_module_default.description,
|
|
42
|
-
children: option_0.description
|
|
43
|
-
}) : null]
|
|
44
|
-
})]
|
|
45
|
-
}, position))
|
|
66
|
+
children: radios
|
|
46
67
|
}),
|
|
47
68
|
/* @__PURE__ */ jsx(FieldDescription, {
|
|
48
69
|
className: descriptionClassName,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RadioGroup.js","names":["option","RadioGroup","
|
|
1
|
+
{"version":3,"file":"RadioGroup.js","names":["option","RadioGroup","styles","AriaRadioGroup","fieldStyles"],"sources":["../../src/radio-group/RadioGroup.tsx"],"sourcesContent":["import type { CSSProperties, ReactNode } from 'react';\nimport {\n RadioGroup as AriaRadioGroup,\n type RadioGroupProps as AriaRadioGroupProps,\n Radio,\n} from 'react-aria-components';\n\nimport {\n type FieldChromeProps,\n FieldDescription,\n FieldErrors,\n FieldLabel,\n fieldStyles,\n} from '../field/FieldParts';\nimport type { OptionValue, SelectOption } from '../select/Select';\nimport { cx } from '../utils/cx';\nimport styles from './RadioGroup.module.css';\n\n/** An option of a `RadioGroup`: a `SelectOption`, with an optional leading media. */\nexport interface RadioGroupOption extends SelectOption {\n /** Leading media, such as an avatar or an image, between the radio and the label. */\n media?: ReactNode;\n}\n\n/** How a `RadioGroup` shows its options: a list of radios, or bordered cards in a grid. */\nexport type RadioGroupAppearance = 'list' | 'cards';\n\nexport interface RadioGroupProps\n extends\n Omit<\n AriaRadioGroupProps,\n | 'className'\n | 'style'\n | 'children'\n | 'isInvalid'\n | 'validate'\n | 'value'\n | 'defaultValue'\n | 'onChange'\n >,\n FieldChromeProps {\n options: readonly RadioGroupOption[];\n value?: OptionValue | null;\n onChange?: (value: OptionValue) => void;\n /**\n * `list` (default) shows the options as radios, one under the other or side by side with\n * `orientation=\"horizontal\"`. `cards` shows them as bordered cards in a grid of `columns`, which\n * becomes a single column in a narrow container. The selected card has a stronger border.\n */\n appearance?: RadioGroupAppearance;\n /** Columns of cards, with `appearance=\"cards\"`. Defaults to 2. */\n columns?: number;\n radioClassName?: string;\n}\n\n/**\n * A set of options where one can be picked, all visible at once, as a list of radios or as cards\n * (`appearance=\"cards\"`). Arrow keys move between options in both appearances.\n */\nexport function RadioGroup({\n options,\n value,\n onChange,\n label,\n description,\n errors = [],\n orientation = 'vertical',\n appearance = 'list',\n columns = 2,\n isRequired,\n className,\n labelClassName,\n descriptionClassName,\n errorsClassName,\n radioClassName,\n ...props\n}: RadioGroupProps) {\n const radios = options.map((option, position) => (\n <Radio\n key={position}\n value={String(position)}\n isDisabled={option.disabled}\n className={cx(\n 'panneau-radio',\n styles.radio,\n appearance === 'cards' && styles.card,\n radioClassName,\n )}\n >\n <span className={styles.circle} aria-hidden=\"true\" />\n {option.media !== undefined && option.media !== null ? (\n <span className={styles.media}>{option.media}</span>\n ) : null}\n <span className={styles.text}>\n <span className={styles.optionLabel}>{option.label}</span>\n {option.description !== undefined ? (\n <span className={styles.description}>{option.description}</span>\n ) : null}\n </span>\n </Radio>\n ));\n const index = value === undefined ? undefined : options.findIndex((o) => o.value === value);\n return (\n <AriaRadioGroup\n {...props}\n orientation={orientation}\n isRequired={isRequired}\n value={index === undefined ? undefined : index === -1 ? null : String(index)}\n onChange={(key) => {\n const option = options[Number(key)];\n if (option !== undefined) {\n onChange?.(option.value);\n }\n }}\n isInvalid={errors.length > 0}\n validationBehavior=\"aria\"\n className={cx(\n 'panneau-radio-group',\n fieldStyles.field,\n appearance === 'cards'\n ? styles.cards\n : orientation === 'horizontal' && styles.horizontal,\n className,\n )}\n >\n <FieldLabel isRequired={isRequired} className={labelClassName}>\n {label}\n </FieldLabel>\n {appearance === 'cards' ? (\n <div className={styles.grid}>\n <div\n className={styles.options}\n style={\n {\n '--_panneau-radio-group-columns': String(\n Math.max(1, Math.floor(columns)),\n ),\n } as CSSProperties\n }\n >\n {radios}\n </div>\n </div>\n ) : (\n <div className={styles.options}>{radios}</div>\n )}\n <FieldDescription className={descriptionClassName}>{description}</FieldDescription>\n <FieldErrors errors={errors} className={errorsClassName} />\n </AriaRadioGroup>\n );\n}\n"],"mappings":";;;;;;;;;;;AA2DA,SAAgBC,aAAW,EACvB,SACA,OACA,UACA,OACA,aACA,SAAS,CAAA,GACT,cAAc,YACd,aAAa,QACb,UAAU,GACV,YACA,WACA,gBACA,sBACA,iBACA,gBACA,GAAG,SACa;CAChB,MAAM,SAAS,QAAQ,KAAK,QAAQ,aAChC,qBAAC,OAAD;EAEI,OAAO,OAAO,QAAQ;EACtB,YAAY,OAAO;EACnB,WAAW,GACP,iBACAC,0BAAO,OACP,eAAe,WAAWA,0BAAO,MACjC,cACJ;EATJ,UAAA;GAWI,oBAAC,QAAD;IAAM,WAAWA,0BAAO;IAAQ,eAAY;GAAM,CAAA;GACjD,OAAO,UAAU,KAAA,KAAa,OAAO,UAAU,OAC5C,oBAAC,QAAD;IAAM,WAAWA,0BAAO;IAAQ,UAAA,OAAO;GAAY,CAAA,IACnD;GACJ,qBAAC,QAAD;IAAM,WAAWA,0BAAO;IAAxB,UAAA,CACI,oBAAC,QAAD;KAAM,WAAWA,0BAAO;KAAc,UAAA,OAAO;IAAY,CAAA,GACxD,OAAO,gBAAgB,KAAA,IACpB,oBAAC,QAAD;KAAM,WAAWA,0BAAO;KAAc,UAAA,OAAO;IAAkB,CAAA,IAC/D,IACF;;EACH;CApBE,GAAA,QAoBF,CACV;CACD,MAAM,QAAQ,UAAU,KAAA,IAAY,KAAA,IAAY,QAAQ,WAAW,MAAM,EAAE,UAAU,KAAK;CAC1F,OACI,qBAACC,YAAD;EACI,GAAI;EACS;EACD;EACZ,OAAO,UAAU,KAAA,IAAY,KAAA,IAAY,UAAU,KAAK,OAAO,OAAO,KAAK;EAC3E,WAAW,QAAQ;GACf,MAAMH,WAAS,QAAQ,OAAO,GAAG;GACjC,IAAIA,aAAW,KAAA,GACX,WAAWA,SAAO,KAAK;EAE/B;EACA,WAAW,OAAO,SAAS;EAC3B,oBAAmB;EACnB,WAAW,GACP,uBACAI,qBAAY,OACZ,eAAe,UACTF,0BAAO,QACP,gBAAgB,gBAAgBA,0BAAO,YAC7C,SACJ;EApBJ,UAAA;GAsBI,oBAAC,YAAD;IAAwB;IAAY,WAAW;IAC1C,UAAA;GACO,CAAA;GACX,eAAe,UACZ,oBAAC,OAAD;IAAK,WAAWA,0BAAO;IACnB,UAAA,oBAAC,OAAD;KACI,WAAWA,0BAAO;KAClB,OACI,EACI,kCAAkC,OAC9B,KAAK,IAAI,GAAG,KAAK,MAAM,OAAO,CAAC,CACnC,EACJ;KAGH,UAAA;IACA,CAAA;GACJ,CAAA,IAEL,oBAAC,OAAD;IAAK,WAAWA,0BAAO;IAAU,UAAA;GAAY,CAAA;GAEjD,oBAAC,kBAAD;IAAkB,WAAW;IAAuB,UAAA;GAA8B,CAAA;GAClF,oBAAC,aAAD;IAAqB;IAAQ,WAAW;GAAgB,CAAA;EAC5C;;AAExB"}
|
|
@@ -5,16 +5,26 @@ var horizontal = "panneau-radio-group-horizontal";
|
|
|
5
5
|
var radio = "panneau-radio-group-radio";
|
|
6
6
|
var circle = "panneau-radio-group-circle";
|
|
7
7
|
var text = "panneau-radio-group-text";
|
|
8
|
+
var optionLabel = "panneau-radio-group-option-label";
|
|
8
9
|
var description = "panneau-radio-group-description";
|
|
10
|
+
var media = "panneau-radio-group-media";
|
|
11
|
+
var grid = "panneau-radio-group-grid";
|
|
12
|
+
var cards = "panneau-radio-group-cards";
|
|
13
|
+
var card = "panneau-radio-group-card";
|
|
9
14
|
var RadioGroup_module_default = {
|
|
10
15
|
options,
|
|
11
16
|
horizontal,
|
|
12
17
|
radio,
|
|
13
18
|
circle,
|
|
14
19
|
text,
|
|
15
|
-
|
|
20
|
+
optionLabel,
|
|
21
|
+
description,
|
|
22
|
+
media,
|
|
23
|
+
grid,
|
|
24
|
+
cards,
|
|
25
|
+
card
|
|
16
26
|
};
|
|
17
27
|
//#endregion
|
|
18
|
-
export { circle, RadioGroup_module_default as default, description, horizontal, options, radio, text };
|
|
28
|
+
export { card, cards, circle, RadioGroup_module_default as default, description, grid, horizontal, media, optionLabel, options, radio, text };
|
|
19
29
|
|
|
20
30
|
//# sourceMappingURL=RadioGroup.module.js.map
|