@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,5 +1,5 @@
|
|
|
1
1
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
-
import "react";
|
|
2
|
+
import React from "react";
|
|
3
3
|
import "./SelectionCard.css";
|
|
4
4
|
const CheckIcon = () => /* @__PURE__ */ jsx(
|
|
5
5
|
"svg",
|
|
@@ -22,64 +22,80 @@ const CheckIcon = () => /* @__PURE__ */ jsx(
|
|
|
22
22
|
)
|
|
23
23
|
}
|
|
24
24
|
);
|
|
25
|
-
const SelectionCard = (
|
|
26
|
-
mode = "radio",
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
if (e.key === " " || e.key === "Enter") {
|
|
47
|
-
e.preventDefault();
|
|
48
|
-
handleSelect(option);
|
|
49
|
-
}
|
|
50
|
-
};
|
|
51
|
-
const groupRole = mode === "radio" ? "radiogroup" : "group";
|
|
52
|
-
const itemRole = mode === "radio" ? "radio" : mode === "toggle" ? "switch" : "checkbox";
|
|
53
|
-
const groupClasses = [`${baseClass}-group`, className].filter(Boolean).join(" ");
|
|
54
|
-
return /* @__PURE__ */ jsx("div", { className: groupClasses, role: groupRole, "aria-label": name, children: options.map((option) => {
|
|
55
|
-
const selected = isSelected(option.value);
|
|
56
|
-
const cardClasses = [
|
|
57
|
-
baseClass,
|
|
58
|
-
selected ? `${baseClass}--selected` : "",
|
|
59
|
-
option.disabled ? `${baseClass}--disabled` : ""
|
|
60
|
-
].filter(Boolean).join(" ");
|
|
61
|
-
return /* @__PURE__ */ jsxs(
|
|
25
|
+
const SelectionCard = React.forwardRef(
|
|
26
|
+
({ mode = "radio", options, value, onValueChange, onChange, name, className = "", ...rest }, ref) => {
|
|
27
|
+
const baseClass = "ds-selection-card";
|
|
28
|
+
const selectedValues = Array.isArray(value) ? value : value !== void 0 ? [value] : [];
|
|
29
|
+
const isSelected = (optionValue) => selectedValues.includes(optionValue);
|
|
30
|
+
const handleSelect = (option) => {
|
|
31
|
+
if (option.disabled) return;
|
|
32
|
+
const next = mode === "radio" ? option.value : isSelected(option.value) ? selectedValues.filter((v) => v !== option.value) : [...selectedValues, option.value];
|
|
33
|
+
onValueChange?.(next);
|
|
34
|
+
onChange?.(next);
|
|
35
|
+
};
|
|
36
|
+
const handleKeyDown = (e, option) => {
|
|
37
|
+
if (e.key === " " || e.key === "Enter") {
|
|
38
|
+
e.preventDefault();
|
|
39
|
+
handleSelect(option);
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
const groupRole = mode === "radio" ? "radiogroup" : "group";
|
|
43
|
+
const itemRole = mode === "radio" ? "radio" : mode === "toggle" ? "switch" : "checkbox";
|
|
44
|
+
const groupClasses = [`${baseClass}-group`, className].filter(Boolean).join(" ");
|
|
45
|
+
return /* @__PURE__ */ jsx(
|
|
62
46
|
"div",
|
|
63
47
|
{
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
option.
|
|
75
|
-
]
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
48
|
+
...rest,
|
|
49
|
+
ref,
|
|
50
|
+
className: groupClasses,
|
|
51
|
+
role: groupRole,
|
|
52
|
+
"aria-label": name || rest["aria-label"],
|
|
53
|
+
children: options.map((option) => {
|
|
54
|
+
const selected = isSelected(option.value);
|
|
55
|
+
const cardClasses = [
|
|
56
|
+
baseClass,
|
|
57
|
+
selected ? `${baseClass}--selected` : "",
|
|
58
|
+
option.disabled ? `${baseClass}--disabled` : ""
|
|
59
|
+
].filter(Boolean).join(" ");
|
|
60
|
+
return /* @__PURE__ */ jsxs(
|
|
61
|
+
"div",
|
|
62
|
+
{
|
|
63
|
+
className: cardClasses,
|
|
64
|
+
role: itemRole,
|
|
65
|
+
"aria-checked": selected,
|
|
66
|
+
"aria-disabled": option.disabled,
|
|
67
|
+
tabIndex: option.disabled ? -1 : 0,
|
|
68
|
+
onClick: () => handleSelect(option),
|
|
69
|
+
onKeyDown: (e) => handleKeyDown(e, option),
|
|
70
|
+
children: [
|
|
71
|
+
/* @__PURE__ */ jsxs("div", { className: `${baseClass}__content`, children: [
|
|
72
|
+
/* @__PURE__ */ jsx("span", { className: `${baseClass}__label`, children: option.label }),
|
|
73
|
+
option.description && /* @__PURE__ */ jsx("span", { className: `${baseClass}__description`, children: option.description })
|
|
74
|
+
] }),
|
|
75
|
+
/* @__PURE__ */ jsx("div", { className: `${baseClass}__indicator`, children: mode === "radio" ? /* @__PURE__ */ jsx("div", { className: `${baseClass}__radio`, children: /* @__PURE__ */ jsx("div", { className: `${baseClass}__radio-dot` }) }) : mode === "toggle" ? /* @__PURE__ */ jsx(
|
|
76
|
+
"div",
|
|
77
|
+
{
|
|
78
|
+
className: `${baseClass}__toggle ${selected ? "" : `${baseClass}__toggle--off`}`,
|
|
79
|
+
children: /* @__PURE__ */ jsx("div", { className: `${baseClass}__toggle-thumb`, children: /* @__PURE__ */ jsx(
|
|
80
|
+
"span",
|
|
81
|
+
{
|
|
82
|
+
className: "material-symbols-rounded ds-selection-card__toggle-icon",
|
|
83
|
+
"aria-hidden": "true",
|
|
84
|
+
children: "check"
|
|
85
|
+
}
|
|
86
|
+
) })
|
|
87
|
+
}
|
|
88
|
+
) : /* @__PURE__ */ jsx("div", { className: `${baseClass}__checkbox`, children: /* @__PURE__ */ jsx(CheckIcon, {}) }) })
|
|
89
|
+
]
|
|
90
|
+
},
|
|
91
|
+
option.value
|
|
92
|
+
);
|
|
93
|
+
})
|
|
94
|
+
}
|
|
80
95
|
);
|
|
81
|
-
}
|
|
82
|
-
|
|
96
|
+
}
|
|
97
|
+
);
|
|
98
|
+
SelectionCard.displayName = "SelectionCard";
|
|
83
99
|
export {
|
|
84
100
|
SelectionCard
|
|
85
101
|
};
|
|
@@ -22,6 +22,8 @@
|
|
|
22
22
|
var(--color-bg-container-primary) 50%,
|
|
23
23
|
transparent 100%
|
|
24
24
|
);
|
|
25
|
+
/* ds-allow(motion): the shimmer needs a symmetric in-out curve and no
|
|
26
|
+
--motion-ease-* token provides one — the duration is tokenized. */
|
|
25
27
|
animation: ds-skeleton-shimmer var(--motion-duration-loop-shimmer) ease-in-out infinite;
|
|
26
28
|
}
|
|
27
29
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { default as React } from 'react';
|
|
2
|
-
|
|
2
|
+
/** Props owned by Slider itself — everything else falls through to the <input type="range">. */
|
|
3
|
+
type SliderOwnProps = {
|
|
3
4
|
/** Current value */
|
|
4
5
|
value?: number;
|
|
5
6
|
/** Minimum value */
|
|
@@ -8,18 +9,26 @@ export interface SliderProps {
|
|
|
8
9
|
max?: number;
|
|
9
10
|
/** Step increment */
|
|
10
11
|
step?: number;
|
|
11
|
-
/**
|
|
12
|
-
disabled?: boolean;
|
|
13
|
-
/** Size */
|
|
12
|
+
/** Component size (not the native character-width `size` attribute) */
|
|
14
13
|
size?: 'default' | 'compact';
|
|
15
|
-
/**
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
14
|
+
/**
|
|
15
|
+
* Convenience callback receiving the numeric value directly.
|
|
16
|
+
* Fires alongside `onChange`, which keeps the standard React event signature
|
|
17
|
+
* so form libraries work unmodified.
|
|
18
|
+
*/
|
|
19
|
+
onValueChange?: (value: number) => void;
|
|
20
|
+
/** Additional CSS classes — applied to the wrapper, not the <input> */
|
|
20
21
|
className?: string;
|
|
22
|
+
/** @deprecated Pass the native `aria-label` attribute instead. */
|
|
23
|
+
ariaLabel?: string;
|
|
24
|
+
};
|
|
25
|
+
export interface SliderProps extends SliderOwnProps, Omit<React.ComponentPropsWithoutRef<'input'>, keyof SliderOwnProps | 'type'> {
|
|
21
26
|
}
|
|
22
27
|
/**
|
|
23
28
|
* Slider allows selecting a value from within a given range.
|
|
29
|
+
*
|
|
30
|
+
* Forwards a ref to the underlying `<input type="range">` and spreads
|
|
31
|
+
* unrecognised props onto it.
|
|
24
32
|
*/
|
|
25
|
-
export declare const Slider:
|
|
33
|
+
export declare const Slider: React.ForwardRefExoticComponent<SliderProps & React.RefAttributes<HTMLInputElement>>;
|
|
34
|
+
export {};
|
|
@@ -1,46 +1,56 @@
|
|
|
1
1
|
import { jsx } from "react/jsx-runtime";
|
|
2
|
-
import "react";
|
|
2
|
+
import React from "react";
|
|
3
3
|
import "./Slider.css";
|
|
4
|
-
const Slider = (
|
|
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
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
4
|
+
const Slider = React.forwardRef(
|
|
5
|
+
({
|
|
6
|
+
value = 50,
|
|
7
|
+
min = 0,
|
|
8
|
+
max = 100,
|
|
9
|
+
step = 1,
|
|
10
|
+
disabled = false,
|
|
11
|
+
size = "default",
|
|
12
|
+
onChange,
|
|
13
|
+
onValueChange,
|
|
14
|
+
ariaLabel = "Slider",
|
|
15
|
+
className = "",
|
|
16
|
+
style,
|
|
17
|
+
...rest
|
|
18
|
+
}, ref) => {
|
|
19
|
+
const baseClass = "ds-slider";
|
|
20
|
+
const classes = [
|
|
21
|
+
baseClass,
|
|
22
|
+
`${baseClass}--${size}`,
|
|
23
|
+
disabled ? `${baseClass}--disabled` : "",
|
|
24
|
+
className
|
|
25
|
+
].filter(Boolean).join(" ");
|
|
26
|
+
const percentage = (value - min) / (max - min) * 100;
|
|
27
|
+
const handleChange = (e) => {
|
|
28
|
+
onChange?.(e);
|
|
29
|
+
onValueChange?.(Number(e.target.value));
|
|
30
|
+
};
|
|
31
|
+
return /* @__PURE__ */ jsx("div", { className: classes, children: /* @__PURE__ */ jsx(
|
|
32
|
+
"input",
|
|
33
|
+
{
|
|
34
|
+
...rest,
|
|
35
|
+
ref,
|
|
36
|
+
type: "range",
|
|
37
|
+
className: `${baseClass}__input`,
|
|
38
|
+
value,
|
|
39
|
+
min,
|
|
40
|
+
max,
|
|
41
|
+
step,
|
|
42
|
+
disabled,
|
|
43
|
+
onChange: handleChange,
|
|
44
|
+
"aria-label": ariaLabel || rest["aria-label"],
|
|
45
|
+
style: {
|
|
46
|
+
background: `linear-gradient(to right, var(--color-action-primary-bg) ${percentage}%, var(--color-bg-container-secondary) ${percentage}%)`,
|
|
47
|
+
...style
|
|
48
|
+
}
|
|
40
49
|
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
|
|
50
|
+
) });
|
|
51
|
+
}
|
|
52
|
+
);
|
|
53
|
+
Slider.displayName = "Slider";
|
|
44
54
|
export {
|
|
45
55
|
Slider
|
|
46
56
|
};
|
|
@@ -59,6 +59,17 @@
|
|
|
59
59
|
stroke: var(--color-text-secondary);
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
+
/* Inherit — both circles draw in currentColor so the spinner matches the
|
|
63
|
+
text/icon colour of whatever control contains it (e.g. a loading Button) */
|
|
64
|
+
.ds-spinner--inherit .ds-spinner__track {
|
|
65
|
+
stroke: currentColor;
|
|
66
|
+
opacity: 0.25;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.ds-spinner--inherit .ds-spinner__arc {
|
|
70
|
+
stroke: currentColor;
|
|
71
|
+
}
|
|
72
|
+
|
|
62
73
|
/* ============================================
|
|
63
74
|
ANIMATION
|
|
64
75
|
============================================ */
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
export interface SpinnerProps {
|
|
2
2
|
/** Size of the spinner */
|
|
3
3
|
size?: 'sm' | 'md' | 'lg';
|
|
4
|
-
/** Visual variant */
|
|
5
|
-
variant?: 'primary' | 'neutral';
|
|
4
|
+
/** Visual variant — `inherit` draws the spinner in `currentColor`, for use inside coloured controls */
|
|
5
|
+
variant?: 'primary' | 'neutral' | 'inherit';
|
|
6
6
|
/** Accessible label */
|
|
7
7
|
label?: string;
|
|
8
8
|
/** Additional CSS classes */
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/* ============================================
|
|
2
|
+
SWATCH COMPONENT
|
|
3
|
+
Clickable colour tile for palettes and pickers
|
|
4
|
+
============================================ */
|
|
5
|
+
|
|
6
|
+
/* Base */
|
|
7
|
+
|
|
8
|
+
.ds-swatch {
|
|
9
|
+
width: 24px;
|
|
10
|
+
height: 24px;
|
|
11
|
+
padding: 0;
|
|
12
|
+
border: none;
|
|
13
|
+
border-radius: var(--radius-full);
|
|
14
|
+
background-color: var(--ds-swatch-color);
|
|
15
|
+
/* A hairline inset keeps very light colours visible on the white floor */
|
|
16
|
+
box-shadow: inset 0 0 0 var(--border-xs) var(--color-bg-container-border);
|
|
17
|
+
cursor: pointer;
|
|
18
|
+
flex-shrink: 0;
|
|
19
|
+
transition: box-shadow var(--motion-duration-base) var(--motion-ease-standard);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/* Sizes */
|
|
23
|
+
|
|
24
|
+
.ds-swatch--compact {
|
|
25
|
+
width: 20px;
|
|
26
|
+
height: 20px;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/* Shapes */
|
|
30
|
+
|
|
31
|
+
.ds-swatch--square {
|
|
32
|
+
border-radius: var(--radius-sm);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/* States */
|
|
36
|
+
|
|
37
|
+
.ds-swatch--selected {
|
|
38
|
+
box-shadow:
|
|
39
|
+
inset 0 0 0 var(--border-xs) var(--color-bg-container-border),
|
|
40
|
+
0 0 0 var(--border-md) var(--color-bg-page-primary),
|
|
41
|
+
0 0 0 calc(var(--border-md) * 2) var(--color-text-primary);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.ds-swatch:focus-visible {
|
|
45
|
+
outline: var(--border-md) solid var(--color-input-border-selected);
|
|
46
|
+
outline-offset: var(--border-md);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.ds-swatch--disabled {
|
|
50
|
+
opacity: 0.4;
|
|
51
|
+
cursor: not-allowed;
|
|
52
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
/** Props owned by Swatch itself — everything else falls through to the <button>. */
|
|
3
|
+
type SwatchOwnProps = {
|
|
4
|
+
/** The colour this swatch shows — any valid CSS colour, typically a hex value */
|
|
5
|
+
value: string;
|
|
6
|
+
/**
|
|
7
|
+
* Accessible name for the swatch. Defaults to the colour value, which is
|
|
8
|
+
* meaningful but terse — prefer a human name ("Teal 07") when you have one.
|
|
9
|
+
*/
|
|
10
|
+
label?: string;
|
|
11
|
+
/** Selected state — renders the selection ring and sets aria-pressed */
|
|
12
|
+
selected?: boolean;
|
|
13
|
+
/** Swatch size */
|
|
14
|
+
size?: 'default' | 'compact';
|
|
15
|
+
/** Corner treatment — circle matches the site's preset grids; square suits picker triggers */
|
|
16
|
+
shape?: 'circle' | 'square';
|
|
17
|
+
/** Whether the swatch is disabled */
|
|
18
|
+
disabled?: boolean;
|
|
19
|
+
/** Additional CSS classes */
|
|
20
|
+
className?: string;
|
|
21
|
+
};
|
|
22
|
+
export interface SwatchProps extends SwatchOwnProps, Omit<React.ComponentPropsWithoutRef<'button'>, keyof SwatchOwnProps | 'type'> {
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* A clickable colour tile — the building block for preset palettes and
|
|
26
|
+
* picker triggers. Renders a `<button>` whose background is the `value`
|
|
27
|
+
* colour; `selected` draws the theme-aware selection ring.
|
|
28
|
+
*
|
|
29
|
+
* Purely presentational (no hooks), so it can be rendered from a Server
|
|
30
|
+
* Component; interactivity arrives through the native `onClick` you pass.
|
|
31
|
+
* Forwards a ref to the `<button>` and spreads unrecognised props onto it.
|
|
32
|
+
*/
|
|
33
|
+
export declare const Swatch: React.ForwardRefExoticComponent<SwatchProps & React.RefAttributes<HTMLButtonElement>>;
|
|
34
|
+
export {};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import "./Swatch.css";
|
|
4
|
+
const Swatch = React.forwardRef(
|
|
5
|
+
({
|
|
6
|
+
value,
|
|
7
|
+
label,
|
|
8
|
+
selected = false,
|
|
9
|
+
size = "default",
|
|
10
|
+
shape = "circle",
|
|
11
|
+
disabled = false,
|
|
12
|
+
className = "",
|
|
13
|
+
style,
|
|
14
|
+
...rest
|
|
15
|
+
}, ref) => {
|
|
16
|
+
const baseClass = "ds-swatch";
|
|
17
|
+
const classes = [
|
|
18
|
+
baseClass,
|
|
19
|
+
size === "compact" ? `${baseClass}--compact` : "",
|
|
20
|
+
shape === "square" ? `${baseClass}--square` : "",
|
|
21
|
+
selected ? `${baseClass}--selected` : "",
|
|
22
|
+
disabled ? `${baseClass}--disabled` : "",
|
|
23
|
+
className
|
|
24
|
+
].filter(Boolean).join(" ");
|
|
25
|
+
const swatchStyle = { ...style, "--ds-swatch-color": value };
|
|
26
|
+
return /* @__PURE__ */ jsx(
|
|
27
|
+
"button",
|
|
28
|
+
{
|
|
29
|
+
...rest,
|
|
30
|
+
ref,
|
|
31
|
+
type: "button",
|
|
32
|
+
className: classes,
|
|
33
|
+
style: swatchStyle,
|
|
34
|
+
disabled,
|
|
35
|
+
"aria-pressed": selected,
|
|
36
|
+
"aria-label": rest["aria-label"] ?? label ?? value
|
|
37
|
+
}
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
);
|
|
41
|
+
Swatch.displayName = "Swatch";
|
|
42
|
+
export {
|
|
43
|
+
Swatch
|
|
44
|
+
};
|
|
@@ -184,3 +184,22 @@
|
|
|
184
184
|
line-height: var(--font-paragraph-sm-line-height);
|
|
185
185
|
letter-spacing: var(--font-paragraph-sm-letter-spacing);
|
|
186
186
|
}
|
|
187
|
+
|
|
188
|
+
/* ============================================
|
|
189
|
+
SCREEN-READER-ONLY
|
|
190
|
+
Fallback text for header cells with no visible
|
|
191
|
+
label (checkbox / actions columns) — an empty
|
|
192
|
+
<th> is unannounced.
|
|
193
|
+
============================================ */
|
|
194
|
+
|
|
195
|
+
.ds-table__sr-only {
|
|
196
|
+
position: absolute;
|
|
197
|
+
width: 1px;
|
|
198
|
+
height: 1px;
|
|
199
|
+
padding: 0;
|
|
200
|
+
margin: -1px;
|
|
201
|
+
overflow: hidden;
|
|
202
|
+
clip: rect(0, 0, 0, 0);
|
|
203
|
+
white-space: nowrap;
|
|
204
|
+
border: 0;
|
|
205
|
+
}
|
|
@@ -15,7 +15,8 @@ export interface TableRow {
|
|
|
15
15
|
/** Cell values keyed by column key — each accepts any React node */
|
|
16
16
|
cells: Record<string, React.ReactNode>;
|
|
17
17
|
}
|
|
18
|
-
|
|
18
|
+
/** Props owned by Table itself — everything else falls through to the <table>. */
|
|
19
|
+
type TableOwnProps = {
|
|
19
20
|
/** Column definitions */
|
|
20
21
|
columns: TableColumn[];
|
|
21
22
|
/** Row data */
|
|
@@ -36,10 +37,17 @@ export interface TableProps {
|
|
|
36
37
|
captionHidden?: boolean;
|
|
37
38
|
/** Additional CSS classes */
|
|
38
39
|
className?: string;
|
|
40
|
+
};
|
|
41
|
+
export interface TableProps extends TableOwnProps, Omit<React.ComponentPropsWithoutRef<'table'>, keyof TableOwnProps> {
|
|
39
42
|
}
|
|
40
43
|
/**
|
|
41
44
|
* Table component from Figma design system.
|
|
42
45
|
* Data table with flexible cell content — supports text, icons,
|
|
43
46
|
* inputs, buttons, and any other React nodes inside cells.
|
|
47
|
+
*
|
|
48
|
+
* Forwards a ref to the `<table>` element and spreads unrecognised props onto
|
|
49
|
+
* it. When `bordered`, the table is wrapped in a container div — the ref and
|
|
50
|
+
* spread props still target the inner `<table>`.
|
|
44
51
|
*/
|
|
45
|
-
export declare const Table:
|
|
52
|
+
export declare const Table: React.ForwardRefExoticComponent<TableProps & React.RefAttributes<HTMLTableElement>>;
|
|
53
|
+
export {};
|
|
@@ -1,65 +1,65 @@
|
|
|
1
1
|
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
|
-
import "react";
|
|
2
|
+
import React from "react";
|
|
3
3
|
import "./Table.css";
|
|
4
|
-
const Table = (
|
|
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
|
-
|
|
33
|
-
|
|
34
|
-
|
|
4
|
+
const Table = React.forwardRef(
|
|
5
|
+
({
|
|
6
|
+
columns,
|
|
7
|
+
rows,
|
|
8
|
+
size = "default",
|
|
9
|
+
striped = false,
|
|
10
|
+
bordered = false,
|
|
11
|
+
caption,
|
|
12
|
+
captionHidden = false,
|
|
13
|
+
className = "",
|
|
14
|
+
...rest
|
|
15
|
+
}, ref) => {
|
|
16
|
+
const baseClass = "ds-table";
|
|
17
|
+
const classes = [
|
|
18
|
+
baseClass,
|
|
19
|
+
`${baseClass}--${size}`,
|
|
20
|
+
striped ? `${baseClass}--striped` : "",
|
|
21
|
+
bordered ? `${baseClass}--bordered` : "",
|
|
22
|
+
className
|
|
23
|
+
].filter(Boolean).join(" ");
|
|
24
|
+
const table = /* @__PURE__ */ jsxs("table", { ...rest, ref, className: classes, children: [
|
|
25
|
+
caption && /* @__PURE__ */ jsx(
|
|
26
|
+
"caption",
|
|
27
|
+
{
|
|
28
|
+
className: captionHidden ? `${baseClass}__caption--hidden` : `${baseClass}__caption`,
|
|
29
|
+
children: caption
|
|
30
|
+
}
|
|
31
|
+
),
|
|
32
|
+
/* @__PURE__ */ jsx("thead", { className: `${baseClass}__head`, children: /* @__PURE__ */ jsx("tr", { className: `${baseClass}__row ${baseClass}__row--header`, children: columns.map((col) => /* @__PURE__ */ jsx(
|
|
33
|
+
"th",
|
|
34
|
+
{
|
|
35
|
+
className: `${baseClass}__header-cell`,
|
|
36
|
+
scope: "col",
|
|
37
|
+
style: {
|
|
38
|
+
width: col.width,
|
|
39
|
+
textAlign: col.align || "left"
|
|
40
|
+
},
|
|
41
|
+
children: col.header || /* @__PURE__ */ jsx("span", { className: `${baseClass}__sr-only`, children: col.key })
|
|
35
42
|
},
|
|
36
|
-
|
|
37
|
-
},
|
|
38
|
-
col
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
)
|
|
54
|
-
},
|
|
55
|
-
col.key
|
|
56
|
-
)) }, row.id)) })
|
|
57
|
-
] });
|
|
58
|
-
if (bordered) {
|
|
59
|
-
return /* @__PURE__ */ jsx("div", { className: `${baseClass}__wrapper`, children: table });
|
|
43
|
+
col.key
|
|
44
|
+
)) }) }),
|
|
45
|
+
/* @__PURE__ */ jsx("tbody", { className: `${baseClass}__body`, children: rows.map((row) => /* @__PURE__ */ jsx("tr", { className: `${baseClass}__row`, children: columns.map((col) => /* @__PURE__ */ jsx("td", { className: `${baseClass}__cell`, children: /* @__PURE__ */ jsx(
|
|
46
|
+
"div",
|
|
47
|
+
{
|
|
48
|
+
className: `${baseClass}__cell-content`,
|
|
49
|
+
style: {
|
|
50
|
+
justifyContent: col.align === "center" ? "center" : col.align === "right" ? "flex-end" : "flex-start"
|
|
51
|
+
},
|
|
52
|
+
children: row.cells[col.key]
|
|
53
|
+
}
|
|
54
|
+
) }, col.key)) }, row.id)) })
|
|
55
|
+
] });
|
|
56
|
+
if (bordered) {
|
|
57
|
+
return /* @__PURE__ */ jsx("div", { className: `${baseClass}__wrapper`, children: table });
|
|
58
|
+
}
|
|
59
|
+
return table;
|
|
60
60
|
}
|
|
61
|
-
|
|
62
|
-
|
|
61
|
+
);
|
|
62
|
+
Table.displayName = "Table";
|
|
63
63
|
export {
|
|
64
64
|
Table
|
|
65
65
|
};
|