@robr0/design-system 0.1.0 → 0.3.0
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 +13 -9
- package/components/Accordion/Accordion.js +0 -1
- package/components/Avatar/Avatar.js +1 -0
- package/components/Breadcrumb/Breadcrumb.css +9 -1
- package/components/Breadcrumb/Breadcrumb.d.ts +7 -1
- package/components/Breadcrumb/Breadcrumb.js +3 -2
- package/components/Button/Button.css +18 -0
- package/components/Button/Button.d.ts +38 -16
- package/components/Button/Button.js +76 -58
- package/components/Card/Card.css +6 -0
- package/components/Card/Card.d.ts +17 -5
- package/components/Card/Card.js +101 -80
- package/components/Checkbox/Checkbox.d.ts +24 -12
- package/components/Checkbox/Checkbox.js +99 -85
- package/components/CircularButton/CircularButton.css +11 -0
- package/components/CircularButton/CircularButton.d.ts +7 -1
- package/components/CircularButton/CircularButton.js +15 -4
- package/components/CodeBlock/CodeBlock.js +10 -1
- package/components/ColorPicker/ColorPicker.css +278 -0
- package/components/ColorPicker/ColorPicker.d.ts +50 -0
- package/components/ColorPicker/ColorPicker.js +338 -0
- package/components/Combobox/Combobox.css +0 -36
- package/components/Combobox/Combobox.d.ts +19 -7
- package/components/Combobox/Combobox.js +106 -89
- package/components/CommandPalette/CommandPalette.css +1 -15
- package/components/CommandPalette/CommandPalette.js +6 -5
- package/components/ContextMenu/ContextMenu.css +262 -0
- package/components/ContextMenu/ContextMenu.d.ts +26 -0
- package/components/ContextMenu/ContextMenu.js +350 -0
- package/components/DateInput/DateInput.css +0 -36
- package/components/DateInput/DateInput.d.ts +18 -21
- package/components/DateInput/DateInput.js +76 -64
- package/components/DatePicker/DatePicker.d.ts +9 -2
- package/components/DatePicker/DatePicker.js +137 -128
- package/components/Dialog/Dialog.d.ts +15 -4
- package/components/Dialog/Dialog.js +136 -118
- package/components/Drawer/Drawer.d.ts +15 -4
- package/components/Drawer/Drawer.js +138 -119
- package/components/Dropdown/Dropdown.css +0 -36
- package/components/Dropdown/Dropdown.d.ts +24 -8
- package/components/Dropdown/Dropdown.js +219 -169
- package/components/DropdownMenu/DropdownMenu.js +10 -7
- package/components/Field/Field.css +80 -0
- package/components/Field/Field.d.ts +50 -0
- package/components/Field/Field.js +58 -0
- package/components/Field/FieldContext.d.ts +42 -0
- package/components/Field/FieldContext.js +7 -0
- package/components/FileInput/FileInput.css +0 -36
- package/components/FileInput/FileInput.d.ts +13 -17
- package/components/FileInput/FileInput.js +168 -141
- package/components/Input/Input.css +0 -43
- package/components/Input/Input.d.ts +23 -22
- package/components/Input/Input.js +93 -66
- package/components/Kbd/Kbd.css +28 -0
- package/components/Kbd/Kbd.d.ts +19 -0
- package/components/Kbd/Kbd.js +14 -0
- package/components/Popover/Popover.d.ts +0 -6
- package/components/Popover/Popover.js +22 -16
- package/components/ProgressBar/ProgressBar.js +1 -1
- package/components/RadioButton/RadioButton.d.ts +26 -13
- package/components/RadioButton/RadioButton.js +95 -70
- package/components/SelectionCard/SelectionCard.css +6 -2
- package/components/SelectionCard/SelectionCard.d.ts +10 -4
- package/components/SelectionCard/SelectionCard.js +72 -56
- package/components/Skeleton/Skeleton.css +2 -0
- package/components/Slider/Slider.d.ts +19 -10
- package/components/Slider/Slider.js +50 -40
- package/components/Spinner/Spinner.css +11 -0
- package/components/Spinner/Spinner.d.ts +2 -2
- package/components/Swatch/Swatch.css +52 -0
- package/components/Swatch/Swatch.d.ts +34 -0
- package/components/Swatch/Swatch.js +44 -0
- package/components/Table/Table.css +19 -0
- package/components/Table/Table.d.ts +10 -2
- package/components/Table/Table.js +58 -58
- package/components/Textarea/Textarea.css +0 -43
- package/components/Textarea/Textarea.d.ts +21 -22
- package/components/Textarea/Textarea.js +78 -67
- package/components/ToggleGroup/ToggleGroup.d.ts +18 -8
- package/components/ToggleGroup/ToggleGroup.js +61 -44
- package/components/ToggleSwitch/ToggleSwitch.css +7 -2
- package/components/ToggleSwitch/ToggleSwitch.d.ts +17 -9
- package/components/ToggleSwitch/ToggleSwitch.js +57 -44
- package/components/registry.d.ts +47 -10
- package/components/registry.js +5 -1
- package/components/registry.json +498 -56
- package/components/registry.json.d.ts +498 -56
- package/components/registry.json.js +4 -1
- package/index.d.ts +8 -1
- package/index.js +16 -1
- package/package.json +1 -1
|
@@ -1,71 +1,98 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import "react";
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { Field } from "../Field/Field.js";
|
|
3
4
|
import "./Input.css";
|
|
4
5
|
import "../../fonts/material-symbols.css";
|
|
5
|
-
const Input = (
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
6
|
+
const Input = React.forwardRef(
|
|
7
|
+
({
|
|
8
|
+
label,
|
|
9
|
+
placeholder = "",
|
|
10
|
+
value,
|
|
11
|
+
type = "text",
|
|
12
|
+
size = "default",
|
|
13
|
+
disabled = false,
|
|
14
|
+
required = false,
|
|
15
|
+
error = false,
|
|
16
|
+
helperText,
|
|
17
|
+
iconLeft,
|
|
18
|
+
iconRight,
|
|
19
|
+
onChange,
|
|
20
|
+
onValueChange,
|
|
21
|
+
className = "",
|
|
22
|
+
ariaLabel,
|
|
23
|
+
name,
|
|
24
|
+
id,
|
|
25
|
+
...rest
|
|
26
|
+
}, ref) => {
|
|
27
|
+
const baseClass = "ds-input";
|
|
28
|
+
const classes = [
|
|
29
|
+
baseClass,
|
|
30
|
+
size === "compact" ? `${baseClass}--compact` : "",
|
|
31
|
+
error ? `${baseClass}--error` : "",
|
|
32
|
+
disabled ? `${baseClass}--disabled` : "",
|
|
33
|
+
iconLeft ? `${baseClass}--has-icon-left` : "",
|
|
34
|
+
iconRight ? `${baseClass}--has-icon-right` : "",
|
|
35
|
+
className
|
|
36
|
+
].filter(Boolean).join(" ");
|
|
37
|
+
const handleChange = (e) => {
|
|
38
|
+
onChange?.(e);
|
|
39
|
+
onValueChange?.(e.target.value);
|
|
40
|
+
};
|
|
41
|
+
const inputId = id || name || label?.toLowerCase().replace(/\s+/g, "-");
|
|
42
|
+
const describedBy = helperText ? `${inputId}-helper` : rest["aria-describedby"];
|
|
43
|
+
return /* @__PURE__ */ jsx(
|
|
44
|
+
Field,
|
|
45
|
+
{
|
|
46
|
+
className: classes,
|
|
47
|
+
label,
|
|
48
|
+
helperText,
|
|
49
|
+
error,
|
|
50
|
+
required,
|
|
51
|
+
disabled,
|
|
52
|
+
size,
|
|
53
|
+
id: inputId,
|
|
54
|
+
children: /* @__PURE__ */ jsxs("div", { className: `${baseClass}__field-wrapper`, children: [
|
|
55
|
+
iconLeft && /* @__PURE__ */ jsx(
|
|
56
|
+
"span",
|
|
57
|
+
{
|
|
58
|
+
className: `${baseClass}__icon ${baseClass}__icon--left material-symbols-rounded`,
|
|
59
|
+
"aria-hidden": "true",
|
|
60
|
+
children: iconLeft
|
|
61
|
+
}
|
|
62
|
+
),
|
|
63
|
+
/* @__PURE__ */ jsx(
|
|
64
|
+
"input",
|
|
65
|
+
{
|
|
66
|
+
...rest,
|
|
67
|
+
ref,
|
|
68
|
+
className: `${baseClass}__field`,
|
|
69
|
+
type,
|
|
70
|
+
id: inputId,
|
|
71
|
+
name,
|
|
72
|
+
value,
|
|
73
|
+
placeholder,
|
|
74
|
+
disabled,
|
|
75
|
+
required,
|
|
76
|
+
"aria-label": ariaLabel || rest["aria-label"] || label,
|
|
77
|
+
"aria-invalid": error,
|
|
78
|
+
"aria-describedby": describedBy,
|
|
79
|
+
onChange: handleChange
|
|
80
|
+
}
|
|
81
|
+
),
|
|
82
|
+
iconRight && /* @__PURE__ */ jsx(
|
|
83
|
+
"span",
|
|
84
|
+
{
|
|
85
|
+
className: `${baseClass}__icon ${baseClass}__icon--right material-symbols-rounded`,
|
|
86
|
+
"aria-hidden": "true",
|
|
87
|
+
children: iconRight
|
|
88
|
+
}
|
|
89
|
+
)
|
|
90
|
+
] })
|
|
91
|
+
}
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
);
|
|
95
|
+
Input.displayName = "Input";
|
|
69
96
|
export {
|
|
70
97
|
Input
|
|
71
98
|
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/* ============================================
|
|
2
|
+
KBD COMPONENT
|
|
3
|
+
A single keyboard key rendered as a keycap
|
|
4
|
+
============================================ */
|
|
5
|
+
|
|
6
|
+
/* Base */
|
|
7
|
+
.ds-kbd {
|
|
8
|
+
display: inline-flex;
|
|
9
|
+
align-items: center;
|
|
10
|
+
justify-content: center;
|
|
11
|
+
min-width: 24px;
|
|
12
|
+
padding: var(--padding-xxxs) var(--padding-xs);
|
|
13
|
+
border: var(--border-xs) solid var(--color-bg-container-border);
|
|
14
|
+
border-radius: var(--radius-xs);
|
|
15
|
+
background-color: var(--color-bg-container-primary);
|
|
16
|
+
font-family: var(--font-paragraph-sm-family);
|
|
17
|
+
font-size: var(--font-paragraph-sm-size);
|
|
18
|
+
font-weight: var(--font-paragraph-sm-em-weight);
|
|
19
|
+
line-height: var(--font-paragraph-sm-line-height);
|
|
20
|
+
color: var(--color-text-tertiary);
|
|
21
|
+
white-space: nowrap;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/* Sizes */
|
|
25
|
+
.ds-kbd--compact {
|
|
26
|
+
min-width: 20px;
|
|
27
|
+
padding: var(--padding-xxxs) var(--padding-xxs);
|
|
28
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
/** Props owned by Kbd itself — everything else falls through to the <kbd> element. */
|
|
3
|
+
type KbdOwnProps = {
|
|
4
|
+
/** Key size */
|
|
5
|
+
size?: 'default' | 'compact';
|
|
6
|
+
/** Additional CSS classes */
|
|
7
|
+
className?: string;
|
|
8
|
+
/** The key legend — e.g. ⌘, K, Esc, Shift */
|
|
9
|
+
children?: React.ReactNode;
|
|
10
|
+
};
|
|
11
|
+
export interface KbdProps extends KbdOwnProps, Omit<React.ComponentPropsWithoutRef<'kbd'>, keyof KbdOwnProps> {
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Kbd renders a single keyboard key as a keycap, for shortcut hints in
|
|
15
|
+
* menus and docs prose. Compose several for a chord: `<Kbd>⌘</Kbd><Kbd>K</Kbd>`.
|
|
16
|
+
* Purely presentational — safe to render from a Server Component.
|
|
17
|
+
*/
|
|
18
|
+
export declare const Kbd: React.ForwardRefExoticComponent<KbdProps & React.RefAttributes<HTMLElement>>;
|
|
19
|
+
export {};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import "./Kbd.css";
|
|
4
|
+
const Kbd = React.forwardRef(
|
|
5
|
+
({ size = "default", className = "", children, ...rest }, ref) => {
|
|
6
|
+
const baseClass = "ds-kbd";
|
|
7
|
+
const classes = [baseClass, `${baseClass}--${size}`, className].filter(Boolean).join(" ");
|
|
8
|
+
return /* @__PURE__ */ jsx("kbd", { ...rest, ref, className: classes, children });
|
|
9
|
+
}
|
|
10
|
+
);
|
|
11
|
+
Kbd.displayName = "Kbd";
|
|
12
|
+
export {
|
|
13
|
+
Kbd
|
|
14
|
+
};
|
|
@@ -19,10 +19,4 @@ export interface PopoverProps {
|
|
|
19
19
|
/** Additional CSS classes for the popover panel */
|
|
20
20
|
className?: string;
|
|
21
21
|
}
|
|
22
|
-
/**
|
|
23
|
-
* Popover component for contextual overlays.
|
|
24
|
-
* Wraps a trigger element and displays content in a
|
|
25
|
-
* positioned panel. Supports click and hover triggers
|
|
26
|
-
* with automatic outside-click dismissal.
|
|
27
|
-
*/
|
|
28
22
|
export declare const Popover: ({ children, content, size, position, trigger, open: controlledOpen, onOpenChange, ariaLabel, className, }: PopoverProps) => React.JSX.Element;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
|
-
import { useState, useRef, useCallback, useEffect } from "react";
|
|
2
|
+
import React, { useState, useRef, useCallback, useEffect } from "react";
|
|
3
3
|
import "./Popover.css";
|
|
4
|
+
const INTERACTIVE_TAGS = /* @__PURE__ */ new Set(["button", "a", "input", "select", "textarea", "summary"]);
|
|
5
|
+
const canCarryPopoverSemantics = (el) => typeof el.type === "string" ? INTERACTIVE_TAGS.has(el.type) : true;
|
|
4
6
|
const Popover = ({
|
|
5
7
|
children,
|
|
6
8
|
content,
|
|
@@ -73,26 +75,30 @@ const Popover = ({
|
|
|
73
75
|
onMouseEnter: handleMouseEnter,
|
|
74
76
|
onMouseLeave: handleMouseLeave,
|
|
75
77
|
children: [
|
|
76
|
-
/* @__PURE__ */ jsx(
|
|
77
|
-
"
|
|
78
|
+
/* @__PURE__ */ jsx("div", { className: `${baseClass}__trigger`, onClick: handleClick, children: React.isValidElement(children) && canCarryPopoverSemantics(children) ? React.cloneElement(children, {
|
|
79
|
+
"aria-expanded": isOpen,
|
|
80
|
+
"aria-haspopup": "dialog",
|
|
81
|
+
...ariaLabel ? { "aria-label": ariaLabel } : {}
|
|
82
|
+
}) : trigger === "click" ? /* @__PURE__ */ jsx(
|
|
83
|
+
"button",
|
|
78
84
|
{
|
|
79
|
-
|
|
80
|
-
onClick: handleClick,
|
|
81
|
-
role: trigger === "click" ? "button" : void 0,
|
|
82
|
-
tabIndex: trigger === "click" ? 0 : void 0,
|
|
85
|
+
type: "button",
|
|
83
86
|
"aria-expanded": isOpen,
|
|
84
|
-
"aria-label": ariaLabel,
|
|
85
87
|
"aria-haspopup": "dialog",
|
|
86
|
-
|
|
87
|
-
if (trigger === "click" && (e.key === "Enter" || e.key === " ")) {
|
|
88
|
-
e.preventDefault();
|
|
89
|
-
setOpen(!isOpen);
|
|
90
|
-
}
|
|
91
|
-
},
|
|
88
|
+
"aria-label": ariaLabel,
|
|
92
89
|
children
|
|
93
90
|
}
|
|
94
|
-
),
|
|
95
|
-
/* @__PURE__ */ jsx(
|
|
91
|
+
) : children }),
|
|
92
|
+
/* @__PURE__ */ jsx(
|
|
93
|
+
"div",
|
|
94
|
+
{
|
|
95
|
+
className: panelClasses,
|
|
96
|
+
role: "dialog",
|
|
97
|
+
"aria-label": ariaLabel || "Popover",
|
|
98
|
+
"aria-hidden": !isOpen,
|
|
99
|
+
children: content
|
|
100
|
+
}
|
|
101
|
+
)
|
|
96
102
|
]
|
|
97
103
|
}
|
|
98
104
|
);
|
|
@@ -14,7 +14,7 @@ const ProgressBar = ({
|
|
|
14
14
|
`${baseClass}--${size}`,
|
|
15
15
|
className
|
|
16
16
|
].filter(Boolean).join(" ");
|
|
17
|
-
return /* @__PURE__ */ jsxs("div", { className: classes, role: "progressbar", "aria-valuenow": clamped, "aria-valuemin": 0, "aria-valuemax": 100, "aria-label": ariaLabel, children: [
|
|
17
|
+
return /* @__PURE__ */ jsxs("div", { className: classes, role: "progressbar", "aria-valuenow": clamped, "aria-valuemin": 0, "aria-valuemax": 100, "aria-label": ariaLabel || "Progress", children: [
|
|
18
18
|
/* @__PURE__ */ jsx("div", { className: `${baseClass}__track`, children: /* @__PURE__ */ jsx("div", { className: `${baseClass}__fill`, style: { width: `${clamped}%` } }) }),
|
|
19
19
|
showLabel && /* @__PURE__ */ jsxs("span", { className: `${baseClass}__label`, children: [
|
|
20
20
|
clamped,
|
|
@@ -1,26 +1,34 @@
|
|
|
1
1
|
import { default as React } from 'react';
|
|
2
|
-
|
|
2
|
+
/** Props owned by RadioButton itself — everything else falls through to the wrapper. */
|
|
3
|
+
type RadioButtonOwnProps = {
|
|
3
4
|
/** Label text */
|
|
4
5
|
label?: string;
|
|
5
6
|
/** Whether this radio is selected */
|
|
6
7
|
checked?: boolean;
|
|
7
8
|
/** Whether the radio is disabled */
|
|
8
9
|
disabled?: boolean;
|
|
9
|
-
/** Radio group name — groups radios together */
|
|
10
|
-
name?: string;
|
|
11
10
|
/** Value for this radio option */
|
|
12
11
|
value?: string;
|
|
13
|
-
/**
|
|
14
|
-
|
|
12
|
+
/** Called with this radio's value when selected */
|
|
13
|
+
onValueChange?: (value: string) => void;
|
|
15
14
|
/** Additional CSS classes */
|
|
16
15
|
className?: string;
|
|
17
|
-
/**
|
|
16
|
+
/** @deprecated Use `onValueChange` instead. */
|
|
17
|
+
onChange?: (value: string) => void;
|
|
18
|
+
/** @deprecated Pass the native `aria-label` attribute instead. */
|
|
18
19
|
ariaLabel?: string;
|
|
19
|
-
/**
|
|
20
|
-
|
|
20
|
+
/**
|
|
21
|
+
* @deprecated No-op. This component renders a `<div role="radio">`, not a
|
|
22
|
+
* native `<input type="radio">`, so it does not group by name or participate
|
|
23
|
+
* in native form submission — `RadioGroup` handles grouping in React state.
|
|
24
|
+
* Declared only so the attribute is not forwarded to an element that rejects it.
|
|
25
|
+
*/
|
|
26
|
+
name?: string;
|
|
27
|
+
};
|
|
28
|
+
export interface RadioButtonProps extends RadioButtonOwnProps, Omit<React.ComponentPropsWithoutRef<'div'>, keyof RadioButtonOwnProps> {
|
|
21
29
|
}
|
|
22
|
-
export declare const RadioButton:
|
|
23
|
-
|
|
30
|
+
export declare const RadioButton: React.ForwardRefExoticComponent<RadioButtonProps & React.RefAttributes<HTMLDivElement>>;
|
|
31
|
+
type RadioGroupOwnProps = {
|
|
24
32
|
/** Group label */
|
|
25
33
|
label?: string;
|
|
26
34
|
/** Currently selected value */
|
|
@@ -35,9 +43,14 @@ export interface RadioGroupProps {
|
|
|
35
43
|
}[];
|
|
36
44
|
/** Layout direction */
|
|
37
45
|
direction?: 'vertical' | 'horizontal';
|
|
38
|
-
/**
|
|
39
|
-
|
|
46
|
+
/** Called with the newly selected value */
|
|
47
|
+
onValueChange?: (value: string) => void;
|
|
40
48
|
/** Additional CSS classes */
|
|
41
49
|
className?: string;
|
|
50
|
+
/** @deprecated Use `onValueChange` instead. */
|
|
51
|
+
onChange?: (value: string) => void;
|
|
52
|
+
};
|
|
53
|
+
export interface RadioGroupProps extends RadioGroupOwnProps, Omit<React.ComponentPropsWithoutRef<'div'>, keyof RadioGroupOwnProps> {
|
|
42
54
|
}
|
|
43
|
-
export declare const RadioGroup:
|
|
55
|
+
export declare const RadioGroup: React.ForwardRefExoticComponent<RadioGroupProps & React.RefAttributes<HTMLDivElement>>;
|
|
56
|
+
export {};
|
|
@@ -1,76 +1,101 @@
|
|
|
1
1
|
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
|
-
import "react";
|
|
2
|
+
import React from "react";
|
|
3
3
|
import "./RadioButton.css";
|
|
4
|
-
const RadioButton = (
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
onClick
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
"
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
);
|
|
45
|
-
};
|
|
46
|
-
const RadioGroup = ({
|
|
47
|
-
label,
|
|
48
|
-
value,
|
|
49
|
-
name,
|
|
50
|
-
options,
|
|
51
|
-
direction = "vertical",
|
|
52
|
-
onChange,
|
|
53
|
-
className = ""
|
|
54
|
-
}) => {
|
|
55
|
-
const baseClass = "ds-radio-group";
|
|
56
|
-
const directionClass = `${baseClass}--${direction}`;
|
|
57
|
-
const classes = [baseClass, directionClass, className].filter(Boolean).join(" ");
|
|
58
|
-
return /* @__PURE__ */ jsxs("div", { className: classes, role: "radiogroup", "aria-label": label, children: [
|
|
59
|
-
label && /* @__PURE__ */ jsx("span", { className: `${baseClass}__label`, children: label }),
|
|
60
|
-
/* @__PURE__ */ jsx("div", { className: `${baseClass}__options`, children: options.map((option) => /* @__PURE__ */ jsx(
|
|
61
|
-
RadioButton,
|
|
4
|
+
const RadioButton = React.forwardRef(
|
|
5
|
+
({
|
|
6
|
+
label,
|
|
7
|
+
checked = false,
|
|
8
|
+
disabled = false,
|
|
9
|
+
value = "",
|
|
10
|
+
onValueChange,
|
|
11
|
+
onChange,
|
|
12
|
+
className = "",
|
|
13
|
+
ariaLabel,
|
|
14
|
+
name: _name,
|
|
15
|
+
onClick,
|
|
16
|
+
onKeyDown,
|
|
17
|
+
...rest
|
|
18
|
+
}, ref) => {
|
|
19
|
+
const baseClass = "ds-radio";
|
|
20
|
+
const classes = [
|
|
21
|
+
baseClass,
|
|
22
|
+
checked ? `${baseClass}--checked` : "",
|
|
23
|
+
disabled ? `${baseClass}--disabled` : "",
|
|
24
|
+
className
|
|
25
|
+
].filter(Boolean).join(" ");
|
|
26
|
+
const select = () => {
|
|
27
|
+
if (disabled) return;
|
|
28
|
+
onValueChange?.(value);
|
|
29
|
+
onChange?.(value);
|
|
30
|
+
};
|
|
31
|
+
const handleClick = (e) => {
|
|
32
|
+
onClick?.(e);
|
|
33
|
+
select();
|
|
34
|
+
};
|
|
35
|
+
const handleKeyDown = (e) => {
|
|
36
|
+
onKeyDown?.(e);
|
|
37
|
+
if (e.key === " " || e.key === "Enter") {
|
|
38
|
+
e.preventDefault();
|
|
39
|
+
select();
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
return /* @__PURE__ */ jsxs(
|
|
43
|
+
"div",
|
|
62
44
|
{
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
45
|
+
...rest,
|
|
46
|
+
ref,
|
|
47
|
+
className: classes,
|
|
48
|
+
onClick: handleClick,
|
|
49
|
+
onKeyDown: handleKeyDown,
|
|
50
|
+
role: "radio",
|
|
51
|
+
"aria-checked": checked,
|
|
52
|
+
"aria-disabled": disabled,
|
|
53
|
+
"aria-label": ariaLabel || rest["aria-label"] || label,
|
|
54
|
+
tabIndex: disabled ? -1 : 0,
|
|
55
|
+
children: [
|
|
56
|
+
/* @__PURE__ */ jsx("div", { className: `${baseClass}__circle`, children: /* @__PURE__ */ jsx("div", { className: `${baseClass}__dot` }) }),
|
|
57
|
+
label && /* @__PURE__ */ jsx("span", { className: `${baseClass}__label`, children: label })
|
|
58
|
+
]
|
|
59
|
+
}
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
);
|
|
63
|
+
RadioButton.displayName = "RadioButton";
|
|
64
|
+
const RadioGroup = React.forwardRef(
|
|
65
|
+
({
|
|
66
|
+
label,
|
|
67
|
+
value,
|
|
68
|
+
name: _name,
|
|
69
|
+
options,
|
|
70
|
+
direction = "vertical",
|
|
71
|
+
onValueChange,
|
|
72
|
+
onChange,
|
|
73
|
+
className = "",
|
|
74
|
+
...rest
|
|
75
|
+
}, ref) => {
|
|
76
|
+
const baseClass = "ds-radio-group";
|
|
77
|
+
const classes = [baseClass, `${baseClass}--${direction}`, className].filter(Boolean).join(" ");
|
|
78
|
+
const handleSelect = (next) => {
|
|
79
|
+
onValueChange?.(next);
|
|
80
|
+
onChange?.(next);
|
|
81
|
+
};
|
|
82
|
+
return /* @__PURE__ */ jsxs("div", { ...rest, ref, className: classes, role: "radiogroup", "aria-label": label, children: [
|
|
83
|
+
label && /* @__PURE__ */ jsx("span", { className: `${baseClass}__label`, children: label }),
|
|
84
|
+
/* @__PURE__ */ jsx("div", { className: `${baseClass}__options`, children: options.map((option) => /* @__PURE__ */ jsx(
|
|
85
|
+
RadioButton,
|
|
86
|
+
{
|
|
87
|
+
label: option.label,
|
|
88
|
+
value: option.value,
|
|
89
|
+
checked: value === option.value,
|
|
90
|
+
disabled: option.disabled,
|
|
91
|
+
onValueChange: handleSelect
|
|
92
|
+
},
|
|
93
|
+
option.value
|
|
94
|
+
)) })
|
|
95
|
+
] });
|
|
96
|
+
}
|
|
97
|
+
);
|
|
98
|
+
RadioGroup.displayName = "RadioGroup";
|
|
74
99
|
export {
|
|
75
100
|
RadioButton,
|
|
76
101
|
RadioGroup
|
|
@@ -232,8 +232,12 @@
|
|
|
232
232
|
.ds-selection-card__toggle-icon {
|
|
233
233
|
/* Intentionally off the --icon-size-* scale — same reason as ToggleSwitch:
|
|
234
234
|
this glyph lives inside the 20x20 toggle thumb, and the smallest scale
|
|
235
|
-
step (20px) would fill it completely.
|
|
236
|
-
|
|
235
|
+
step (20px) would fill it completely. Sized via --icon-size, not
|
|
236
|
+
font-size, so the icon's box shrinks with the glyph (see ToggleSwitch).
|
|
237
|
+
|
|
238
|
+
ds-allow(icon-size): 14px glyph inside the 20px thumb — the smallest
|
|
239
|
+
scale step would fill it edge to edge. */
|
|
240
|
+
--icon-size: 14px;
|
|
237
241
|
color: var(--color-action-primary-bg);
|
|
238
242
|
}
|
|
239
243
|
|
|
@@ -9,18 +9,24 @@ export interface SelectionCardOption {
|
|
|
9
9
|
/** Whether this option is disabled */
|
|
10
10
|
disabled?: boolean;
|
|
11
11
|
}
|
|
12
|
-
|
|
12
|
+
/** Props owned by SelectionCard itself — everything else falls through to the group. */
|
|
13
|
+
type SelectionCardOwnProps = {
|
|
13
14
|
/** Selection mode — radio (single), checkbox (multi), or toggle (each card is an on/off switch) */
|
|
14
15
|
mode?: 'radio' | 'checkbox' | 'toggle';
|
|
15
16
|
/** Available options */
|
|
16
17
|
options: SelectionCardOption[];
|
|
17
18
|
/** Currently selected value(s) — string for radio, string[] for checkbox */
|
|
18
19
|
value?: string | string[];
|
|
19
|
-
/**
|
|
20
|
-
|
|
20
|
+
/** Called with the next selection — a string in radio mode, an array otherwise */
|
|
21
|
+
onValueChange?: (value: string | string[]) => void;
|
|
21
22
|
/** Group name (used for aria-label on the group) */
|
|
22
23
|
name?: string;
|
|
23
24
|
/** Additional CSS classes */
|
|
24
25
|
className?: string;
|
|
26
|
+
/** @deprecated Use `onValueChange` instead. */
|
|
27
|
+
onChange?: (value: string | string[]) => void;
|
|
28
|
+
};
|
|
29
|
+
export interface SelectionCardProps extends SelectionCardOwnProps, Omit<React.ComponentPropsWithoutRef<'div'>, keyof SelectionCardOwnProps> {
|
|
25
30
|
}
|
|
26
|
-
export declare const SelectionCard:
|
|
31
|
+
export declare const SelectionCard: React.ForwardRefExoticComponent<SelectionCardProps & React.RefAttributes<HTMLDivElement>>;
|
|
32
|
+
export {};
|