@hideyukimori/nene2-ui 0.19.1 โ 0.21.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 +10 -0
- package/dist/data/Pagination.js +2 -2
- package/dist/data/Pagination.js.map +1 -1
- package/dist/feedback/Badge.d.ts +17 -1
- package/dist/feedback/Badge.js +3 -3
- package/dist/feedback/Badge.js.map +1 -1
- package/dist/feedback/InlineAlert.d.ts +11 -5
- package/dist/feedback/InlineAlert.js +10 -3
- package/dist/feedback/InlineAlert.js.map +1 -1
- package/dist/layout/PageHeader.d.ts +19 -1
- package/dist/layout/PageHeader.js +3 -2
- package/dist/layout/PageHeader.js.map +1 -1
- package/dist/overlay/ConfirmDialog.js +1 -1
- package/dist/overlay/ConfirmDialog.js.map +1 -1
- package/dist/overlay/Modal.d.ts +27 -0
- package/dist/overlay/Modal.js +9 -2
- package/dist/overlay/Modal.js.map +1 -1
- package/dist/primitives/Button.d.ts +33 -2
- package/dist/primitives/Button.js +90 -13
- package/dist/primitives/Button.js.map +1 -1
- package/dist/states/ErrorState.js +1 -1
- package/dist/states/ErrorState.js.map +1 -1
- package/package.json +1 -1
- package/themes/default.css +86 -18
package/README.md
CHANGED
|
@@ -35,6 +35,16 @@ bound. Providing the parts scales with the number of screens, which is finite.**
|
|
|
35
35
|
cannot express it, add a variant โ for everyone. _This is the principle that matters:_ the
|
|
36
36
|
13,021 style violations the fleet is currently remediating exist because values could be
|
|
37
37
|
written inline. Make them unwritable and there is nothing to inspect.
|
|
38
|
+
|
|
39
|
+
๐ด **But "add a variant" is the wrong move when the axis is wrong** (#487). `Button` carried
|
|
40
|
+
one closed enum that mixed *shape* with *colour* โ `primary | secondary | danger | ghost` โ
|
|
41
|
+
so "the ghost shape in the danger colour" was not sayable. Five ships each invented a
|
|
42
|
+
private name for that one cell and no two agreed (`ghost-danger`, `danger-ghost`,
|
|
43
|
+
`link-danger`, `danger-outline`, and nene-deal reached it through slots). Enumerating four
|
|
44
|
+
more values would have left `4 shapes ร 4 tones = 16` names to chase. 0.20.0 splits the
|
|
45
|
+
axis instead: `variant` is the shape, `tone` is the colour. **Before adding a value, check
|
|
46
|
+
whether what is missing is a value or an axis** โ a value that ships keep spelling with a
|
|
47
|
+
hyphen in the middle is usually two axes wearing one name.
|
|
38
48
|
4. **No strings.** The kit ships no user-visible text. `Spinner` takes `label`, `ErrorState` takes
|
|
39
49
|
`retryLabel`. Localisation stays with the product (`@hideyukimori/nene2-i18n`), so a wording
|
|
40
50
|
change never becomes a kit release.
|
package/dist/data/Pagination.js
CHANGED
|
@@ -28,9 +28,9 @@ export function Pagination(props) {
|
|
|
28
28
|
const atEnd = props.page === undefined ? !props.canNext : props.page >= props.pageCount;
|
|
29
29
|
const goPrev = () => props.page === undefined ? props.onPrev() : props.onPageChange(props.page - 1);
|
|
30
30
|
const goNext = () => props.page === undefined ? props.onNext() : props.onPageChange(props.page + 1);
|
|
31
|
-
const prev = (_jsx(Button, { variant: "
|
|
31
|
+
const prev = (_jsx(Button, { variant: "outline", tone: "neutral", size: size, disabled: atStart, onClick: goPrev, "aria-label": previousLabel, children: previousLabel }, "prev"));
|
|
32
32
|
const current = (_jsx("span", { "aria-current": "page", className: "font-sans text-x-slot-pagination-fg", children: status }, "status"));
|
|
33
|
-
const next = (_jsx(Button, { variant: "
|
|
33
|
+
const next = (_jsx(Button, { variant: "outline", tone: "neutral", size: size, disabled: atEnd, onClick: goNext, "aria-label": nextLabel, children: nextLabel }, "next"));
|
|
34
34
|
const order = statusPlacement === 'start'
|
|
35
35
|
? [current, prev, next]
|
|
36
36
|
: statusPlacement === 'end'
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Pagination.js","sourceRoot":"","sources":["../../src/data/Pagination.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AACjD,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAiElC;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,UAAU,CAAC,KAAsB;IAC/C,MAAM,EACJ,KAAK,EACL,aAAa,EACb,SAAS,EACT,MAAM,EACN,SAAS,EACT,IAAI,GAAG,IAAI,EACX,aAAa,EACb,eAAe,GAAG,QAAQ,GAC3B,GAAG,KAAK,CAAC;IAEV,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,CAAC;IAC5E,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,SAAS,CAAC;IAExF,MAAM,MAAM,GAAG,GAAG,EAAE,CAClB,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,YAAY,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC;IACjF,MAAM,MAAM,GAAG,GAAG,EAAE,CAClB,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,YAAY,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC;IAEjF,MAAM,IAAI,GAAG,CACX,KAAC,MAAM,IAEL,OAAO,EAAC,
|
|
1
|
+
{"version":3,"file":"Pagination.js","sourceRoot":"","sources":["../../src/data/Pagination.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AACjD,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAiElC;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,UAAU,CAAC,KAAsB;IAC/C,MAAM,EACJ,KAAK,EACL,aAAa,EACb,SAAS,EACT,MAAM,EACN,SAAS,EACT,IAAI,GAAG,IAAI,EACX,aAAa,EACb,eAAe,GAAG,QAAQ,GAC3B,GAAG,KAAK,CAAC;IAEV,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,CAAC;IAC5E,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,SAAS,CAAC;IAExF,MAAM,MAAM,GAAG,GAAG,EAAE,CAClB,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,YAAY,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC;IACjF,MAAM,MAAM,GAAG,GAAG,EAAE,CAClB,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,YAAY,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC;IAEjF,MAAM,IAAI,GAAG,CACX,KAAC,MAAM,IAEL,OAAO,EAAC,SAAS,EACjB,IAAI,EAAC,SAAS,EACd,IAAI,EAAE,IAAI,EACV,QAAQ,EAAE,OAAO,EACjB,OAAO,EAAE,MAAM,gBACH,aAAa,YAExB,aAAa,IARV,MAAM,CASH,CACV,CAAC;IACF,MAAM,OAAO,GAAG,CACd,+BAAgC,MAAM,EAAC,SAAS,EAAC,qCAAqC,YACnF,MAAM,IADC,QAAQ,CAEX,CACR,CAAC;IACF,MAAM,IAAI,GAAG,CACX,KAAC,MAAM,IAEL,OAAO,EAAC,SAAS,EACjB,IAAI,EAAC,SAAS,EACd,IAAI,EAAE,IAAI,EACV,QAAQ,EAAE,KAAK,EACf,OAAO,EAAE,MAAM,gBACH,SAAS,YAEpB,SAAS,IARN,MAAM,CASH,CACV,CAAC;IACF,MAAM,KAAK,GACT,eAAe,KAAK,OAAO;QACzB,CAAC,CAAC,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC;QACvB,CAAC,CAAC,eAAe,KAAK,KAAK;YACzB,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC;YACvB,CAAC,CAAC,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;IAE9B,OAAO,CACL,4BAAiB,KAAK,EAAE,SAAS,EAAE,SAAS,YAC1C,KAAC,KAAK,IACJ,SAAS,EAAC,YAAY,EACtB,GAAG,EAAC,KAAK,EACT,KAAK,EAAC,QAAQ;YACd,6EAA6E;YAC7E,SAAS,EAAE,EAAE,CAAC,aAAa,KAAK,IAAI,IAAI,sCAAsC,CAAC,YAE9E,KAAK,GACA,GACJ,CACP,CAAC;AACJ,CAAC"}
|
package/dist/feedback/Badge.d.ts
CHANGED
|
@@ -10,6 +10,22 @@ export interface BadgeProps {
|
|
|
10
10
|
* badge as it does in an alert (0.17.0, #422).
|
|
11
11
|
*/
|
|
12
12
|
tone?: 'neutral' | 'accent' | 'danger' | 'success' | 'warn' | 'info';
|
|
13
|
+
/**
|
|
14
|
+
* Draw a small filled circle before the label.
|
|
15
|
+
*
|
|
16
|
+
* ๐ด It takes its colour from `currentColor`, so there is no dot colour slot and there
|
|
17
|
+
* must not be one: the dot is the tone, shown small. A slot would let a product set a
|
|
18
|
+
* badge whose dot disagrees with its own text, and it would have to be redefined for
|
|
19
|
+
* every tone โ six values to keep in step with six that already exist (the
|
|
20
|
+
* redefine-the-default shape nene-vault retired in #481).
|
|
21
|
+
*
|
|
22
|
+
* Whether a badge has one is a per-call-site decision, not a theme value: nene-clear
|
|
23
|
+
* renders dotted and undotted badges **on the same screen** (`DunningPage` marks overdue
|
|
24
|
+
* with a dot and paused without one), so it cannot be a slot. Hence a prop.
|
|
25
|
+
*
|
|
26
|
+
* Omit it and the render is byte-for-byte what it was before this prop existed.
|
|
27
|
+
*/
|
|
28
|
+
dot?: boolean;
|
|
13
29
|
/** Composed after the kit's own classes (design principle 2). */
|
|
14
30
|
className?: string;
|
|
15
31
|
children: ReactNode;
|
|
@@ -36,4 +52,4 @@ export interface BadgeProps {
|
|
|
36
52
|
*
|
|
37
53
|
* A badge that already fits is unchanged (35.88 ร 26.5 before and after, measured).
|
|
38
54
|
*/
|
|
39
|
-
export declare function Badge({ tone, className, children }: BadgeProps): import("react").JSX.Element;
|
|
55
|
+
export declare function Badge({ tone, dot, className, children }: BadgeProps): import("react").JSX.Element;
|
package/dist/feedback/Badge.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { cx } from '../lib/cx.js';
|
|
3
3
|
const TONE_CLASS = {
|
|
4
4
|
neutral: 'bg-x-slot-badge-neutral-bg text-x-slot-badge-neutral-fg border-x-slot-badge-neutral-border',
|
|
@@ -30,7 +30,7 @@ const TONE_CLASS = {
|
|
|
30
30
|
*
|
|
31
31
|
* A badge that already fits is unchanged (35.88 ร 26.5 before and after, measured).
|
|
32
32
|
*/
|
|
33
|
-
export function Badge({ tone = 'neutral', className, children }) {
|
|
34
|
-
return (
|
|
33
|
+
export function Badge({ tone = 'neutral', dot = false, className, children }) {
|
|
34
|
+
return (_jsxs("span", { className: cx('inline-flex items-center whitespace-nowrap gap-x-slot-badge-gap rounded-x-slot-badge border px-x-slot-badge-pad-x py-x-slot-badge-pad-y font-sans text-x-slot-badge font-x-slot-badge', TONE_CLASS[tone], className), children: [dot && (_jsx("span", { "aria-hidden": "true", className: "size-x-slot-badge-dot shrink-0 rounded-full bg-current" })), children] }));
|
|
35
35
|
}
|
|
36
36
|
//# sourceMappingURL=Badge.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Badge.js","sourceRoot":"","sources":["../../src/feedback/Badge.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"Badge.js","sourceRoot":"","sources":["../../src/feedback/Badge.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAkClC,MAAM,UAAU,GAAoD;IAClE,OAAO,EACL,4FAA4F;IAC9F,MAAM,EAAE,yFAAyF;IACjG,MAAM,EAAE,yFAAyF;IACjG,OAAO,EACL,4FAA4F;IAC9F,IAAI,EAAE,mFAAmF;IACzF,IAAI,EAAE,mFAAmF;CAC1F,CAAC;AAEF;;;;;;GAMG;AACH;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,KAAK,CAAC,EAAE,IAAI,GAAG,SAAS,EAAE,GAAG,GAAG,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAc;IACtF,OAAO,CACL,gBACE,SAAS,EAAE,EAAE,CACX,uLAAuL,EACvL,UAAU,CAAC,IAAI,CAAC,EAChB,SAAS,CACV,aAQA,GAAG,IAAI,CACN,8BACc,MAAM,EAClB,SAAS,EAAC,wDAAwD,GAClE,CACH,EACA,QAAQ,IACJ,CACR,CAAC;AACJ,CAAC"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ReactNode } from 'react';
|
|
2
2
|
export interface InlineAlertProps {
|
|
3
|
-
/** What the message means. `danger` is announced assertively;
|
|
4
|
-
tone?: 'info' | 'warn' | 'danger';
|
|
3
|
+
/** What the message means. `danger` is announced assertively; the rest politely. */
|
|
4
|
+
tone?: 'info' | 'warn' | 'danger' | 'success';
|
|
5
5
|
/**
|
|
6
6
|
* ๐ด Needed to point an `aria-describedby` at this message. Without it a product that
|
|
7
7
|
* wants the alert read out with a control has nowhere to put an id, and nene-vault
|
|
@@ -22,8 +22,14 @@ export interface InlineAlertProps {
|
|
|
22
22
|
* someone listening and no one looking. The palette now carries `warn` of its own.
|
|
23
23
|
*
|
|
24
24
|
* ๐ด The tone decides the ARIA role, not just the colour. `danger` becomes `role="alert"`,
|
|
25
|
-
* which interrupts a screen reader;
|
|
26
|
-
* Six ships wrote this component (three as `InlineAlert`, three as `Alert`) and
|
|
27
|
-
* of role is precisely the part that is easy to get wrong and invisible when you
|
|
25
|
+
* which interrupts a screen reader; every other tone becomes `role="status"`, which waits
|
|
26
|
+
* its turn. Six ships wrote this component (three as `InlineAlert`, three as `Alert`) and
|
|
27
|
+
* the choice of role is precisely the part that is easy to get wrong and invisible when you
|
|
28
|
+
* do.
|
|
29
|
+
*
|
|
30
|
+
* ๐ด `success` (#486) is deliberately **polite**, not assertive. Good news does not earn an
|
|
31
|
+
* interruption, and `ToastProvider` already settled the same question the same way
|
|
32
|
+
* (`POLITE_TONES = ['info', 'success']`). Announcing a success assertively would cut off
|
|
33
|
+
* whatever the person was reading to tell them nothing went wrong.
|
|
28
34
|
*/
|
|
29
35
|
export declare function InlineAlert({ tone, id, className, children }: InlineAlertProps): import("react").JSX.Element;
|
|
@@ -4,6 +4,7 @@ const TONE_CLASS = {
|
|
|
4
4
|
info: 'bg-x-slot-alert-info-bg text-x-slot-alert-info-fg border-x-slot-alert-info-border',
|
|
5
5
|
warn: 'bg-x-slot-alert-warn-bg text-x-slot-alert-warn-fg border-x-slot-alert-warn-border',
|
|
6
6
|
danger: 'bg-x-slot-alert-danger-bg text-x-slot-alert-danger-fg border-x-slot-alert-danger-border',
|
|
7
|
+
success: 'bg-x-slot-alert-success-bg text-x-slot-alert-success-fg border-x-slot-alert-success-border',
|
|
7
8
|
};
|
|
8
9
|
/**
|
|
9
10
|
* A message attached to the thing it is about, rather than to the page.
|
|
@@ -14,9 +15,15 @@ const TONE_CLASS = {
|
|
|
14
15
|
* someone listening and no one looking. The palette now carries `warn` of its own.
|
|
15
16
|
*
|
|
16
17
|
* ๐ด The tone decides the ARIA role, not just the colour. `danger` becomes `role="alert"`,
|
|
17
|
-
* which interrupts a screen reader;
|
|
18
|
-
* Six ships wrote this component (three as `InlineAlert`, three as `Alert`) and
|
|
19
|
-
* of role is precisely the part that is easy to get wrong and invisible when you
|
|
18
|
+
* which interrupts a screen reader; every other tone becomes `role="status"`, which waits
|
|
19
|
+
* its turn. Six ships wrote this component (three as `InlineAlert`, three as `Alert`) and
|
|
20
|
+
* the choice of role is precisely the part that is easy to get wrong and invisible when you
|
|
21
|
+
* do.
|
|
22
|
+
*
|
|
23
|
+
* ๐ด `success` (#486) is deliberately **polite**, not assertive. Good news does not earn an
|
|
24
|
+
* interruption, and `ToastProvider` already settled the same question the same way
|
|
25
|
+
* (`POLITE_TONES = ['info', 'success']`). Announcing a success assertively would cut off
|
|
26
|
+
* whatever the person was reading to tell them nothing went wrong.
|
|
20
27
|
*/
|
|
21
28
|
export function InlineAlert({ tone = 'info', id, className, children }) {
|
|
22
29
|
return (_jsx("div", { id: id, role: tone === 'danger' ? 'alert' : 'status', className: cx('rounded-x-slot-alert border p-x-slot-alert-pad font-sans', TONE_CLASS[tone], className), children: children }));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InlineAlert.js","sourceRoot":"","sources":["../../src/feedback/InlineAlert.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAiBlC,MAAM,UAAU,GAA0D;IACxE,IAAI,EAAE,mFAAmF;IACzF,IAAI,EAAE,mFAAmF;IACzF,MAAM,EAAE,yFAAyF;
|
|
1
|
+
{"version":3,"file":"InlineAlert.js","sourceRoot":"","sources":["../../src/feedback/InlineAlert.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAiBlC,MAAM,UAAU,GAA0D;IACxE,IAAI,EAAE,mFAAmF;IACzF,IAAI,EAAE,mFAAmF;IACzF,MAAM,EAAE,yFAAyF;IACjG,OAAO,EACL,4FAA4F;CAC/F,CAAC;AAEF;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,WAAW,CAAC,EAAE,IAAI,GAAG,MAAM,EAAE,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAoB;IACtF,OAAO,CACL,cACE,EAAE,EAAE,EAAE,EACN,IAAI,EAAE,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,EAC5C,SAAS,EAAE,EAAE,CACX,0DAA0D,EAC1D,UAAU,CAAC,IAAI,CAAC,EAChB,SAAS,CACV,YAEA,QAAQ,GACL,CACP,CAAC;AACJ,CAAC"}
|
|
@@ -4,6 +4,24 @@ export interface PageHeaderProps {
|
|
|
4
4
|
className?: string;
|
|
5
5
|
/** Localized page title. */
|
|
6
6
|
title: string;
|
|
7
|
+
/**
|
|
8
|
+
* Localized one-line description of the page, under the title.
|
|
9
|
+
*
|
|
10
|
+
* ๐ด Not decoration. nene-clear carries one on **every one of its ten pages** โ the prop
|
|
11
|
+
* is `sub` there and the value is always a catalog key (`t('dunning.subtitle')`,
|
|
12
|
+
* `t('audit.subtitle')`, โฆ), so folding it into `title` is not available to it: the two
|
|
13
|
+
* halves are separate keys, and joining them would put the separator โ a string โ in the
|
|
14
|
+
* ship, against principle 4. `PageHeader` takes no `children` either, so without this prop
|
|
15
|
+
* the line has nowhere to go and ten pages lose their description (#492).
|
|
16
|
+
*
|
|
17
|
+
* Omit it and the render is byte-for-byte what it was before this prop existed.
|
|
18
|
+
*
|
|
19
|
+
* โ ๏ธ Its size is not a slot, on purpose. The title has no size slot either โ an `<h1>`
|
|
20
|
+
* reset by Preflight inherits the body size โ so adding one here alone would let a product
|
|
21
|
+
* scale the description while its title stayed put. Products that need a type scale of
|
|
22
|
+
* their own are blocked on the same missing thing, and it is one gap, not two.
|
|
23
|
+
*/
|
|
24
|
+
description?: string;
|
|
7
25
|
actions?: ReactNode;
|
|
8
26
|
}
|
|
9
|
-
export declare function PageHeader({ title, actions, className }: PageHeaderProps): import("react").JSX.Element;
|
|
27
|
+
export declare function PageHeader({ title, description, actions, className }: PageHeaderProps): import("react").JSX.Element;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { cx } from '../lib/cx.js';
|
|
3
|
-
export function PageHeader({ title, actions, className }) {
|
|
4
|
-
|
|
3
|
+
export function PageHeader({ title, description, actions, className }) {
|
|
4
|
+
const heading = (_jsx("h1", { className: "font-sans font-x-slot-page-header text-x-slot-page-header-fg", children: title }));
|
|
5
|
+
return (_jsxs("header", { className: cx('flex items-center justify-between py-x-slot-page-header-pad-y', className), children: [description === undefined ? (heading) : (_jsxs("div", { children: [heading, _jsx("p", { className: "mt-x-slot-page-header-gap font-sans text-x-slot-page-header-description-fg", children: description })] })), actions] }));
|
|
5
6
|
}
|
|
6
7
|
//# sourceMappingURL=PageHeader.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PageHeader.js","sourceRoot":"","sources":["../../src/layout/PageHeader.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"PageHeader.js","sourceRoot":"","sources":["../../src/layout/PageHeader.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AA4BlC,MAAM,UAAU,UAAU,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,SAAS,EAAmB;IACpF,MAAM,OAAO,GAAG,CACd,aAAI,SAAS,EAAC,8DAA8D,YAAE,KAAK,GAAM,CAC1F,CAAC;IAEF,OAAO,CACL,kBACE,SAAS,EAAE,EAAE,CAAC,+DAA+D,EAAE,SAAS,CAAC,aAMxF,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,CAC3B,OAAO,CACR,CAAC,CAAC,CAAC,CACF,0BACG,OAAO,EACR,YAAG,SAAS,EAAC,4EAA4E,YACtF,WAAW,GACV,IACA,CACP,EACA,OAAO,IACD,CACV,CAAC;AACJ,CAAC"}
|
|
@@ -12,6 +12,6 @@ import { Modal } from './Modal.js';
|
|
|
12
12
|
* kind of detail that differs between five independent implementations.
|
|
13
13
|
*/
|
|
14
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: "
|
|
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: "outline", tone: "neutral", onClick: onCancel, children: cancelLabel }), _jsx(Button, { tone: tone === 'danger' ? 'danger' : 'accent', onClick: onConfirm, children: confirmLabel })] })] }) }));
|
|
16
16
|
}
|
|
17
17
|
//# sourceMappingURL=ConfirmDialog.js.map
|
|
@@ -1 +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,
|
|
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,SAAS,EAAC,IAAI,EAAC,SAAS,EAAC,OAAO,EAAE,QAAQ,YACvD,WAAW,GACL,EAIT,KAAC,MAAM,IAAC,IAAI,EAAE,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,EAAE,OAAO,EAAE,SAAS,YACtE,YAAY,GACN,IACH,IACF,GACF,CACT,CAAC;AACJ,CAAC"}
|
package/dist/overlay/Modal.d.ts
CHANGED
|
@@ -28,6 +28,20 @@ interface ModalBase {
|
|
|
28
28
|
* `showModal`, so it can only be verified in a real browser (see #392, live lane).
|
|
29
29
|
*/
|
|
30
30
|
scrollable?: boolean;
|
|
31
|
+
/**
|
|
32
|
+
* The dialog's actions, laid out below the body and **outside its scroll area**.
|
|
33
|
+
*
|
|
34
|
+
* ๐ด Not a matter of layout โ a matter of structure. Pushed into `children`, the action row
|
|
35
|
+
* joins the body's scroll region, so with `scrollable` it slides off the bottom of a tall
|
|
36
|
+
* dialog and the person cannot reach "Confirm". nene-clear uses a footer in **11 of 11**
|
|
37
|
+
* dialogs and makes it a required prop (#493); eight ships wrote a modal and every one of
|
|
38
|
+
* them drew this row.
|
|
39
|
+
*
|
|
40
|
+
* The kit lays the row out end-aligned with a gap, which is what those eleven do. A product
|
|
41
|
+
* that wants another arrangement composes it inside โ `footer={<div className="flex w-full
|
|
42
|
+
* justify-between">โฆ</div>}` โ rather than the kit growing an alignment prop.
|
|
43
|
+
*/
|
|
44
|
+
footer?: ReactNode;
|
|
31
45
|
children: ReactNode;
|
|
32
46
|
}
|
|
33
47
|
interface PlainModal extends ModalBase {
|
|
@@ -37,6 +51,19 @@ interface PlainModal extends ModalBase {
|
|
|
37
51
|
interface HeaderModal extends ModalBase {
|
|
38
52
|
/** Draw a header: the title, and a control that closes the dialog. */
|
|
39
53
|
header: true;
|
|
54
|
+
/**
|
|
55
|
+
* Localized one-line description, under the title.
|
|
56
|
+
*
|
|
57
|
+
* ๐ด On `HeaderModal` only, and deliberately. Without a header the title is never drawn โ
|
|
58
|
+
* it becomes the dialog's `aria-label` โ so a description would have nothing to sit under
|
|
59
|
+
* and would be dropped in silence. The same reasoning `closeLabel` uses below: let the
|
|
60
|
+
* compiler ask for it exactly where it is going to be rendered.
|
|
61
|
+
*
|
|
62
|
+
* ๐ด Named `description`, matching `PageHeader` (#492/#497) and `EmptyState` (#456), not
|
|
63
|
+
* clear's local `sub`. Nine of clear's eleven dialogs carry this line (#493). One word for
|
|
64
|
+
* one thing across the kit โ the rule `Badge`'s tone vocabulary states, applied to a prop.
|
|
65
|
+
*/
|
|
66
|
+
description?: string;
|
|
40
67
|
/**
|
|
41
68
|
* Localized name for the close control.
|
|
42
69
|
*
|
package/dist/overlay/Modal.js
CHANGED
|
@@ -33,7 +33,7 @@ const SHEET_CLASS = 'max-sm:mt-auto max-sm:mb-0 max-sm:w-full max-sm:max-w-none
|
|
|
33
33
|
* up until a consumer overrode one side of a pair.
|
|
34
34
|
*/
|
|
35
35
|
export function Modal(props) {
|
|
36
|
-
const { open, onClose, title, size, sheetOnMobile, scrollable, children } = props;
|
|
36
|
+
const { open, onClose, title, size, sheetOnMobile, scrollable, footer, children } = props;
|
|
37
37
|
const ref = useRef(null);
|
|
38
38
|
const titleId = useId();
|
|
39
39
|
useEffect(() => {
|
|
@@ -72,6 +72,13 @@ export function Modal(props) {
|
|
|
72
72
|
// The sheet classes below (`max-sm:mt-auto max-sm:mb-0`) always assumed this margin was
|
|
73
73
|
// there; saying it explicitly is the kit owning an assumption it had been borrowing.
|
|
74
74
|
// jsdom does not implement `showModal`, so the position itself is a live-lane check.
|
|
75
|
-
'm-auto bg-x-slot-modal-bg text-x-slot-modal-fg border border-x-slot-modal-border rounded-x-slot-modal', 'p-x-slot-modal-pad font-sans backdrop:bg-x-slot-modal-scrim/50', size !== undefined && SIZE_CLASS[size], sheetOnMobile === true && SHEET_CLASS,
|
|
75
|
+
'm-auto bg-x-slot-modal-bg text-x-slot-modal-fg border border-x-slot-modal-border rounded-x-slot-modal', 'p-x-slot-modal-pad font-sans backdrop:bg-x-slot-modal-scrim/50', size !== undefined && SIZE_CLASS[size], sheetOnMobile === true && SHEET_CLASS,
|
|
76
|
+
// The column is what keeps the footer out of the scroll region: the body flexes and
|
|
77
|
+
// scrolls, the footer keeps its height. Without `scrollable` there is nothing to
|
|
78
|
+
// scroll, so the dialog keeps the block layout every caller has had until now.
|
|
79
|
+
scrollable === true && 'flex flex-col'), children: [props.header === true && (_jsxs("header", { className: "mb-x-slot-modal-header-gap flex items-start justify-between gap-x-slot-modal-header-gap", children: [props.description === undefined ? (_jsx("h2", { id: titleId, className: "font-x-slot-modal-title text-x-slot-modal-title-size", children: title })) : (_jsxs("div", { children: [_jsx("h2", { id: titleId, className: "font-x-slot-modal-title text-x-slot-modal-title-size", children: title }), _jsx("p", { className: "mt-x-slot-modal-description-gap font-sans text-x-slot-modal-description-fg", children: props.description })] })), _jsx("button", { type: "button", "aria-label": props.closeLabel, onClick: onClose, className: "rounded-x-slot-control text-x-slot-modal-close-fg leading-none hover:brightness-x-slot-hover focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-x-slot-focus-ring", children: _jsx("span", { "aria-hidden": "true", children: "\u00D7" }) })] })), scrollable === true ? _jsx("div", { className: "min-h-0 overflow-y-auto", children: children }) : children, footer !== undefined && (
|
|
80
|
+
// `shrink-0` matters only in the scrollable column, where the body would otherwise
|
|
81
|
+
// take the footer's height with it; it is inert in the block layout.
|
|
82
|
+
_jsx("footer", { className: "mt-x-slot-modal-footer-gap flex shrink-0 justify-end gap-x-slot-modal-footer-gap", children: footer }))] }));
|
|
76
83
|
}
|
|
77
84
|
//# sourceMappingURL=Modal.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Modal.js","sourceRoot":"","sources":["../../src/overlay/Modal.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAkB,MAAM,OAAO,CAAC;AACjE,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"Modal.js","sourceRoot":"","sources":["../../src/overlay/Modal.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,37 @@
|
|
|
1
1
|
import type { ButtonHTMLAttributes, ReactNode } from 'react';
|
|
2
2
|
export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
3
|
-
|
|
3
|
+
/**
|
|
4
|
+
* The shape: which properties get painted. Not which colour they get painted in.
|
|
5
|
+
*
|
|
6
|
+
* ๐ด This used to be one closed enum that mixed shape and colour
|
|
7
|
+
* (`primary | secondary | danger | ghost`), so "the ghost shape in the danger colour" was
|
|
8
|
+
* not expressible. Five ships each invented their own name for that one missing cell, and
|
|
9
|
+
* no two agreed: nene-clear `ghost-danger`, nene-field `danger-ghost` (the same thing,
|
|
10
|
+
* written backwards), nene-profile `link-danger`, nene-origin `danger-outline`, and
|
|
11
|
+
* nene-deal reached the same place through slots instead โ it set
|
|
12
|
+
* `--color-x-slot-button-danger-bg: transparent` and turned the filled danger into an
|
|
13
|
+
* outlined one (#455). One need, five workarounds, because the API could not say it.
|
|
14
|
+
*
|
|
15
|
+
* ๐ด `bare`, not `ghost`. The old name meant "no fill, no border" here, but nene-clear's
|
|
16
|
+
* `.btn-ghost` has both a background and a border โ it is this kit's `outline`. The word is
|
|
17
|
+
* split across the industry too (Bootstrap's ghost is an outline, Material's is a text
|
|
18
|
+
* button), so a ship reading `ghost` cannot know which one it got. Renaming costs nothing:
|
|
19
|
+
* neither consuming ship uses it (nene-vault 0, nene-deal 0, measured 2026-08-27).
|
|
20
|
+
*/
|
|
21
|
+
variant?: 'solid' | 'outline' | 'bare' | 'link';
|
|
22
|
+
/**
|
|
23
|
+
* The colour: what the shape means. Not how loud it is.
|
|
24
|
+
*
|
|
25
|
+
* ๐ด The same six words `Badge` has carried since 0.17.0, in the same order, painted from
|
|
26
|
+
* the same shape of slot. A tone means one thing across the kit or it means nothing.
|
|
27
|
+
*
|
|
28
|
+
* ๐ด The default is `accent`, not `neutral`. What 0.19.x called `primary` was never a tone
|
|
29
|
+
* โ it was "the accent-coloured filled button", so `<Button>` keeps rendering exactly that.
|
|
30
|
+
* `neutral` is the quiet grey step, which is what `Badge` has always meant by the word.
|
|
31
|
+
* Reading `neutral` as "the ordinary action" is how this kit ended up with two vocabularies
|
|
32
|
+
* in the first place.
|
|
33
|
+
*/
|
|
34
|
+
tone?: 'neutral' | 'accent' | 'danger' | 'success' | 'warn' | 'info';
|
|
4
35
|
/**
|
|
5
36
|
* Two sizes, not a length. `sm` for dense rows and toolbars.
|
|
6
37
|
*
|
|
@@ -10,4 +41,4 @@ export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
|
10
41
|
size?: 'md' | 'sm';
|
|
11
42
|
children: ReactNode;
|
|
12
43
|
}
|
|
13
|
-
export declare function Button({ variant, size, children, type, className, ...rest }: ButtonProps): import("react").JSX.Element;
|
|
44
|
+
export declare function Button({ variant, tone, size, children, type, className, ...rest }: ButtonProps): import("react").JSX.Element;
|
|
@@ -1,18 +1,82 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { cx } from '../lib/cx.js';
|
|
3
3
|
import { CLICKABLE_CLASS, TOUCH_CLASS } from '../lib/states.js';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
4
|
+
/**
|
|
5
|
+
* Shape ร tone, written out.
|
|
6
|
+
*
|
|
7
|
+
* ๐ด Sixteen literal strings and no interpolation, because Tailwind reads the source as text.
|
|
8
|
+
* `` `bg-x-slot-button-${tone}-bg` `` produces the right class at runtime and no CSS for it at
|
|
9
|
+
* build time โ the generator never sees the string, so the rule is never emitted. The kit has
|
|
10
|
+
* to spell every combination it supports.
|
|
11
|
+
*
|
|
12
|
+
* ๐ด `solid` paints `-bg` + `-fg`; every other shape paints `-ink`. They are separate slots
|
|
13
|
+
* because they are separate colours: on a filled danger button the text is the on-accent
|
|
14
|
+
* colour, and on an outlined one it is the danger colour itself. Deriving one from the other
|
|
15
|
+
* would have made the outlined button's label white on white.
|
|
16
|
+
*
|
|
17
|
+
* ๐ด `outline`'s background is a single slot that does not vary with tone. nene-clear's
|
|
18
|
+
* outlined danger sits on the plain surface (`background: var(--surface)`) and only reaches
|
|
19
|
+
* for a tinted one on hover; painting the rest a tone-tinted colour would be louder than what
|
|
20
|
+
* any ship draws today.
|
|
21
|
+
*/
|
|
22
|
+
const SHAPE_TONE_CLASS = {
|
|
23
|
+
solid: {
|
|
24
|
+
neutral: 'bg-x-slot-button-neutral-bg text-x-slot-button-neutral-fg shadow-x-slot-button-solid',
|
|
25
|
+
accent: 'bg-x-slot-button-accent-bg text-x-slot-button-accent-fg shadow-x-slot-button-solid',
|
|
26
|
+
danger: 'bg-x-slot-button-danger-bg text-x-slot-button-danger-fg shadow-x-slot-button-solid',
|
|
27
|
+
success: 'bg-x-slot-button-success-bg text-x-slot-button-success-fg shadow-x-slot-button-solid',
|
|
28
|
+
warn: 'bg-x-slot-button-warn-bg text-x-slot-button-warn-fg shadow-x-slot-button-solid',
|
|
29
|
+
info: 'bg-x-slot-button-info-bg text-x-slot-button-info-fg shadow-x-slot-button-solid',
|
|
30
|
+
},
|
|
31
|
+
outline: {
|
|
32
|
+
neutral: 'bg-x-slot-button-outline-bg text-x-slot-button-neutral-ink border-x-slot-button-neutral-border',
|
|
33
|
+
accent: 'bg-x-slot-button-outline-bg text-x-slot-button-accent-ink border-x-slot-button-accent-border',
|
|
34
|
+
danger: 'bg-x-slot-button-outline-bg text-x-slot-button-danger-ink border-x-slot-button-danger-border',
|
|
35
|
+
success: 'bg-x-slot-button-outline-bg text-x-slot-button-success-ink border-x-slot-button-success-border',
|
|
36
|
+
warn: 'bg-x-slot-button-outline-bg text-x-slot-button-warn-ink border-x-slot-button-warn-border',
|
|
37
|
+
info: 'bg-x-slot-button-outline-bg text-x-slot-button-info-ink border-x-slot-button-info-border',
|
|
38
|
+
},
|
|
39
|
+
bare: {
|
|
40
|
+
neutral: 'bg-transparent text-x-slot-button-neutral-ink',
|
|
41
|
+
accent: 'bg-transparent text-x-slot-button-accent-ink',
|
|
42
|
+
danger: 'bg-transparent text-x-slot-button-danger-ink',
|
|
43
|
+
success: 'bg-transparent text-x-slot-button-success-ink',
|
|
44
|
+
warn: 'bg-transparent text-x-slot-button-warn-ink',
|
|
45
|
+
info: 'bg-transparent text-x-slot-button-info-ink',
|
|
46
|
+
},
|
|
47
|
+
link: {
|
|
48
|
+
neutral: 'bg-transparent text-x-slot-button-neutral-ink underline-offset-4 hover:underline',
|
|
49
|
+
accent: 'bg-transparent text-x-slot-button-accent-ink underline-offset-4 hover:underline',
|
|
50
|
+
danger: 'bg-transparent text-x-slot-button-danger-ink underline-offset-4 hover:underline',
|
|
51
|
+
success: 'bg-transparent text-x-slot-button-success-ink underline-offset-4 hover:underline',
|
|
52
|
+
warn: 'bg-transparent text-x-slot-button-warn-ink underline-offset-4 hover:underline',
|
|
53
|
+
info: 'bg-transparent text-x-slot-button-info-ink underline-offset-4 hover:underline',
|
|
54
|
+
},
|
|
11
55
|
};
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
56
|
+
/**
|
|
57
|
+
* ๐ด Padding and type size are separate because `link` takes one and not the other.
|
|
58
|
+
*
|
|
59
|
+
* A link-shaped button is a run of text inside a sentence or a table cell; padding would push
|
|
60
|
+
* it off the line it belongs to. nene-clear's `.btn-link` sets `padding: 0` and
|
|
61
|
+
* nene-profile's renders through a `linkbtn` class that does the same. The type size still
|
|
62
|
+
* applies โ it is the same two sizes as every other button.
|
|
63
|
+
*/
|
|
64
|
+
const PAD_CLASS = {
|
|
65
|
+
md: 'px-x-slot-button-pad-x py-x-slot-button-pad-y',
|
|
66
|
+
sm: 'px-x-slot-button-sm-pad-x py-x-slot-button-sm-pad-y',
|
|
15
67
|
};
|
|
68
|
+
const TEXT_CLASS = {
|
|
69
|
+
md: 'text-x-slot-button-size',
|
|
70
|
+
sm: 'text-x-slot-button-sm-size',
|
|
71
|
+
};
|
|
72
|
+
/**
|
|
73
|
+
* `link` drops the box the other three shapes share.
|
|
74
|
+
*
|
|
75
|
+
* ๐ด `border-0` rather than leaving the transparent border in place: the border is there so a
|
|
76
|
+
* bordered button matches an unbordered one in height, and a link has no height to match.
|
|
77
|
+
* `rounded-none` for the same reason โ there is no box to round.
|
|
78
|
+
*/
|
|
79
|
+
const LINK_UNBOX = 'border-0 rounded-none';
|
|
16
80
|
// ๐ด `inline-flex`, so the button places what is inside it. A `<button>` is `inline-block`
|
|
17
81
|
// by default, which leaves an icon and its label on a shared baseline rather than centred โ
|
|
18
82
|
// visible as a half-pixel of drift on every icon button, and invisible in a diff. The kit
|
|
@@ -42,8 +106,21 @@ const SIZE_CLASS = {
|
|
|
42
106
|
// instead of its own. A maximum cannot collide with a height: different property, and it
|
|
43
107
|
// leaves anything already smaller alone.
|
|
44
108
|
const SVG_BOUND = '[&_svg]:max-h-x-slot-button-icon [&_svg]:max-w-x-slot-button-icon';
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
109
|
+
// ๐ด `whitespace-nowrap` is load-bearing (#501). A button's label is a command, not body
|
|
110
|
+
// copy: it names one action, and a wrapped command reads as two. nene-clear measured 15
|
|
111
|
+
// buttons wrapping on its SP layout (PC 1440x900: zero) โ "็ฃไฟใ้ไฟก" became four lines at
|
|
112
|
+
// 70px, and "ๆถ่พผใ็ขบๅฎ" broke *inside* a word as "ๆถ่พผใ / ็ขบๅฎ".
|
|
113
|
+
//
|
|
114
|
+
// ๐ด CJK breaks at any character and Latin breaks at word boundaries, so fixing one is not
|
|
115
|
+
// evidence about the other (nene-vault, #477). `nowrap` stops both.
|
|
116
|
+
//
|
|
117
|
+
// This is the same property `Badge` got in #477. It was added there by naming the component
|
|
118
|
+
// rather than by deriving which components need it, so `Button` was simply not on the list โ
|
|
119
|
+
// the third instance of that shape (#486 / #501 / #503). The inventory that would have
|
|
120
|
+
// caught all of them at once is a separate, larger piece of work; this line is the stanch.
|
|
121
|
+
const BASE_CLASS = `whitespace-nowrap rounded-x-slot-button border border-transparent inline-flex items-center justify-center gap-x-slot-button-gap font-sans font-x-slot-button ${SVG_BOUND} ${TOUCH_CLASS} ${CLICKABLE_CLASS}`;
|
|
122
|
+
export function Button({ variant = 'solid', tone = 'accent', size = 'md', children, type = 'button', className, ...rest }) {
|
|
123
|
+
const isLink = variant === 'link';
|
|
124
|
+
return (_jsx("button", { type: type, className: cx(BASE_CLASS, isLink ? LINK_UNBOX : PAD_CLASS[size], TEXT_CLASS[size], SHAPE_TONE_CLASS[variant][tone], className), ...rest, children: children }));
|
|
48
125
|
}
|
|
49
126
|
//# sourceMappingURL=Button.js.map
|
|
@@ -1 +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,eAAe,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"Button.js","sourceRoot":"","sources":["../../src/primitives/Button.tsx"],"names":[],"mappings":"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"}
|
|
@@ -2,6 +2,6 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { Button } from '../primitives/Button.js';
|
|
3
3
|
import { cx } from '../lib/cx.js';
|
|
4
4
|
export function ErrorState({ message, retryLabel, onRetry, className }) {
|
|
5
|
-
return (_jsxs("div", { className: cx('py-x-slot-state-pad-y', className), role: "alert", children: [_jsx("p", { className: "font-sans text-x-slot-error-state-fg", children: message }), _jsx("div", { className: "py-x-slot-state-action-pad-y", children: _jsx(Button, { variant: "
|
|
5
|
+
return (_jsxs("div", { className: cx('py-x-slot-state-pad-y', className), role: "alert", children: [_jsx("p", { className: "font-sans text-x-slot-error-state-fg", children: message }), _jsx("div", { className: "py-x-slot-state-action-pad-y", children: _jsx(Button, { variant: "outline", tone: "neutral", onClick: onRetry, children: retryLabel }) })] }));
|
|
6
6
|
}
|
|
7
7
|
//# sourceMappingURL=ErrorState.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ErrorState.js","sourceRoot":"","sources":["../../src/states/ErrorState.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AACjD,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAYlC,MAAM,UAAU,UAAU,CAAC,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,SAAS,EAAmB;IACrF,OAAO,CACL,eAAK,SAAS,EAAE,EAAE,CAAC,uBAAuB,EAAE,SAAS,CAAC,EAAE,IAAI,EAAC,OAAO,aAClE,YAAG,SAAS,EAAC,sCAAsC,YAAE,OAAO,GAAK,EACjE,cAAK,SAAS,EAAC,8BAA8B,YAC3C,KAAC,MAAM,IAAC,OAAO,EAAC,
|
|
1
|
+
{"version":3,"file":"ErrorState.js","sourceRoot":"","sources":["../../src/states/ErrorState.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AACjD,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAYlC,MAAM,UAAU,UAAU,CAAC,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,SAAS,EAAmB;IACrF,OAAO,CACL,eAAK,SAAS,EAAE,EAAE,CAAC,uBAAuB,EAAE,SAAS,CAAC,EAAE,IAAI,EAAC,OAAO,aAClE,YAAG,SAAS,EAAC,sCAAsC,YAAE,OAAO,GAAK,EACjE,cAAK,SAAS,EAAC,8BAA8B,YAC3C,KAAC,MAAM,IAAC,OAAO,EAAC,SAAS,EAAC,IAAI,EAAC,SAAS,EAAC,OAAO,EAAE,OAAO,YACtD,UAAU,GACJ,GACL,IACF,CACP,CAAC;AACJ,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hideyukimori/nene2-ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.21.0",
|
|
4
4
|
"description": "NeNe fleet shared React UI kit โ token-driven primitives on Tailwind v4 @theme. Components carry no design of their own; themes do.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
package/themes/default.css
CHANGED
|
@@ -42,6 +42,11 @@
|
|
|
42
42
|
--color-warn-soft: oklch(95% 0.035 80);
|
|
43
43
|
--color-on-warn: oklch(21% 0.04 75);
|
|
44
44
|
--color-danger-soft: oklch(95% 0.03 30);
|
|
45
|
+
/* ๐ด ๅฅ็ดใญใผใ ใๅคใ็กใใฃใ2ใค๏ผ#487 ใงๅฟ
่ฆใซใชใฃใใฎใงไธใใ๏ผใ
|
|
46
|
+
* `on-danger` ใฏ 0.19.x ใ danger ใฎๅกใใซไฝฟใฃใฆใใ `on-accent` ใจๅๅค๏ผๆ็ปใฏไธๅคใ
|
|
47
|
+
* `accent-soft` ใฏไปใฎ *-soft๏ผ95% / chroma ~0.03 / ๅ hue๏ผใจๅใไฝใๆนใ */
|
|
48
|
+
--color-on-danger: oklch(99% 0 0);
|
|
49
|
+
--color-accent-soft: oklch(95% 0.03 250);
|
|
45
50
|
|
|
46
51
|
/* ๐ด Six more contract colours, added in 0.17.0 for `Badge` (#422). Five ships carry a
|
|
47
52
|
* success tone and a warning tone in their own badge (clear / field / invoice / origin /
|
|
@@ -170,6 +175,7 @@
|
|
|
170
175
|
* nene-deal โ were already correcting that independently, so the painting this replaces
|
|
171
176
|
* is one no consumer used. */
|
|
172
177
|
--spacing-x-slot-badge-gap: var(--spacing-x-3xs);
|
|
178
|
+
--spacing-x-slot-badge-dot: var(--spacing-x-3xs);
|
|
173
179
|
--spacing-x-slot-switch-pad-x: var(--spacing-x-2xs);
|
|
174
180
|
--spacing-x-slot-switch-pad-y: var(--spacing-x-3xs);
|
|
175
181
|
--spacing-x-slot-alert-pad: var(--spacing-x-2xs);
|
|
@@ -187,6 +193,7 @@
|
|
|
187
193
|
/* Between an EmptyState's two lines (#456). Only read when `description` is passed. */
|
|
188
194
|
--spacing-x-slot-empty-state-gap: var(--spacing-x-3xs);
|
|
189
195
|
--spacing-x-slot-page-header-pad-y: var(--spacing-x-md);
|
|
196
|
+
--spacing-x-slot-page-header-gap: var(--spacing-x-3xs);
|
|
190
197
|
|
|
191
198
|
--radius-x-slot-button: var(--radius-x-md);
|
|
192
199
|
--radius-x-slot-control: var(--radius-x-md);
|
|
@@ -230,6 +237,11 @@
|
|
|
230
237
|
--color-x-slot-alert-danger-bg: var(--color-surface);
|
|
231
238
|
--color-x-slot-alert-danger-fg: var(--color-danger);
|
|
232
239
|
--color-x-slot-alert-danger-border: var(--color-danger);
|
|
240
|
+
/* `success` (#486). Shaped like `danger`: the surface stays the page's, and the meaning is
|
|
241
|
+
* carried by the border and the text โ an alert is read, not filled. */
|
|
242
|
+
--color-x-slot-alert-success-bg: var(--color-surface);
|
|
243
|
+
--color-x-slot-alert-success-fg: var(--color-success);
|
|
244
|
+
--color-x-slot-alert-success-border: var(--color-success);
|
|
233
245
|
--color-x-slot-field-label: var(--color-text-muted);
|
|
234
246
|
--color-x-slot-field-hint: var(--color-text-muted);
|
|
235
247
|
--text-x-slot-field-hint-size: var(--text-x-2xs);
|
|
@@ -283,22 +295,65 @@
|
|
|
283
295
|
* there is now an opening. */
|
|
284
296
|
--color-x-slot-focus-ring: var(--color-text-primary);
|
|
285
297
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
298
|
+
/* Button: shape ร tone (#487).
|
|
299
|
+
*
|
|
300
|
+
* ๐ด The six tones are `Badge`'s six, in `Badge`'s order, read through the same shape of
|
|
301
|
+
* slot. That was the whole argument for splitting the axis โ if the words do not line up,
|
|
302
|
+
* the kit still has two vocabularies and has only moved where they disagree.
|
|
303
|
+
*
|
|
304
|
+
* ๐ด `-fg` reads the contract's own `on-<tone>`, not `on-accent` for everything. The
|
|
305
|
+
* contract has carried `on-warn` since it was frozen (2026-07-14) and it is a dark brown,
|
|
306
|
+
* because `--color-warn` is mid-luminance and white on it measures 3.48:1 โ below AA.
|
|
307
|
+
* With `on-warn` it is 4.97:1. The first draft of this PR painted every tone's label with
|
|
308
|
+
* `on-accent` and shipped that 3.48:1; the contract had already solved it.
|
|
309
|
+
*
|
|
310
|
+
* ๐ด The default tone is `accent`, so `<Button>` is still the accent-coloured filled
|
|
311
|
+
* button 0.19.x called `primary`. `neutral` is the quiet grey step.
|
|
312
|
+
*
|
|
313
|
+
* Four colours per tone, none derivable from the others:
|
|
314
|
+
* -bg the fill, painted by `solid` only
|
|
315
|
+
* -fg what sits on that fill (the contract's `on-<tone>`)
|
|
316
|
+
* -ink the tone itself, painted by `outline` / `bare` / `link`
|
|
317
|
+
* -border the outline's frame โ the *-soft step, not the tone
|
|
318
|
+
*
|
|
319
|
+
* ๐ด `-border` is the soft step. nene-clear draws its outlined danger with a frame far
|
|
320
|
+
* lighter than the label (`--bad-line` #e3bcbc against `--bad` #9c2c2c). Using the tone for
|
|
321
|
+
* both makes every outlined button louder than any ship draws today.
|
|
322
|
+
*
|
|
323
|
+
* ๐ด Renaming a slot fails SILENTLY. A ship that redefined `primary-* / secondary-* /
|
|
324
|
+
* danger-border / ghost-fg` sees no error โ the property stops being read and the kit
|
|
325
|
+
* default paints instead. Both consuming ships redefined some (nene-deal 4, nene-vault 3,
|
|
326
|
+
* measured 2026-08-27), so the migration note carries the mapping. */
|
|
327
|
+
--color-x-slot-button-outline-bg: var(--color-surface-raised);
|
|
328
|
+
--color-x-slot-button-neutral-bg: var(--color-border);
|
|
329
|
+
--color-x-slot-button-neutral-fg: var(--color-text-primary);
|
|
330
|
+
--color-x-slot-button-neutral-ink: var(--color-text-primary);
|
|
331
|
+
--color-x-slot-button-neutral-border: var(--color-border);
|
|
332
|
+
--color-x-slot-button-accent-bg: var(--color-accent);
|
|
333
|
+
--color-x-slot-button-accent-fg: var(--color-on-accent);
|
|
334
|
+
--color-x-slot-button-accent-ink: var(--color-accent);
|
|
335
|
+
--color-x-slot-button-accent-border: var(--color-accent-soft);
|
|
291
336
|
--color-x-slot-button-danger-bg: var(--color-danger);
|
|
292
|
-
--color-x-slot-button-danger-fg: var(--color-on-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
--color-x-slot-button-
|
|
300
|
-
--color-x-slot-button-
|
|
301
|
-
|
|
337
|
+
--color-x-slot-button-danger-fg: var(--color-on-danger);
|
|
338
|
+
--color-x-slot-button-danger-ink: var(--color-danger);
|
|
339
|
+
--color-x-slot-button-danger-border: var(--color-danger-soft);
|
|
340
|
+
--color-x-slot-button-success-bg: var(--color-success);
|
|
341
|
+
--color-x-slot-button-success-fg: var(--color-on-success);
|
|
342
|
+
--color-x-slot-button-success-ink: var(--color-success);
|
|
343
|
+
--color-x-slot-button-success-border: var(--color-success-soft);
|
|
344
|
+
--color-x-slot-button-warn-bg: var(--color-warn);
|
|
345
|
+
--color-x-slot-button-warn-fg: var(--color-on-warn);
|
|
346
|
+
/* ๐ด warn ใฎ ink ใ ใ tone ๆฌไฝ่ฒใงใฏใชใใ`--color-warn` ใฏไธญ้่ผๅบฆใงใ็ฝๅฐใซ็ฝฎใใจ
|
|
347
|
+
* 3.58:1 โโAA ใๅฒใ๏ผไปใฎ tone ใฏๆฌไฝ่ฒใฎใพใพใง 4.7ใ5.5 ้ใ๏ผใๅฅ็ดใฎ `--color-on-warn`
|
|
348
|
+
* ใฏ 16:1 ใงใ**InlineAlert ใๆขใซใ็ฝๅฐใซ่ผใ warn ใฎๅญใใจใใฆไฝฟใฃใฆใใ**
|
|
349
|
+
* ๏ผ`--color-x-slot-alert-warn-fg`๏ผใๅใ็จ้ใซๅใใใผใฏใณใๅ
ใฆใใฎใฏๆใใๆนๅใงใใฃใฆใ
|
|
350
|
+
* ไพๅคใงใฏใชใใโ ๅฅ็ดใฎๅคใฏ1ใคใๅคใใใซๆธใ๏ผBadge ใ InlineAlert ใๅใใชใ๏ผใ */
|
|
351
|
+
--color-x-slot-button-warn-ink: var(--color-on-warn);
|
|
352
|
+
--color-x-slot-button-warn-border: var(--color-warn-soft);
|
|
353
|
+
--color-x-slot-button-info-bg: var(--color-info);
|
|
354
|
+
--color-x-slot-button-info-fg: var(--color-on-info);
|
|
355
|
+
--color-x-slot-button-info-ink: var(--color-info);
|
|
356
|
+
--color-x-slot-button-info-border: var(--color-info-soft);
|
|
302
357
|
/* Shared by Input, Select and Textarea โ they are one control with three shapes, and a
|
|
303
358
|
* product that darkens one and not the others has a bug, not a design. */
|
|
304
359
|
--color-x-slot-control-fg: var(--color-text-primary);
|
|
@@ -360,8 +415,10 @@
|
|
|
360
415
|
--color-x-slot-toast-border: var(--color-border);
|
|
361
416
|
--color-x-slot-toast-danger-fg: var(--color-danger);
|
|
362
417
|
--color-x-slot-toast-danger-border: var(--color-danger);
|
|
363
|
-
/* `success` tone (#457).
|
|
364
|
-
* the
|
|
418
|
+
/* `success` tone (#457). โ ๏ธ This comment claimed InlineAlert already carried the meaning.
|
|
419
|
+
* It did not, and would not until #486 โ the sentence was written from the enumeration in
|
|
420
|
+
* the issue rather than from the component. Corrected here rather than deleted: a note
|
|
421
|
+
* that was wrong about a neighbour is the exact shape #486 is about. */
|
|
365
422
|
--color-x-slot-toast-success-fg: var(--color-success);
|
|
366
423
|
--color-x-slot-toast-success-border: var(--color-success);
|
|
367
424
|
/* The toast's second line (#457). Only read when `description` is passed. */
|
|
@@ -388,6 +445,7 @@
|
|
|
388
445
|
|
|
389
446
|
--color-x-slot-pagination-fg: var(--color-text-muted);
|
|
390
447
|
--color-x-slot-page-header-fg: var(--color-text-primary);
|
|
448
|
+
--color-x-slot-page-header-description-fg: var(--color-text-muted);
|
|
391
449
|
--color-x-slot-text-fg: var(--color-text-primary);
|
|
392
450
|
--color-x-slot-text-muted-fg: var(--color-text-muted);
|
|
393
451
|
--color-x-slot-spinner-fg: var(--color-text-muted);
|
|
@@ -473,12 +531,19 @@
|
|
|
473
531
|
--container-x-slot-modal-lg: var(--container-xl);
|
|
474
532
|
|
|
475
533
|
--spacing-x-slot-modal-header-gap: var(--spacing-x-xs);
|
|
534
|
+
/* The action row (#493). One slot for both the space above it and the space between the
|
|
535
|
+
* buttons: they are the same rhythm, and a product that wants them apart can say so. */
|
|
536
|
+
--spacing-x-slot-modal-footer-gap: var(--spacing-x-xs);
|
|
537
|
+
/* The dialog's second line (#493). Only read when `description` is passed. Same value as
|
|
538
|
+
* PageHeader's and EmptyState's โ one word, one look. */
|
|
539
|
+
--spacing-x-slot-modal-description-gap: var(--spacing-x-3xs);
|
|
476
540
|
--font-weight-x-slot-modal-title: var(--font-weight-medium);
|
|
477
541
|
/* `inherit`, so the header title takes the dialog's own size unless a product says
|
|
478
542
|
* otherwise. There is no previous rendering to copy โ the header is new โ and picking a
|
|
479
543
|
* step here would decide type for every product that turns the header on. */
|
|
480
544
|
--text-x-slot-modal-title-size: inherit;
|
|
481
545
|
--color-x-slot-modal-close-fg: var(--color-text-muted);
|
|
546
|
+
--color-x-slot-modal-description-fg: var(--color-text-muted);
|
|
482
547
|
|
|
483
548
|
/* โโ Shadow slots โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
484
549
|
* ๐ด Shadow was the one dimension that never got slots (#386). 0.9.0 moved "colour, weight
|
|
@@ -492,7 +557,10 @@
|
|
|
492
557
|
* `Card` and `Toast` wrote `shadow-sm`, so theirs point at the scale. A default that is
|
|
493
558
|
* anything other than the current rendering changes how every product already looks โ
|
|
494
559
|
* and "the default is harmless" only holds while the default is that copy. */
|
|
495
|
-
|
|
560
|
+
/* ๐ด Renamed from `--shadow-x-slot-button-primary` (#487): the shadow belongs to the
|
|
561
|
+
* filled shape, not to one colour. nene-vault redefines this one (`var(--shadow-sm)`) and
|
|
562
|
+
* must rename it โ see the migration note. */
|
|
563
|
+
--shadow-x-slot-button-solid: none;
|
|
496
564
|
--shadow-x-slot-card-raised: var(--shadow-sm);
|
|
497
565
|
--shadow-x-slot-toast: var(--shadow-sm);
|
|
498
566
|
|