@hideyukimori/nene2-ui 0.2.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/LICENSE +21 -0
- package/README.md +192 -0
- package/dist/data/DataTable.d.ts +32 -0
- package/dist/data/DataTable.js +17 -0
- package/dist/data/DataTable.js.map +1 -0
- package/dist/data/DetailList.d.ts +14 -0
- package/dist/data/DetailList.js +9 -0
- package/dist/data/DetailList.js.map +1 -0
- package/dist/data/Pagination.d.ts +26 -0
- package/dist/data/Pagination.js +20 -0
- package/dist/data/Pagination.js.map +1 -0
- package/dist/feedback/Badge.d.ts +14 -0
- package/dist/feedback/Badge.js +18 -0
- package/dist/feedback/Badge.js.map +1 -0
- package/dist/feedback/InlineAlert.d.ts +15 -0
- package/dist/feedback/InlineAlert.js +18 -0
- package/dist/feedback/InlineAlert.js.map +1 -0
- package/dist/feedback/ToastProvider.d.ts +31 -0
- package/dist/feedback/ToastProvider.js +56 -0
- package/dist/feedback/ToastProvider.js.map +1 -0
- package/dist/feedback/toast-context.d.ts +20 -0
- package/dist/feedback/toast-context.js +17 -0
- package/dist/feedback/toast-context.js.map +1 -0
- package/dist/forms/FormField.d.ts +47 -0
- package/dist/forms/FormField.js +25 -0
- package/dist/forms/FormField.js.map +1 -0
- package/dist/forms/field-context.d.ts +54 -0
- package/dist/forms/field-context.js +51 -0
- package/dist/forms/field-context.js.map +1 -0
- package/dist/index.d.ts +34 -0
- package/dist/index.js +47 -0
- package/dist/index.js.map +1 -0
- package/dist/layout/Box.d.ts +20 -0
- package/dist/layout/Box.js +17 -0
- package/dist/layout/Box.js.map +1 -0
- package/dist/layout/Card.d.ts +16 -0
- package/dist/layout/Card.js +13 -0
- package/dist/layout/Card.js.map +1 -0
- package/dist/layout/Grid.d.ts +15 -0
- package/dist/layout/Grid.js +7 -0
- package/dist/layout/Grid.js.map +1 -0
- package/dist/layout/PageHeader.d.ts +7 -0
- package/dist/layout/PageHeader.js +5 -0
- package/dist/layout/PageHeader.js.map +1 -0
- package/dist/layout/Section.d.ts +16 -0
- package/dist/layout/Section.js +14 -0
- package/dist/layout/Section.js.map +1 -0
- package/dist/layout/Stack.d.ts +20 -0
- package/dist/layout/Stack.js +24 -0
- package/dist/layout/Stack.js.map +1 -0
- package/dist/lib/cx.d.ts +12 -0
- package/dist/lib/cx.js +15 -0
- package/dist/lib/cx.js.map +1 -0
- package/dist/lib/source-probe.d.ts +28 -0
- package/dist/lib/source-probe.js +29 -0
- package/dist/lib/source-probe.js.map +1 -0
- package/dist/lib/spacing.d.ts +54 -0
- package/dist/lib/spacing.js +85 -0
- package/dist/lib/spacing.js.map +1 -0
- package/dist/lib/states.d.ts +44 -0
- package/dist/lib/states.js +45 -0
- package/dist/lib/states.js.map +1 -0
- package/dist/overlay/ConfirmDialog.d.ts +24 -0
- package/dist/overlay/ConfirmDialog.js +17 -0
- package/dist/overlay/ConfirmDialog.js.map +1 -0
- package/dist/overlay/Modal.d.ts +24 -0
- package/dist/overlay/Modal.js +47 -0
- package/dist/overlay/Modal.js.map +1 -0
- package/dist/primitives/Button.d.ts +6 -0
- package/dist/primitives/Button.js +13 -0
- package/dist/primitives/Button.js.map +1 -0
- package/dist/primitives/Checkbox.d.ts +14 -0
- package/dist/primitives/Checkbox.js +19 -0
- package/dist/primitives/Checkbox.js.map +1 -0
- package/dist/primitives/Icon.d.ts +38 -0
- package/dist/primitives/Icon.js +38 -0
- package/dist/primitives/Icon.js.map +1 -0
- package/dist/primitives/Input.d.ts +7 -0
- package/dist/primitives/Input.js +15 -0
- package/dist/primitives/Input.js.map +1 -0
- package/dist/primitives/Radio.d.ts +19 -0
- package/dist/primitives/Radio.js +20 -0
- package/dist/primitives/Radio.js.map +1 -0
- package/dist/primitives/Select.d.ts +9 -0
- package/dist/primitives/Select.js +15 -0
- package/dist/primitives/Select.js.map +1 -0
- package/dist/primitives/Spinner.d.ts +5 -0
- package/dist/primitives/Spinner.js +5 -0
- package/dist/primitives/Spinner.js.map +1 -0
- package/dist/primitives/Switch.d.ts +19 -0
- package/dist/primitives/Switch.js +19 -0
- package/dist/primitives/Switch.js.map +1 -0
- package/dist/primitives/Text.d.ts +7 -0
- package/dist/primitives/Text.js +6 -0
- package/dist/primitives/Text.js.map +1 -0
- package/dist/primitives/Textarea.d.ts +11 -0
- package/dist/primitives/Textarea.js +19 -0
- package/dist/primitives/Textarea.js.map +1 -0
- package/dist/states/EmptyState.d.ts +5 -0
- package/dist/states/EmptyState.js +5 -0
- package/dist/states/EmptyState.js.map +1 -0
- package/dist/states/ErrorState.d.ts +8 -0
- package/dist/states/ErrorState.js +6 -0
- package/dist/states/ErrorState.js.map +1 -0
- package/dist/states/LoadingState.d.ts +18 -0
- package/dist/states/LoadingState.js +19 -0
- package/dist/states/LoadingState.js.map +1 -0
- package/dist/theme/tokens.d.ts +19 -0
- package/dist/theme/tokens.js +20 -0
- package/dist/theme/tokens.js.map +1 -0
- package/package.json +41 -0
- package/themes/default.css +60 -0
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve a responsive prop against one of the tables below.
|
|
3
|
+
* Returns a class string; an undefined value contributes nothing.
|
|
4
|
+
*/
|
|
5
|
+
export function resolve(value, table) {
|
|
6
|
+
if (value === undefined)
|
|
7
|
+
return '';
|
|
8
|
+
if (typeof value !== 'object')
|
|
9
|
+
return table[String(value)]?.base ?? '';
|
|
10
|
+
return ['base', 'sm', 'md', 'lg']
|
|
11
|
+
.map((bp) => {
|
|
12
|
+
const v = value[bp];
|
|
13
|
+
return v === undefined ? '' : (table[String(v)]?.[bp] ?? '');
|
|
14
|
+
})
|
|
15
|
+
.filter(Boolean)
|
|
16
|
+
.join(' ');
|
|
17
|
+
}
|
|
18
|
+
/** `gap` on a flex or grid container. */
|
|
19
|
+
export const GAP = {
|
|
20
|
+
none: { base: 'gap-0', sm: 'sm:gap-0', md: 'md:gap-0', lg: 'lg:gap-0' },
|
|
21
|
+
'3xs': { base: 'gap-x-3xs', sm: 'sm:gap-x-3xs', md: 'md:gap-x-3xs', lg: 'lg:gap-x-3xs' },
|
|
22
|
+
'2xs': { base: 'gap-x-2xs', sm: 'sm:gap-x-2xs', md: 'md:gap-x-2xs', lg: 'lg:gap-x-2xs' },
|
|
23
|
+
xs: { base: 'gap-x-xs', sm: 'sm:gap-x-xs', md: 'md:gap-x-xs', lg: 'lg:gap-x-xs' },
|
|
24
|
+
sm: { base: 'gap-x-sm', sm: 'sm:gap-x-sm', md: 'md:gap-x-sm', lg: 'lg:gap-x-sm' },
|
|
25
|
+
md: { base: 'gap-x-md', sm: 'sm:gap-x-md', md: 'md:gap-x-md', lg: 'lg:gap-x-md' },
|
|
26
|
+
lg: { base: 'gap-x-lg', sm: 'sm:gap-x-lg', md: 'md:gap-x-lg', lg: 'lg:gap-x-lg' },
|
|
27
|
+
xl: { base: 'gap-x-xl', sm: 'sm:gap-x-xl', md: 'md:gap-x-xl', lg: 'lg:gap-x-xl' },
|
|
28
|
+
'2xl': { base: 'gap-x-2xl', sm: 'sm:gap-x-2xl', md: 'md:gap-x-2xl', lg: 'lg:gap-x-2xl' },
|
|
29
|
+
};
|
|
30
|
+
/** Padding on all four sides. */
|
|
31
|
+
export const PAD = {
|
|
32
|
+
none: { base: 'p-0', sm: 'sm:p-0', md: 'md:p-0', lg: 'lg:p-0' },
|
|
33
|
+
'3xs': { base: 'p-x-3xs', sm: 'sm:p-x-3xs', md: 'md:p-x-3xs', lg: 'lg:p-x-3xs' },
|
|
34
|
+
'2xs': { base: 'p-x-2xs', sm: 'sm:p-x-2xs', md: 'md:p-x-2xs', lg: 'lg:p-x-2xs' },
|
|
35
|
+
xs: { base: 'p-x-xs', sm: 'sm:p-x-xs', md: 'md:p-x-xs', lg: 'lg:p-x-xs' },
|
|
36
|
+
sm: { base: 'p-x-sm', sm: 'sm:p-x-sm', md: 'md:p-x-sm', lg: 'lg:p-x-sm' },
|
|
37
|
+
md: { base: 'p-x-md', sm: 'sm:p-x-md', md: 'md:p-x-md', lg: 'lg:p-x-md' },
|
|
38
|
+
lg: { base: 'p-x-lg', sm: 'sm:p-x-lg', md: 'md:p-x-lg', lg: 'lg:p-x-lg' },
|
|
39
|
+
xl: { base: 'p-x-xl', sm: 'sm:p-x-xl', md: 'md:p-x-xl', lg: 'lg:p-x-xl' },
|
|
40
|
+
'2xl': { base: 'p-x-2xl', sm: 'sm:p-x-2xl', md: 'md:p-x-2xl', lg: 'lg:p-x-2xl' },
|
|
41
|
+
};
|
|
42
|
+
/** Inline (left/right) padding. */
|
|
43
|
+
export const PAD_X = {
|
|
44
|
+
none: { base: 'px-0', sm: 'sm:px-0', md: 'md:px-0', lg: 'lg:px-0' },
|
|
45
|
+
'3xs': { base: 'px-x-3xs', sm: 'sm:px-x-3xs', md: 'md:px-x-3xs', lg: 'lg:px-x-3xs' },
|
|
46
|
+
'2xs': { base: 'px-x-2xs', sm: 'sm:px-x-2xs', md: 'md:px-x-2xs', lg: 'lg:px-x-2xs' },
|
|
47
|
+
xs: { base: 'px-x-xs', sm: 'sm:px-x-xs', md: 'md:px-x-xs', lg: 'lg:px-x-xs' },
|
|
48
|
+
sm: { base: 'px-x-sm', sm: 'sm:px-x-sm', md: 'md:px-x-sm', lg: 'lg:px-x-sm' },
|
|
49
|
+
md: { base: 'px-x-md', sm: 'sm:px-x-md', md: 'md:px-x-md', lg: 'lg:px-x-md' },
|
|
50
|
+
lg: { base: 'px-x-lg', sm: 'sm:px-x-lg', md: 'md:px-x-lg', lg: 'lg:px-x-lg' },
|
|
51
|
+
xl: { base: 'px-x-xl', sm: 'sm:px-x-xl', md: 'md:px-x-xl', lg: 'lg:px-x-xl' },
|
|
52
|
+
'2xl': { base: 'px-x-2xl', sm: 'sm:px-x-2xl', md: 'md:px-x-2xl', lg: 'lg:px-x-2xl' },
|
|
53
|
+
};
|
|
54
|
+
/** Block (top/bottom) padding. */
|
|
55
|
+
export const PAD_Y = {
|
|
56
|
+
none: { base: 'py-0', sm: 'sm:py-0', md: 'md:py-0', lg: 'lg:py-0' },
|
|
57
|
+
'3xs': { base: 'py-x-3xs', sm: 'sm:py-x-3xs', md: 'md:py-x-3xs', lg: 'lg:py-x-3xs' },
|
|
58
|
+
'2xs': { base: 'py-x-2xs', sm: 'sm:py-x-2xs', md: 'md:py-x-2xs', lg: 'lg:py-x-2xs' },
|
|
59
|
+
xs: { base: 'py-x-xs', sm: 'sm:py-x-xs', md: 'md:py-x-xs', lg: 'lg:py-x-xs' },
|
|
60
|
+
sm: { base: 'py-x-sm', sm: 'sm:py-x-sm', md: 'md:py-x-sm', lg: 'lg:py-x-sm' },
|
|
61
|
+
md: { base: 'py-x-md', sm: 'sm:py-x-md', md: 'md:py-x-md', lg: 'lg:py-x-md' },
|
|
62
|
+
lg: { base: 'py-x-lg', sm: 'sm:py-x-lg', md: 'md:py-x-lg', lg: 'lg:py-x-lg' },
|
|
63
|
+
xl: { base: 'py-x-xl', sm: 'sm:py-x-xl', md: 'md:py-x-xl', lg: 'lg:py-x-xl' },
|
|
64
|
+
'2xl': { base: 'py-x-2xl', sm: 'sm:py-x-2xl', md: 'md:py-x-2xl', lg: 'lg:py-x-2xl' },
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* Grid column counts. 1–12 rather than only the six the fleet currently uses
|
|
68
|
+
* (1, 2, 3, 4, 5, 7), because a column count is a structural fact about a layout,
|
|
69
|
+
* not a design value — capping it would only push callers back to `grid-cols-*`.
|
|
70
|
+
*/
|
|
71
|
+
export const COLS = {
|
|
72
|
+
1: { base: 'grid-cols-1', sm: 'sm:grid-cols-1', md: 'md:grid-cols-1', lg: 'lg:grid-cols-1' },
|
|
73
|
+
2: { base: 'grid-cols-2', sm: 'sm:grid-cols-2', md: 'md:grid-cols-2', lg: 'lg:grid-cols-2' },
|
|
74
|
+
3: { base: 'grid-cols-3', sm: 'sm:grid-cols-3', md: 'md:grid-cols-3', lg: 'lg:grid-cols-3' },
|
|
75
|
+
4: { base: 'grid-cols-4', sm: 'sm:grid-cols-4', md: 'md:grid-cols-4', lg: 'lg:grid-cols-4' },
|
|
76
|
+
5: { base: 'grid-cols-5', sm: 'sm:grid-cols-5', md: 'md:grid-cols-5', lg: 'lg:grid-cols-5' },
|
|
77
|
+
6: { base: 'grid-cols-6', sm: 'sm:grid-cols-6', md: 'md:grid-cols-6', lg: 'lg:grid-cols-6' },
|
|
78
|
+
7: { base: 'grid-cols-7', sm: 'sm:grid-cols-7', md: 'md:grid-cols-7', lg: 'lg:grid-cols-7' },
|
|
79
|
+
8: { base: 'grid-cols-8', sm: 'sm:grid-cols-8', md: 'md:grid-cols-8', lg: 'lg:grid-cols-8' },
|
|
80
|
+
9: { base: 'grid-cols-9', sm: 'sm:grid-cols-9', md: 'md:grid-cols-9', lg: 'lg:grid-cols-9' },
|
|
81
|
+
10: { base: 'grid-cols-10', sm: 'sm:grid-cols-10', md: 'md:grid-cols-10', lg: 'lg:grid-cols-10' },
|
|
82
|
+
11: { base: 'grid-cols-11', sm: 'sm:grid-cols-11', md: 'md:grid-cols-11', lg: 'lg:grid-cols-11' },
|
|
83
|
+
12: { base: 'grid-cols-12', sm: 'sm:grid-cols-12', md: 'md:grid-cols-12', lg: 'lg:grid-cols-12' },
|
|
84
|
+
};
|
|
85
|
+
//# sourceMappingURL=spacing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spacing.js","sourceRoot":"","sources":["../../src/lib/spacing.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interaction states shared by every control in the kit (#300).
|
|
3
|
+
*
|
|
4
|
+
* 🔴 Why this exists at all: v0.1 shipped `Button`, `Input` and `Select` with **no disabled
|
|
5
|
+
* and no focus styling whatsoever**. The screens that used them wrote `disabled:opacity-50`
|
|
6
|
+
* and `focus:ring-1` themselves — 39 times across the fleet. That was never a deviation to
|
|
7
|
+
* be linted away; it was products patching a hole the kit had left open. Ban those classes
|
|
8
|
+
* before filling the hole and you ship a button that is disabled but does not look it.
|
|
9
|
+
*
|
|
10
|
+
* 🔴 `focus-visible`, not `focus`. `:focus` also fires on a mouse click, leaving a ring
|
|
11
|
+
* behind after every press — which is exactly why the fleet's screens ended up carrying
|
|
12
|
+
* both `focus:` (11 uses) and `focus-visible:` (5). The kit picks one, and picks the one
|
|
13
|
+
* that only shows the ring to keyboard users.
|
|
14
|
+
*
|
|
15
|
+
* 🔴 `outline`, not `ring`. Tailwind's `ring-*` is a box-shadow, so a parent with
|
|
16
|
+
* `overflow-hidden` clips it away entirely. This kit's own `Card` does not clip — but the
|
|
17
|
+
* products' existing containers do: `overflow-hidden` appears 12 times in nene-records and
|
|
18
|
+
* twice each in nene-vault and nene-deal, which are the first two ships to be migrated
|
|
19
|
+
* (measured 2026-08-23). `outline` is not clipped and carries its own offset.
|
|
20
|
+
*
|
|
21
|
+
* 🔴 The ring is `text-primary`, not `accent`. An accent ring is *the same colour as a
|
|
22
|
+
* primary button* — contrast 1.00:1 against its own fill, and 1.11:1 against a danger
|
|
23
|
+
* button (computed from the theme's oklch values, 2026-08-23). The offset keeps the ring
|
|
24
|
+
* off the fill, so what it actually sits against is the page, and both colours clear 3:1
|
|
25
|
+
* there; but a ring that disappears the moment the offset does is one layout change away
|
|
26
|
+
* from being invisible. `text-primary` measures 15.55:1 against `surface`, 16.00:1 against
|
|
27
|
+
* `surface-raised`, and still 3.30:1 / 2.97:1 against the accent and danger fills.
|
|
28
|
+
*
|
|
29
|
+
* No single colour clears 3:1 against *both* fills — accent and danger are both mid
|
|
30
|
+
* luminance — which is why nene-deal moved to a two-tone box-shadow ring (#183, after a
|
|
31
|
+
* 1.38:1 indicator went unnoticed because a contrast checker cannot see it). Here the
|
|
32
|
+
* offset provides the second tone: fill, page-coloured gap, dark ring, page.
|
|
33
|
+
*
|
|
34
|
+
* 🔴 `outline-offset` is therefore load-bearing, not decoration. Do not set it to 0.
|
|
35
|
+
*/
|
|
36
|
+
/** Keyboard focus indicator. Colour comes from the theme, never from a caller. */
|
|
37
|
+
export declare const FOCUS_CLASS = "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-text-primary";
|
|
38
|
+
/**
|
|
39
|
+
* Disabled appearance. The opacity is a theme token (`--opacity-x-disabled`) because a
|
|
40
|
+
* literal here would be a design value living outside themes/default.css.
|
|
41
|
+
*/
|
|
42
|
+
export declare const DISABLED_CLASS = "disabled:opacity-x-disabled disabled:cursor-not-allowed";
|
|
43
|
+
/** Controls that can be focused and disabled — every interactive primitive in the kit. */
|
|
44
|
+
export declare const CONTROL_CLASS = "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-text-primary disabled:opacity-x-disabled disabled:cursor-not-allowed";
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interaction states shared by every control in the kit (#300).
|
|
3
|
+
*
|
|
4
|
+
* 🔴 Why this exists at all: v0.1 shipped `Button`, `Input` and `Select` with **no disabled
|
|
5
|
+
* and no focus styling whatsoever**. The screens that used them wrote `disabled:opacity-50`
|
|
6
|
+
* and `focus:ring-1` themselves — 39 times across the fleet. That was never a deviation to
|
|
7
|
+
* be linted away; it was products patching a hole the kit had left open. Ban those classes
|
|
8
|
+
* before filling the hole and you ship a button that is disabled but does not look it.
|
|
9
|
+
*
|
|
10
|
+
* 🔴 `focus-visible`, not `focus`. `:focus` also fires on a mouse click, leaving a ring
|
|
11
|
+
* behind after every press — which is exactly why the fleet's screens ended up carrying
|
|
12
|
+
* both `focus:` (11 uses) and `focus-visible:` (5). The kit picks one, and picks the one
|
|
13
|
+
* that only shows the ring to keyboard users.
|
|
14
|
+
*
|
|
15
|
+
* 🔴 `outline`, not `ring`. Tailwind's `ring-*` is a box-shadow, so a parent with
|
|
16
|
+
* `overflow-hidden` clips it away entirely. This kit's own `Card` does not clip — but the
|
|
17
|
+
* products' existing containers do: `overflow-hidden` appears 12 times in nene-records and
|
|
18
|
+
* twice each in nene-vault and nene-deal, which are the first two ships to be migrated
|
|
19
|
+
* (measured 2026-08-23). `outline` is not clipped and carries its own offset.
|
|
20
|
+
*
|
|
21
|
+
* 🔴 The ring is `text-primary`, not `accent`. An accent ring is *the same colour as a
|
|
22
|
+
* primary button* — contrast 1.00:1 against its own fill, and 1.11:1 against a danger
|
|
23
|
+
* button (computed from the theme's oklch values, 2026-08-23). The offset keeps the ring
|
|
24
|
+
* off the fill, so what it actually sits against is the page, and both colours clear 3:1
|
|
25
|
+
* there; but a ring that disappears the moment the offset does is one layout change away
|
|
26
|
+
* from being invisible. `text-primary` measures 15.55:1 against `surface`, 16.00:1 against
|
|
27
|
+
* `surface-raised`, and still 3.30:1 / 2.97:1 against the accent and danger fills.
|
|
28
|
+
*
|
|
29
|
+
* No single colour clears 3:1 against *both* fills — accent and danger are both mid
|
|
30
|
+
* luminance — which is why nene-deal moved to a two-tone box-shadow ring (#183, after a
|
|
31
|
+
* 1.38:1 indicator went unnoticed because a contrast checker cannot see it). Here the
|
|
32
|
+
* offset provides the second tone: fill, page-coloured gap, dark ring, page.
|
|
33
|
+
*
|
|
34
|
+
* 🔴 `outline-offset` is therefore load-bearing, not decoration. Do not set it to 0.
|
|
35
|
+
*/
|
|
36
|
+
/** Keyboard focus indicator. Colour comes from the theme, never from a caller. */
|
|
37
|
+
export const FOCUS_CLASS = 'focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-text-primary';
|
|
38
|
+
/**
|
|
39
|
+
* Disabled appearance. The opacity is a theme token (`--opacity-x-disabled`) because a
|
|
40
|
+
* literal here would be a design value living outside themes/default.css.
|
|
41
|
+
*/
|
|
42
|
+
export const DISABLED_CLASS = 'disabled:opacity-x-disabled disabled:cursor-not-allowed';
|
|
43
|
+
/** Controls that can be focused and disabled — every interactive primitive in the kit. */
|
|
44
|
+
export const CONTROL_CLASS = `${FOCUS_CLASS} ${DISABLED_CLASS}`;
|
|
45
|
+
//# sourceMappingURL=states.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"states.js","sourceRoot":"","sources":["../../src/lib/states.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAEH,kFAAkF;AAClF,MAAM,CAAC,MAAM,WAAW,GACtB,2FAA2F,CAAC;AAE9F;;;GAGG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,yDAAyD,CAAC;AAExF,0FAA0F;AAC1F,MAAM,CAAC,MAAM,aAAa,GAAG,GAAG,WAAW,IAAI,cAAc,EAAE,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export interface ConfirmDialogProps {
|
|
2
|
+
open: boolean;
|
|
3
|
+
/** Localized title. */
|
|
4
|
+
title: string;
|
|
5
|
+
/** Localized body. */
|
|
6
|
+
message: string;
|
|
7
|
+
/** Localized label for the affirmative control. */
|
|
8
|
+
confirmLabel: string;
|
|
9
|
+
/** Localized label for the dismissive control. */
|
|
10
|
+
cancelLabel: string;
|
|
11
|
+
onConfirm: () => void;
|
|
12
|
+
onCancel: () => void;
|
|
13
|
+
/** `danger` for destructive confirmations. Chooses a variant, never a colour. */
|
|
14
|
+
tone?: 'default' | 'danger';
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* "Are you sure?" — the same dialog five ships wrote separately.
|
|
18
|
+
*
|
|
19
|
+
* 🔴 Cancel comes first in the DOM. It is the safe choice, so it is the one that should be
|
|
20
|
+
* reached first by keyboard and the one focus lands on when the dialog opens. A destructive
|
|
21
|
+
* confirmation whose dangerous button is the default is a footgun, and it is exactly the
|
|
22
|
+
* kind of detail that differs between five independent implementations.
|
|
23
|
+
*/
|
|
24
|
+
export declare function ConfirmDialog({ open, title, message, confirmLabel, cancelLabel, onConfirm, onCancel, tone, }: ConfirmDialogProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Button } from '../primitives/Button.js';
|
|
3
|
+
import { Stack } from '../layout/Stack.js';
|
|
4
|
+
import { Text } from '../primitives/Text.js';
|
|
5
|
+
import { Modal } from './Modal.js';
|
|
6
|
+
/**
|
|
7
|
+
* "Are you sure?" — the same dialog five ships wrote separately.
|
|
8
|
+
*
|
|
9
|
+
* 🔴 Cancel comes first in the DOM. It is the safe choice, so it is the one that should be
|
|
10
|
+
* reached first by keyboard and the one focus lands on when the dialog opens. A destructive
|
|
11
|
+
* confirmation whose dangerous button is the default is a footgun, and it is exactly the
|
|
12
|
+
* kind of detail that differs between five independent implementations.
|
|
13
|
+
*/
|
|
14
|
+
export function ConfirmDialog({ open, title, message, confirmLabel, cancelLabel, onConfirm, onCancel, tone = 'default', }) {
|
|
15
|
+
return (_jsx(Modal, { open: open, onClose: onCancel, title: title, children: _jsxs(Stack, { gap: "xs", children: [_jsx(Text, { children: message }), _jsxs(Stack, { direction: "horizontal", gap: "2xs", justify: "end", children: [_jsx(Button, { variant: "secondary", onClick: onCancel, children: cancelLabel }), _jsx(Button, { variant: tone === 'danger' ? 'danger' : 'primary', onClick: onConfirm, children: confirmLabel })] })] }) }));
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=ConfirmDialog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ConfirmDialog.js","sourceRoot":"","sources":["../../src/overlay/ConfirmDialog.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AACjD,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAC7C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAkBnC;;;;;;;GAOG;AACH,MAAM,UAAU,aAAa,CAAC,EAC5B,IAAI,EACJ,KAAK,EACL,OAAO,EACP,YAAY,EACZ,WAAW,EACX,SAAS,EACT,QAAQ,EACR,IAAI,GAAG,SAAS,GACG;IACnB,OAAO,CACL,KAAC,KAAK,IAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,YAChD,MAAC,KAAK,IAAC,GAAG,EAAC,IAAI,aACb,KAAC,IAAI,cAAE,OAAO,GAAQ,EACtB,MAAC,KAAK,IAAC,SAAS,EAAC,YAAY,EAAC,GAAG,EAAC,KAAK,EAAC,OAAO,EAAC,KAAK,aACnD,KAAC,MAAM,IAAC,OAAO,EAAC,WAAW,EAAC,OAAO,EAAE,QAAQ,YAC1C,WAAW,GACL,EACT,KAAC,MAAM,IAAC,OAAO,EAAE,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,EAAE,OAAO,EAAE,SAAS,YAC1E,YAAY,GACN,IACH,IACF,GACF,CACT,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
export interface ModalProps {
|
|
3
|
+
open: boolean;
|
|
4
|
+
/** Called for every dismissal the browser owns: Esc, the close control, the backdrop. */
|
|
5
|
+
onClose: () => void;
|
|
6
|
+
/** Localized title. Also names the dialog for assistive tech. */
|
|
7
|
+
title: string;
|
|
8
|
+
children: ReactNode;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* A modal dialog built on the native `<dialog>` element.
|
|
12
|
+
*
|
|
13
|
+
* 🔴 Why native. Focus trapping, Esc-to-dismiss, the backdrop, and rendering above every
|
|
14
|
+
* stacking context are all things the browser already does correctly. Eight ships wrote
|
|
15
|
+
* their own modal, which means the fleet currently maintains eight focus traps — the single
|
|
16
|
+
* hardest piece of interaction code to get right, reimplemented per product.
|
|
17
|
+
*
|
|
18
|
+
* 🔴 `showModal()` is called imperatively rather than through the `open` attribute, because
|
|
19
|
+
* only `showModal()` puts the dialog in the top layer and traps focus; setting `open`
|
|
20
|
+
* renders it inline and non-modal. jsdom 25.0.1 does not implement `showModal` at all
|
|
21
|
+
* (measured 2026-08-23), and neither do browsers older than the feature, so the fallback
|
|
22
|
+
* sets `open` — degraded but visible, rather than a dialog that never appears.
|
|
23
|
+
*/
|
|
24
|
+
export declare function Modal({ open, onClose, title, children }: ModalProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useRef } from 'react';
|
|
3
|
+
import { cx } from '../lib/cx.js';
|
|
4
|
+
/**
|
|
5
|
+
* A modal dialog built on the native `<dialog>` element.
|
|
6
|
+
*
|
|
7
|
+
* 🔴 Why native. Focus trapping, Esc-to-dismiss, the backdrop, and rendering above every
|
|
8
|
+
* stacking context are all things the browser already does correctly. Eight ships wrote
|
|
9
|
+
* their own modal, which means the fleet currently maintains eight focus traps — the single
|
|
10
|
+
* hardest piece of interaction code to get right, reimplemented per product.
|
|
11
|
+
*
|
|
12
|
+
* 🔴 `showModal()` is called imperatively rather than through the `open` attribute, because
|
|
13
|
+
* only `showModal()` puts the dialog in the top layer and traps focus; setting `open`
|
|
14
|
+
* renders it inline and non-modal. jsdom 25.0.1 does not implement `showModal` at all
|
|
15
|
+
* (measured 2026-08-23), and neither do browsers older than the feature, so the fallback
|
|
16
|
+
* sets `open` — degraded but visible, rather than a dialog that never appears.
|
|
17
|
+
*/
|
|
18
|
+
export function Modal({ open, onClose, title, children }) {
|
|
19
|
+
const ref = useRef(null);
|
|
20
|
+
useEffect(() => {
|
|
21
|
+
const el = ref.current;
|
|
22
|
+
if (el === null)
|
|
23
|
+
return;
|
|
24
|
+
if (open) {
|
|
25
|
+
if (typeof el.showModal === 'function') {
|
|
26
|
+
if (!el.open)
|
|
27
|
+
el.showModal();
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
el.setAttribute('open', '');
|
|
31
|
+
}
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
if (typeof el.close === 'function') {
|
|
35
|
+
if (el.open)
|
|
36
|
+
el.close();
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
el.removeAttribute('open');
|
|
40
|
+
}
|
|
41
|
+
}, [open]);
|
|
42
|
+
return (_jsx("dialog", { ref: ref, "aria-label": title,
|
|
43
|
+
// The browser fires `close` for Esc as well as for close(); routing both through the
|
|
44
|
+
// caller keeps `open` from drifting out of sync with what is on screen.
|
|
45
|
+
onClose: onClose, onCancel: onClose, className: cx('bg-surface-raised text-text-primary border border-border rounded-x-md', 'p-x-sm font-sans backdrop:bg-text-primary/50'), children: children }));
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=Modal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Modal.js","sourceRoot":"","sources":["../../src/overlay/Modal.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,EAAkB,MAAM,OAAO,CAAC;AAC1D,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAWlC;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,KAAK,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAc;IAClE,MAAM,GAAG,GAAG,MAAM,CAAoB,IAAI,CAAC,CAAC;IAE5C,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,EAAE,GAAG,GAAG,CAAC,OAAO,CAAC;QACvB,IAAI,EAAE,KAAK,IAAI;YAAE,OAAO;QAExB,IAAI,IAAI,EAAE,CAAC;YACT,IAAI,OAAO,EAAE,CAAC,SAAS,KAAK,UAAU,EAAE,CAAC;gBACvC,IAAI,CAAC,EAAE,CAAC,IAAI;oBAAE,EAAE,CAAC,SAAS,EAAE,CAAC;YAC/B,CAAC;iBAAM,CAAC;gBACN,EAAE,CAAC,YAAY,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;YAC9B,CAAC;YACD,OAAO;QACT,CAAC;QAED,IAAI,OAAO,EAAE,CAAC,KAAK,KAAK,UAAU,EAAE,CAAC;YACnC,IAAI,EAAE,CAAC,IAAI;gBAAE,EAAE,CAAC,KAAK,EAAE,CAAC;QAC1B,CAAC;aAAM,CAAC;YACN,EAAE,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;IAEX,OAAO,CACL,iBACE,GAAG,EAAE,GAAG,gBACI,KAAK;QACjB,qFAAqF;QACrF,wEAAwE;QACxE,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,OAAO,EACjB,SAAS,EAAE,EAAE,CACX,uEAAuE,EACvE,8CAA8C,CAC/C,YAEA,QAAQ,GACF,CACV,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ButtonHTMLAttributes, ReactNode } from 'react';
|
|
2
|
+
export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
3
|
+
variant?: 'primary' | 'secondary' | 'danger';
|
|
4
|
+
children: ReactNode;
|
|
5
|
+
}
|
|
6
|
+
export declare function Button({ variant, children, type, className, ...rest }: ButtonProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { cx } from '../lib/cx.js';
|
|
3
|
+
import { CONTROL_CLASS } from '../lib/states.js';
|
|
4
|
+
const VARIANT_CLASS = {
|
|
5
|
+
primary: 'bg-accent text-on-accent',
|
|
6
|
+
secondary: 'bg-surface-raised text-text-primary border border-border',
|
|
7
|
+
danger: 'bg-danger text-on-accent',
|
|
8
|
+
};
|
|
9
|
+
const BASE_CLASS = `rounded-x-md px-x-inline-md py-x-stack-sm font-sans font-medium ${CONTROL_CLASS}`;
|
|
10
|
+
export function Button({ variant = 'primary', children, type = 'button', className, ...rest }) {
|
|
11
|
+
return (_jsx("button", { type: type, className: cx(BASE_CLASS, VARIANT_CLASS[variant], className), ...rest, children: children }));
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=Button.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Button.js","sourceRoot":"","sources":["../../src/primitives/Button.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAOjD,MAAM,aAAa,GAAwD;IACzE,OAAO,EAAE,0BAA0B;IACnC,SAAS,EAAE,0DAA0D;IACrE,MAAM,EAAE,0BAA0B;CACnC,CAAC;AAEF,MAAM,UAAU,GAAG,mEAAmE,aAAa,EAAE,CAAC;AAEtG,MAAM,UAAU,MAAM,CAAC,EACrB,OAAO,GAAG,SAAS,EACnB,QAAQ,EACR,IAAI,GAAG,QAAQ,EACf,SAAS,EACT,GAAG,IAAI,EACK;IACZ,OAAO,CACL,iBAAQ,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,CAAC,UAAU,EAAE,aAAa,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC,KAAM,IAAI,YACvF,QAAQ,GACF,CACV,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type InputHTMLAttributes, type ReactNode } from 'react';
|
|
2
|
+
export interface CheckboxProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'type'> {
|
|
3
|
+
/** Localized label. Rendered inside the control's own `<label>`. */
|
|
4
|
+
label: ReactNode;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* A checkbox and its label, as one part.
|
|
8
|
+
*
|
|
9
|
+
* 🔴 The label is not optional and not a sibling. The recurring shape in the fleet is an
|
|
10
|
+
* `<input>` next to a `<label>` whose `htmlFor` is missing or stale — which loses nothing
|
|
11
|
+
* visible, and loses the ability to click the text to toggle the box, plus the name the
|
|
12
|
+
* control is announced by. Making the label a prop means it cannot be forgotten.
|
|
13
|
+
*/
|
|
14
|
+
export declare const Checkbox: import("react").ForwardRefExoticComponent<CheckboxProps & import("react").RefAttributes<HTMLInputElement>>;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef } from 'react';
|
|
3
|
+
import { cx } from '../lib/cx.js';
|
|
4
|
+
import { CONTROL_CLASS } from '../lib/states.js';
|
|
5
|
+
import { useFieldWiring } from '../forms/field-context.js';
|
|
6
|
+
const BOX_CLASS = `rounded-x-md border border-border accent-accent ${CONTROL_CLASS}`;
|
|
7
|
+
/**
|
|
8
|
+
* A checkbox and its label, as one part.
|
|
9
|
+
*
|
|
10
|
+
* 🔴 The label is not optional and not a sibling. The recurring shape in the fleet is an
|
|
11
|
+
* `<input>` next to a `<label>` whose `htmlFor` is missing or stale — which loses nothing
|
|
12
|
+
* visible, and loses the ability to click the text to toggle the box, plus the name the
|
|
13
|
+
* control is announced by. Making the label a prop means it cannot be forgotten.
|
|
14
|
+
*/
|
|
15
|
+
export const Checkbox = forwardRef(function Checkbox({ label, className, id, 'aria-invalid': ariaInvalid, 'aria-describedby': ariaDescribedBy, 'aria-required': ariaRequired, ...rest }, ref) {
|
|
16
|
+
const wiring = useFieldWiring({ id, ariaInvalid, ariaDescribedBy, ariaRequired });
|
|
17
|
+
return (_jsxs("label", { className: "inline-flex items-center gap-x-2xs font-sans text-text-primary", children: [_jsx("input", { ref: ref, type: "checkbox", className: cx(BOX_CLASS, className), ...wiring, ...rest }), label] }));
|
|
18
|
+
});
|
|
19
|
+
//# sourceMappingURL=Checkbox.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Checkbox.js","sourceRoot":"","sources":["../../src/primitives/Checkbox.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,UAAU,EAA4C,MAAM,OAAO,CAAC;AAC7E,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAO3D,MAAM,SAAS,GAAG,mDAAmD,aAAa,EAAE,CAAC;AAErF;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,UAAU,CAAkC,SAAS,QAAQ,CACnF,EACE,KAAK,EACL,SAAS,EACT,EAAE,EACF,cAAc,EAAE,WAAW,EAC3B,kBAAkB,EAAE,eAAe,EACnC,eAAe,EAAE,YAAY,EAC7B,GAAG,IAAI,EACR,EACD,GAAG;IAEH,MAAM,MAAM,GAAG,cAAc,CAAC,EAAE,EAAE,EAAE,WAAW,EAAE,eAAe,EAAE,YAAY,EAAE,CAAC,CAAC;IAElF,OAAO,CACL,iBAAO,SAAS,EAAC,gEAAgE,aAC/E,gBAAO,GAAG,EAAE,GAAG,EAAE,IAAI,EAAC,UAAU,EAAC,SAAS,EAAE,EAAE,CAAC,SAAS,EAAE,SAAS,CAAC,KAAM,MAAM,KAAM,IAAI,GAAI,EAC7F,KAAK,IACA,CACT,CAAC;AACJ,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { ReactNode, SVGProps } from 'react';
|
|
2
|
+
type IconSize = 'sm' | 'md' | 'lg';
|
|
3
|
+
interface IconBase extends Omit<SVGProps<SVGSVGElement>, 'children' | 'aria-label'> {
|
|
4
|
+
/** The `<path>`, `<circle>`… of a 24×24 icon. The kit ships no artwork. */
|
|
5
|
+
children: ReactNode;
|
|
6
|
+
size?: IconSize;
|
|
7
|
+
}
|
|
8
|
+
interface MeaningfulIcon extends IconBase {
|
|
9
|
+
/** Localized name. Present when the icon carries meaning of its own. */
|
|
10
|
+
label: string;
|
|
11
|
+
decorative?: never;
|
|
12
|
+
}
|
|
13
|
+
interface DecorativeIcon extends IconBase {
|
|
14
|
+
/** The icon repeats something already in text, so it is hidden from assistive tech. */
|
|
15
|
+
decorative: true;
|
|
16
|
+
label?: never;
|
|
17
|
+
}
|
|
18
|
+
export type IconProps = MeaningfulIcon | DecorativeIcon;
|
|
19
|
+
/**
|
|
20
|
+
* The semantics around an icon — not the icon.
|
|
21
|
+
*
|
|
22
|
+
* 🔴 The kit ships no artwork and takes on no icon library, because the fleet has none:
|
|
23
|
+
* across all ten products the dependency count for lucide / heroicons / feather / phosphor
|
|
24
|
+
* / tabler is zero, and every icon is an inline `<svg>` (222 of them, measured 2026-08-23).
|
|
25
|
+
* Choosing a set would mean adding a dependency to seventeen ships to solve a problem they
|
|
26
|
+
* do not have.
|
|
27
|
+
*
|
|
28
|
+
* 🔴 What is not consistent is the meaning. Of those 222, **101 declare neither
|
|
29
|
+
* `aria-hidden` nor `role="img"`** — they do not say whether they are decoration or
|
|
30
|
+
* content, so assistive technology is left to guess, and the page looks entirely correct
|
|
31
|
+
* either way. Three carry `role="img"`; none carries a `<title>`.
|
|
32
|
+
*
|
|
33
|
+
* So `label` and `decorative` are mutually exclusive and one of them is required, enforced
|
|
34
|
+
* by the type. An icon that can be rendered without saying which it is would reproduce the
|
|
35
|
+
* 101 exactly.
|
|
36
|
+
*/
|
|
37
|
+
export declare function Icon({ children, size, className, ...rest }: IconProps): import("react").JSX.Element;
|
|
38
|
+
export {};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { cx } from '../lib/cx.js';
|
|
3
|
+
const SIZE_CLASS = {
|
|
4
|
+
sm: 'h-4 w-4',
|
|
5
|
+
md: 'h-5 w-5',
|
|
6
|
+
lg: 'h-6 w-6',
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* The semantics around an icon — not the icon.
|
|
10
|
+
*
|
|
11
|
+
* 🔴 The kit ships no artwork and takes on no icon library, because the fleet has none:
|
|
12
|
+
* across all ten products the dependency count for lucide / heroicons / feather / phosphor
|
|
13
|
+
* / tabler is zero, and every icon is an inline `<svg>` (222 of them, measured 2026-08-23).
|
|
14
|
+
* Choosing a set would mean adding a dependency to seventeen ships to solve a problem they
|
|
15
|
+
* do not have.
|
|
16
|
+
*
|
|
17
|
+
* 🔴 What is not consistent is the meaning. Of those 222, **101 declare neither
|
|
18
|
+
* `aria-hidden` nor `role="img"`** — they do not say whether they are decoration or
|
|
19
|
+
* content, so assistive technology is left to guess, and the page looks entirely correct
|
|
20
|
+
* either way. Three carry `role="img"`; none carries a `<title>`.
|
|
21
|
+
*
|
|
22
|
+
* So `label` and `decorative` are mutually exclusive and one of them is required, enforced
|
|
23
|
+
* by the type. An icon that can be rendered without saying which it is would reproduce the
|
|
24
|
+
* 101 exactly.
|
|
25
|
+
*/
|
|
26
|
+
export function Icon({ children, size = 'md', className, ...rest }) {
|
|
27
|
+
const { label, ...svgProps } = rest;
|
|
28
|
+
delete svgProps.decorative;
|
|
29
|
+
// 🔴 Falls back to decoration, not to `role="img"`. A JS caller or a stale build can reach
|
|
30
|
+
// here with neither prop, and a nameless `role="img"` is worse than silence: assistive
|
|
31
|
+
// technology announces "image" and stops. An empty string counts as missing too — that is
|
|
32
|
+
// what an unresolved translation key looks like at runtime.
|
|
33
|
+
const decorative = label === undefined || label === '';
|
|
34
|
+
return (_jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 1.5, className: cx(SIZE_CLASS[size], 'shrink-0', className), ...(decorative
|
|
35
|
+
? { 'aria-hidden': true, focusable: false }
|
|
36
|
+
: { role: 'img', 'aria-label': label }), ...svgProps, children: children }));
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=Icon.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Icon.js","sourceRoot":"","sources":["../../src/primitives/Icon.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAwBlC,MAAM,UAAU,GAA6B;IAC3C,EAAE,EAAE,SAAS;IACb,EAAE,EAAE,SAAS;IACb,EAAE,EAAE,SAAS;CACd,CAAC;AAEF;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,IAAI,CAAC,EAAE,QAAQ,EAAE,IAAI,GAAG,IAAI,EAAE,SAAS,EAAE,GAAG,IAAI,EAAa;IAC3E,MAAM,EAAE,KAAK,EAAE,GAAG,QAAQ,EAAE,GAAG,IAEJ,CAAC;IAC5B,OAAQ,QAAqC,CAAC,UAAU,CAAC;IAEzD,2FAA2F;IAC3F,uFAAuF;IACvF,0FAA0F;IAC1F,4DAA4D;IAC5D,MAAM,UAAU,GAAG,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,EAAE,CAAC;IAEvD,OAAO,CACL,cACE,OAAO,EAAC,WAAW,EACnB,IAAI,EAAC,MAAM,EACX,MAAM,EAAC,cAAc,EACrB,WAAW,EAAE,GAAG,EAChB,SAAS,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,UAAU,EAAE,SAAS,CAAC,KAClD,CAAC,UAAU;YACb,CAAC,CAAC,EAAE,aAAa,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE;YAC3C,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC,KACrC,QAAQ,YAEX,QAAQ,GACL,CACP,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type InputHTMLAttributes } from 'react';
|
|
2
|
+
export type InputProps = InputHTMLAttributes<HTMLInputElement>;
|
|
3
|
+
/**
|
|
4
|
+
* Text input primitive. forwardRef so it works directly with react-hook-form `register`.
|
|
5
|
+
* Visual values come from theme tokens only.
|
|
6
|
+
*/
|
|
7
|
+
export declare const Input: import("react").ForwardRefExoticComponent<InputProps & import("react").RefAttributes<HTMLInputElement>>;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef } from 'react';
|
|
3
|
+
import { cx } from '../lib/cx.js';
|
|
4
|
+
import { CONTROL_CLASS } from '../lib/states.js';
|
|
5
|
+
import { useFieldWiring } from '../forms/field-context.js';
|
|
6
|
+
const BASE_CLASS = `w-full rounded-x-md border border-border bg-surface-raised px-x-inline-sm py-x-stack-sm font-sans text-text-primary placeholder:text-text-muted ${CONTROL_CLASS}`;
|
|
7
|
+
/**
|
|
8
|
+
* Text input primitive. forwardRef so it works directly with react-hook-form `register`.
|
|
9
|
+
* Visual values come from theme tokens only.
|
|
10
|
+
*/
|
|
11
|
+
export const Input = forwardRef(function Input({ className, id, 'aria-invalid': ariaInvalid, 'aria-describedby': ariaDescribedBy, 'aria-required': ariaRequired, ...rest }, ref) {
|
|
12
|
+
const wiring = useFieldWiring({ id, ariaInvalid, ariaDescribedBy, ariaRequired });
|
|
13
|
+
return _jsx("input", { ref: ref, className: cx(BASE_CLASS, className), ...wiring, ...rest });
|
|
14
|
+
});
|
|
15
|
+
//# sourceMappingURL=Input.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Input.js","sourceRoot":"","sources":["../../src/primitives/Input.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,UAAU,EAA4B,MAAM,OAAO,CAAC;AAC7D,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAI3D,MAAM,UAAU,GAAG,mJAAmJ,aAAa,EAAE,CAAC;AAEtL;;;GAGG;AACH,MAAM,CAAC,MAAM,KAAK,GAAG,UAAU,CAA+B,SAAS,KAAK,CAC1E,EACE,SAAS,EACT,EAAE,EACF,cAAc,EAAE,WAAW,EAC3B,kBAAkB,EAAE,eAAe,EACnC,eAAe,EAAE,YAAY,EAC7B,GAAG,IAAI,EACR,EACD,GAAG;IAEH,MAAM,MAAM,GAAG,cAAc,CAAC,EAAE,EAAE,EAAE,WAAW,EAAE,eAAe,EAAE,YAAY,EAAE,CAAC,CAAC;IAElF,OAAO,gBAAO,GAAG,EAAE,GAAG,EAAE,SAAS,EAAE,EAAE,CAAC,UAAU,EAAE,SAAS,CAAC,KAAM,MAAM,KAAM,IAAI,GAAI,CAAC;AACzF,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type InputHTMLAttributes, type ReactNode } from 'react';
|
|
2
|
+
export interface RadioProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'type'> {
|
|
3
|
+
/** Localized label. Rendered inside the control's own `<label>`. */
|
|
4
|
+
label: ReactNode;
|
|
5
|
+
/** Radios only mean anything in a group; `name` is what makes them one. */
|
|
6
|
+
name: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* One option in a radio group, with its label.
|
|
10
|
+
*
|
|
11
|
+
* 🔴 `name` is required, unlike on a bare `<input type="radio">`. A radio without a name is
|
|
12
|
+
* its own group of one: it can be checked but never unchecked, and arrow keys do not move
|
|
13
|
+
* between the options. Nothing about the rendered page shows this, so it survives review.
|
|
14
|
+
*
|
|
15
|
+
* 🔴 This does not take the `FormField` wiring. A group of radios shares one label and one
|
|
16
|
+
* error, so the id and `aria-describedby` belong on a `<fieldset>` around the group, not on
|
|
17
|
+
* each option — putting them here would give every option the same id.
|
|
18
|
+
*/
|
|
19
|
+
export declare const Radio: import("react").ForwardRefExoticComponent<RadioProps & import("react").RefAttributes<HTMLInputElement>>;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef } from 'react';
|
|
3
|
+
import { cx } from '../lib/cx.js';
|
|
4
|
+
import { CONTROL_CLASS } from '../lib/states.js';
|
|
5
|
+
const DOT_CLASS = `border border-border accent-accent ${CONTROL_CLASS}`;
|
|
6
|
+
/**
|
|
7
|
+
* One option in a radio group, with its label.
|
|
8
|
+
*
|
|
9
|
+
* 🔴 `name` is required, unlike on a bare `<input type="radio">`. A radio without a name is
|
|
10
|
+
* its own group of one: it can be checked but never unchecked, and arrow keys do not move
|
|
11
|
+
* between the options. Nothing about the rendered page shows this, so it survives review.
|
|
12
|
+
*
|
|
13
|
+
* 🔴 This does not take the `FormField` wiring. A group of radios shares one label and one
|
|
14
|
+
* error, so the id and `aria-describedby` belong on a `<fieldset>` around the group, not on
|
|
15
|
+
* each option — putting them here would give every option the same id.
|
|
16
|
+
*/
|
|
17
|
+
export const Radio = forwardRef(function Radio({ label, name, className, ...rest }, ref) {
|
|
18
|
+
return (_jsxs("label", { className: "inline-flex items-center gap-x-2xs font-sans text-text-primary", children: [_jsx("input", { ref: ref, type: "radio", name: name, className: cx(DOT_CLASS, className), ...rest }), label] }));
|
|
19
|
+
});
|
|
20
|
+
//# sourceMappingURL=Radio.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Radio.js","sourceRoot":"","sources":["../../src/primitives/Radio.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,UAAU,EAA4C,MAAM,OAAO,CAAC;AAC7E,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AASjD,MAAM,SAAS,GAAG,sCAAsC,aAAa,EAAE,CAAC;AAExE;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,KAAK,GAAG,UAAU,CAA+B,SAAS,KAAK,CAC1E,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,IAAI,EAAE,EACnC,GAAG;IAEH,OAAO,CACL,iBAAO,SAAS,EAAC,gEAAgE,aAC/E,gBAAO,GAAG,EAAE,GAAG,EAAE,IAAI,EAAC,OAAO,EAAC,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,CAAC,SAAS,EAAE,SAAS,CAAC,KAAM,IAAI,GAAI,EAC1F,KAAK,IACA,CACT,CAAC;AACJ,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type ReactNode, type SelectHTMLAttributes } from 'react';
|
|
2
|
+
export interface SelectProps extends SelectHTMLAttributes<HTMLSelectElement> {
|
|
3
|
+
children: ReactNode;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Select primitive. forwardRef so it works directly with react-hook-form `register`.
|
|
7
|
+
* Visual values come from theme tokens only.
|
|
8
|
+
*/
|
|
9
|
+
export declare const Select: import("react").ForwardRefExoticComponent<SelectProps & import("react").RefAttributes<HTMLSelectElement>>;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef } from 'react';
|
|
3
|
+
import { cx } from '../lib/cx.js';
|
|
4
|
+
import { CONTROL_CLASS } from '../lib/states.js';
|
|
5
|
+
import { useFieldWiring } from '../forms/field-context.js';
|
|
6
|
+
const BASE_CLASS = `w-full rounded-x-md border border-border bg-surface-raised px-x-inline-sm py-x-stack-sm font-sans text-text-primary ${CONTROL_CLASS}`;
|
|
7
|
+
/**
|
|
8
|
+
* Select primitive. forwardRef so it works directly with react-hook-form `register`.
|
|
9
|
+
* Visual values come from theme tokens only.
|
|
10
|
+
*/
|
|
11
|
+
export const Select = forwardRef(function Select({ children, className, id, 'aria-invalid': ariaInvalid, 'aria-describedby': ariaDescribedBy, 'aria-required': ariaRequired, ...rest }, ref) {
|
|
12
|
+
const wiring = useFieldWiring({ id, ariaInvalid, ariaDescribedBy, ariaRequired });
|
|
13
|
+
return (_jsx("select", { ref: ref, className: cx(BASE_CLASS, className), ...wiring, ...rest, children: children }));
|
|
14
|
+
});
|
|
15
|
+
//# sourceMappingURL=Select.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Select.js","sourceRoot":"","sources":["../../src/primitives/Select.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,UAAU,EAA6C,MAAM,OAAO,CAAC;AAC9E,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAM3D,MAAM,UAAU,GAAG,uHAAuH,aAAa,EAAE,CAAC;AAE1J;;;GAGG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,UAAU,CAAiC,SAAS,MAAM,CAC9E,EACE,QAAQ,EACR,SAAS,EACT,EAAE,EACF,cAAc,EAAE,WAAW,EAC3B,kBAAkB,EAAE,eAAe,EACnC,eAAe,EAAE,YAAY,EAC7B,GAAG,IAAI,EACR,EACD,GAAG;IAEH,MAAM,MAAM,GAAG,cAAc,CAAC,EAAE,EAAE,EAAE,WAAW,EAAE,eAAe,EAAE,YAAY,EAAE,CAAC,CAAC;IAElF,OAAO,CACL,iBAAQ,GAAG,EAAE,GAAG,EAAE,SAAS,EAAE,EAAE,CAAC,UAAU,EAAE,SAAS,CAAC,KAAM,MAAM,KAAM,IAAI,YACzE,QAAQ,GACF,CACV,CAAC;AACJ,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Spinner.js","sourceRoot":"","sources":["../../src/primitives/Spinner.tsx"],"names":[],"mappings":";AAKA,MAAM,UAAU,OAAO,CAAC,EAAE,KAAK,EAAgB;IAC7C,OAAO,CACL,iBAAQ,SAAS,EAAC,2BAA2B,eAAW,QAAQ,YAC7D,KAAK,GACC,CACV,CAAC;AACJ,CAAC"}
|