@hideyukimori/nene2-ui 0.16.1 → 0.17.1

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 CHANGED
@@ -258,11 +258,17 @@ wrap every choice in a `<div>` to say them.
258
258
  label, so the kit carries it). That was right and it left the reason in place. **Fixing what
259
259
  a report names is not the same as fixing what it is about.**
260
260
 
261
+ Until 0.17.0 seven components accepted no `className` at all. Four of them now do — `Badge`,
262
+ `FormField`, `DataTable`, `Pagination` — because a caller could not add a margin or a width
263
+ without wrapping them. **Three still do not, on purpose**: `Modal`, `ConfirmDialog` and
264
+ `ToastProvider` are overlays and a provider; a class landed on a `<dialog>` from outside can
265
+ undo the margin and top-layer assumptions the kit relies on (0.16.1 is the case in point).
266
+
261
267
  ### 🔴 A palette that is missing a meaning
262
268
 
263
- The kit's theme defines **8 of the 28 colours** in the frozen Core Token Contract v1. That
269
+ The kit's theme defines **14 of the 28 colours** in the frozen Core Token Contract v1. That
264
270
  is a legal theme — the contract says what a name means, not that every name must be used —
265
- but it stops being harmless the moment a component needs one of the twenty.
271
+ but it stops being harmless the moment a component needs one of the fourteen.
266
272
 
267
273
  `warn` was one. Six ships define `--color-warn`; nene-payout, the product this theme was
268
274
  promoted from, does not. So `--color-x-slot-alert-warn-*` pointed at `--color-danger` and a
@@ -273,10 +279,11 @@ listening and no one looking**.
273
279
  resolve to one value cannot express the distinction it is named for.** Both are now checked
274
280
  — radius by step count, colour by whether two meanings resolve to the same value.
275
281
 
276
- Still undefined: `surface-overlay`, `surface-sunken`, `text-faint`, `text-inverse`,
277
- `border-strong`, `accent-hover`, `accent-soft`, `on-danger`, `success`, `success-soft`,
278
- `on-success`, `info`, `info-soft`, `on-info`, `focus-ring`, `scrim`. Two of those —
279
- `focus-ring` and `scrim` — already have component slots pointing at substitutes.
282
+ `success` / `success-soft` / `on-success` and `info` / `info-soft` / `on-info` were added in
283
+ 0.17.0 because `Badge` needed them (#422) — defined when a component needs them, not all at
284
+ once. Still undefined: `surface-overlay`, `surface-sunken`, `text-faint`, `text-inverse`,
285
+ `border-strong`, `accent-hover`, `accent-soft`, `on-danger`, `focus-ring`, `scrim`. Two of
286
+ those — `focus-ring` and `scrim` — already have component slots pointing at substitutes.
280
287
 
281
288
  ### 🔴 Two validity states, and only one of them is invalid
282
289
 
@@ -16,17 +16,31 @@ export interface DataTableProps<Row> {
16
16
  rowKey: (row: Row) => string;
17
17
  /** Localized description of what the table contains. Becomes the table's caption. */
18
18
  caption: string;
19
+ /** Composed after the kit's own classes (design principle 2). Lands on the `<table>`. */
20
+ className?: string;
21
+ /**
22
+ * Below `sm`, draw each row as a card: every cell becomes a block headed by its column's
23
+ * name. Off by default — a table that changes shape at a breakpoint is a decision, the
24
+ * same rule as `Modal`'s `sheetOnMobile`.
25
+ *
26
+ * 🔴 Four ships already do this by hand (`<td data-label>` + `content: attr(data-label)`;
27
+ * invoice / profile / records / vault, measured 2026-08-25), which is why it is here and
28
+ * not left to them (#423). The kit does it with utilities, every one carrying the
29
+ * `max-sm:` prefix, so a wide viewport is untouched.
30
+ *
31
+ * ⚠️ The visual header row is hidden (`sr-only`), not removed: the `<th scope="col">` stay
32
+ * in the document, so assistive tech still pairs a cell with its column.
33
+ *
34
+ * 🔴 The `::before` label is drawn with the alternative-text form of `content`
35
+ * (`attr(data-label) / ""`) so that it stays out of the cell's accessible name. Without
36
+ * the `/ ""` the generated text *is* part of the name: every cell is read as "Name x"
37
+ * while the hidden `<th>` still supplies "Name" — the header twice (#439, vault's
38
+ * Playwright on production 0.9.2 at 375px). Measured in Chromium 149 for 0.17.1: plain
39
+ * `attr()` → cell "Name x"; with `/ ""` → cell "x", also through Tailwind's
40
+ * `--tw-content` indirection. Firefox does not implement the alternative-text form
41
+ * (2026-08), so there the label is still read twice — the same as 0.17.0, not a
42
+ * regression. jsdom does not compute pseudo-elements, so the test pins the class literal.
43
+ */
44
+ collapse?: 'sm';
19
45
  }
20
- /**
21
- * A tabular list.
22
- *
23
- * 🔴 Every heading carries `scope="col"`. Without it a screen reader cannot pair a cell with
24
- * its column, so each cell is read as a bare value — and nothing about the rendered table
25
- * looks any different, which is why three ships each shipped a table and the `scope` is the
26
- * detail most likely to differ between them.
27
- *
28
- * 🔴 The caption is required, not optional. A visually obvious table ("it's clearly the
29
- * invoice list") is not obvious to someone arriving at it by keyboard from elsewhere on the
30
- * page. It is visually hidden, not absent.
31
- */
32
- export declare function DataTable<Row>({ columns, rows, rowKey, caption }: DataTableProps<Row>): import("react").JSX.Element;
46
+ export declare function DataTable<Row>({ columns, rows, rowKey, caption, className, collapse, }: DataTableProps<Row>): import("react").JSX.Element;
@@ -1,4 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { cx } from '../lib/cx.js';
2
3
  /**
3
4
  * A tabular list.
4
5
  *
@@ -11,7 +12,17 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
11
12
  * invoice list") is not obvious to someone arriving at it by keyboard from elsewhere on the
12
13
  * page. It is visually hidden, not absent.
13
14
  */
14
- export function DataTable({ columns, rows, rowKey, caption }) {
15
- return (_jsxs("table", { className: "w-full border-collapse font-sans text-x-slot-table-fg", children: [_jsx("caption", { className: "sr-only", children: caption }), _jsx("thead", { children: _jsx("tr", { children: columns.map((col) => (_jsx("th", { scope: "col", className: `border-b border-x-slot-table-border px-x-slot-table-cell-pad-x py-x-slot-table-cell-pad-y font-x-slot-table-header text-x-slot-table-header-fg ${col.align === 'end' ? 'text-right' : 'text-left'}`, children: col.header }, col.key))) }) }), _jsx("tbody", { children: rows.map((row) => (_jsx("tr", { children: columns.map((col) => (_jsx("td", { className: `border-b border-x-slot-table-border px-x-slot-table-cell-pad-x py-x-slot-table-cell-pad-y ${col.align === 'end' ? 'text-right' : 'text-left'}`, children: col.cell(row) }, col.key))) }, rowKey(row)))) })] }));
15
+ // Every class here carries `max-sm:`. Only structure — the label's weight and colour are
16
+ // the header's own slots, read through `before:`.
17
+ const CARD_TABLE = 'max-sm:block';
18
+ const CARD_THEAD = 'max-sm:sr-only';
19
+ const CARD_TBODY = 'max-sm:block';
20
+ const CARD_ROW = 'max-sm:block max-sm:border-b max-sm:border-x-slot-table-border';
21
+ // `content-[attr(data-label)_/_'']` — Tailwind's `_` is a space, so this is
22
+ // `content: attr(data-label) / ''`: the label is drawn but has empty alternative text (#439).
23
+ const CARD_CELL = "max-sm:block max-sm:border-b-0 max-sm:text-left max-sm:before:block max-sm:before:content-[attr(data-label)_/_''] max-sm:before:font-x-slot-table-header max-sm:before:text-x-slot-table-header-fg";
24
+ export function DataTable({ columns, rows, rowKey, caption, className, collapse, }) {
25
+ const cards = collapse === 'sm';
26
+ return (_jsxs("table", { className: cx('w-full border-collapse font-sans text-x-slot-table-fg', cards && CARD_TABLE, className), children: [_jsx("caption", { className: "sr-only", children: caption }), _jsx("thead", { className: cards ? CARD_THEAD : undefined, children: _jsx("tr", { children: columns.map((col) => (_jsx("th", { scope: "col", className: `border-b border-x-slot-table-border px-x-slot-table-cell-pad-x py-x-slot-table-cell-pad-y font-x-slot-table-header text-x-slot-table-header-fg ${col.align === 'end' ? 'text-right' : 'text-left'}`, children: col.header }, col.key))) }) }), _jsx("tbody", { className: cards ? CARD_TBODY : undefined, children: rows.map((row) => (_jsx("tr", { className: cards ? CARD_ROW : undefined, children: columns.map((col) => (_jsx("td", { ...(cards ? { 'data-label': col.header } : {}), className: cx('border-b border-x-slot-table-border px-x-slot-table-cell-pad-x py-x-slot-table-cell-pad-y', col.align === 'end' ? 'text-right' : 'text-left', cards && CARD_CELL), children: col.cell(row) }, col.key))) }, rowKey(row)))) })] }));
16
27
  }
17
28
  //# sourceMappingURL=DataTable.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"DataTable.js","sourceRoot":"","sources":["../../src/data/DataTable.tsx"],"names":[],"mappings":";AAsBA;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,SAAS,CAAM,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAuB;IACpF,OAAO,CACL,iBAAO,SAAS,EAAC,uDAAuD,aACtE,kBAAS,SAAS,EAAC,SAAS,YAAE,OAAO,GAAW,EAChD,0BACE,uBACG,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CACpB,aAEE,KAAK,EAAC,KAAK,EACX,SAAS,EAAE,kJACT,GAAG,CAAC,KAAK,KAAK,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,WACvC,EAAE,YAED,GAAG,CAAC,MAAM,IANN,GAAG,CAAC,GAAG,CAOT,CACN,CAAC,GACC,GACC,EACR,0BACG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CACjB,uBACG,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CACpB,aAEE,SAAS,EAAE,6FACT,GAAG,CAAC,KAAK,KAAK,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,WACvC,EAAE,YAED,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,IALT,GAAG,CAAC,GAAG,CAMT,CACN,CAAC,IAVK,MAAM,CAAC,GAAG,CAAC,CAWf,CACN,CAAC,GACI,IACF,CACT,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"DataTable.js","sourceRoot":"","sources":["../../src/data/DataTable.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAgDlC;;;;;;;;;;;GAWG;AACH,yFAAyF;AACzF,kDAAkD;AAClD,MAAM,UAAU,GAAG,cAAc,CAAC;AAClC,MAAM,UAAU,GAAG,gBAAgB,CAAC;AACpC,MAAM,UAAU,GAAG,cAAc,CAAC;AAClC,MAAM,QAAQ,GAAG,gEAAgE,CAAC;AAClF,4EAA4E;AAC5E,8FAA8F;AAC9F,MAAM,SAAS,GACb,oMAAoM,CAAC;AAEvM,MAAM,UAAU,SAAS,CAAM,EAC7B,OAAO,EACP,IAAI,EACJ,MAAM,EACN,OAAO,EACP,SAAS,EACT,QAAQ,GACY;IACpB,MAAM,KAAK,GAAG,QAAQ,KAAK,IAAI,CAAC;IAChC,OAAO,CACL,iBACE,SAAS,EAAE,EAAE,CACX,uDAAuD,EACvD,KAAK,IAAI,UAAU,EACnB,SAAS,CACV,aAED,kBAAS,SAAS,EAAC,SAAS,YAAE,OAAO,GAAW,EAChD,gBAAO,SAAS,EAAE,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,YAC9C,uBACG,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CACpB,aAEE,KAAK,EAAC,KAAK,EACX,SAAS,EAAE,kJACT,GAAG,CAAC,KAAK,KAAK,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,WACvC,EAAE,YAED,GAAG,CAAC,MAAM,IANN,GAAG,CAAC,GAAG,CAOT,CACN,CAAC,GACC,GACC,EACR,gBAAO,SAAS,EAAE,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,YAC7C,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CACjB,aAAsB,SAAS,EAAE,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,YAC1D,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CACpB,gBAEM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAC/C,SAAS,EAAE,EAAE,CACX,2FAA2F,EAC3F,GAAG,CAAC,KAAK,KAAK,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,WAAW,EAChD,KAAK,IAAI,SAAS,CACnB,YAEA,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,IART,GAAG,CAAC,GAAG,CAST,CACN,CAAC,IAbK,MAAM,CAAC,GAAG,CAAC,CAcf,CACN,CAAC,GACI,IACF,CACT,CAAC;AACJ,CAAC"}
@@ -8,9 +8,21 @@ export interface DetailListProps {
8
8
  /** Composed after the kit's own classes (design principle 2). */
9
9
  className?: string;
10
10
  rows: DetailRow[];
11
+ /**
12
+ * `stack` (default) is one row per line — what the component always drew. `columns` lays
13
+ * the rows out in two columns on a wide viewport and **falls back to one column below
14
+ * `md` on its own**, so a caller never has to say so (nene-vault's own `<dl>` carries
15
+ * `max-md:grid-cols-1`, and so do the other four ships' — measured 2026-08-25, #391).
16
+ *
17
+ * 🔴 A choice between two arrangements, not a column count. Five ships write a two-column
18
+ * detail block and none writes three; a `columns: number` would be a value the kit
19
+ * invented (design principle 3). `rows[].span` was considered and rejected for the same
20
+ * reason: it brings a column count into every row (#424).
21
+ *
22
+ * Only structure lives here. The term's weight and colour are slots
23
+ * (`--font-weight-x-slot-detail-term`, `--color-x-slot-detail-term-fg`) and reach a
24
+ * product through the theme, not through a prop.
25
+ */
26
+ layout?: 'stack' | 'columns';
11
27
  }
12
- /**
13
- * Read-only key/value display for detail screens. Uses a description list so the
14
- * label/value relationship is conveyed to assistive technology.
15
- */
16
- export declare function DetailList({ rows, className }: DetailListProps): import("react").JSX.Element;
28
+ export declare function DetailList({ rows, className, layout }: DetailListProps): import("react").JSX.Element;
@@ -4,7 +4,13 @@ import { cx } from '../lib/cx.js';
4
4
  * Read-only key/value display for detail screens. Uses a description list so the
5
5
  * label/value relationship is conveyed to assistive technology.
6
6
  */
7
- export function DetailList({ rows, className }) {
8
- return (_jsx("dl", { className: cx('flex flex-col gap-x-slot-detail-gap', className), children: rows.map((row) => (_jsxs("div", { className: "flex flex-col gap-x-slot-detail-row-gap border-b border-x-slot-detail-border py-x-slot-detail-row-pad-y", children: [_jsx("dt", { className: "font-sans font-x-slot-detail-term text-x-slot-detail-term-fg", children: row.label }), _jsx("dd", { className: "font-sans text-x-slot-detail-description-fg", children: row.value })] }, row.label))) }));
7
+ const LAYOUT_CLASS = {
8
+ stack: 'flex flex-col',
9
+ // One gap slot for both axes — the fleet's two-column blocks use one value, and a second
10
+ // slot would be a step nobody asked for.
11
+ columns: 'grid grid-cols-2 max-md:grid-cols-1',
12
+ };
13
+ export function DetailList({ rows, className, layout = 'stack' }) {
14
+ return (_jsx("dl", { className: cx(LAYOUT_CLASS[layout], 'gap-x-slot-detail-gap', className), children: rows.map((row) => (_jsxs("div", { className: "flex flex-col gap-x-slot-detail-row-gap border-b border-x-slot-detail-border py-x-slot-detail-row-pad-y", children: [_jsx("dt", { className: "font-sans font-x-slot-detail-term text-x-slot-detail-term-fg", children: row.label }), _jsx("dd", { className: "font-sans text-x-slot-detail-description-fg", children: row.value })] }, row.label))) }));
9
15
  }
10
16
  //# sourceMappingURL=DetailList.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"DetailList.js","sourceRoot":"","sources":["../../src/data/DetailList.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAclC;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,EAAE,IAAI,EAAE,SAAS,EAAmB;IAC7D,OAAO,CACL,aAAI,SAAS,EAAE,EAAE,CAAC,qCAAqC,EAAE,SAAS,CAAC,YAChE,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CACjB,eAEE,SAAS,EAAC,yGAAyG,aAEnH,aAAI,SAAS,EAAC,8DAA8D,YACzE,GAAG,CAAC,KAAK,GACP,EACL,aAAI,SAAS,EAAC,6CAA6C,YAAE,GAAG,CAAC,KAAK,GAAM,KANvE,GAAG,CAAC,KAAK,CAOV,CACP,CAAC,GACC,CACN,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"DetailList.js","sourceRoot":"","sources":["../../src/data/DetailList.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AA8BlC;;;GAGG;AACH,MAAM,YAAY,GAA2D;IAC3E,KAAK,EAAE,eAAe;IACtB,yFAAyF;IACzF,yCAAyC;IACzC,OAAO,EAAE,qCAAqC;CAC/C,CAAC;AAEF,MAAM,UAAU,UAAU,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,EAAmB;IAC/E,OAAO,CACL,aAAI,SAAS,EAAE,EAAE,CAAC,YAAY,CAAC,MAAM,CAAC,EAAE,uBAAuB,EAAE,SAAS,CAAC,YACxE,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CACjB,eAEE,SAAS,EAAC,yGAAyG,aAEnH,aAAI,SAAS,EAAC,8DAA8D,YACzE,GAAG,CAAC,KAAK,GACP,EACL,aAAI,SAAS,EAAC,6CAA6C,YAAE,GAAG,CAAC,KAAK,GAAM,KANvE,GAAG,CAAC,KAAK,CAOV,CACP,CAAC,GACC,CACN,CAAC;AACJ,CAAC"}
@@ -12,6 +12,30 @@ interface PaginationBase {
12
12
  * component that only knew about pages could not produce the sentence the product needs.
13
13
  */
14
14
  status: string;
15
+ /** Composed after the kit's own classes (design principle 2). Lands on the `<nav>`. */
16
+ className?: string;
17
+ /**
18
+ * Passed to both buttons. `sm` for a dense list footer. Omitted, the buttons keep the
19
+ * size they had — which is what every caller got before 0.17.0.
20
+ */
21
+ size?: 'md' | 'sm';
22
+ /**
23
+ * On a narrow viewport, stack the three parts vertically. Off by default: the same rule as
24
+ * `Modal`'s `sheetOnMobile` — a component that changes shape at a breakpoint is a decision.
25
+ */
26
+ stackOnMobile?: boolean;
27
+ /**
28
+ * Where the status sentence sits. `center` (default) is between the two buttons — what the
29
+ * component always drew. `start` puts it before both, `end` after both.
30
+ *
31
+ * 🔴 Not a free layout. Three positions is the whole space a row of two buttons and one
32
+ * sentence has, which makes it structure (design principle 3), not a value.
33
+ *
34
+ * There is deliberately no "hide when empty" prop: the kit cannot know a list is empty (the
35
+ * offset model carries no total), and `{total > 0 && <Pagination … />}` says it in the one
36
+ * place that does know. A prop would only move that line and pretend the kit decided.
37
+ */
38
+ statusPlacement?: 'start' | 'center' | 'end';
15
39
  }
16
40
  interface PagePagination extends PaginationBase {
17
41
  /** 1-based. */
@@ -1,6 +1,7 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { Button } from '../primitives/Button.js';
3
3
  import { Stack } from '../layout/Stack.js';
4
+ import { cx } from '../lib/cx.js';
4
5
  /**
5
6
  * Page-by-page navigation for a list.
6
7
  *
@@ -22,11 +23,21 @@ import { Stack } from '../layout/Stack.js';
22
23
  * the row jump, and moves the next-page button under the cursor that just clicked it.
23
24
  */
24
25
  export function Pagination(props) {
25
- const { label, previousLabel, nextLabel, status } = props;
26
+ const { label, previousLabel, nextLabel, status, className, size = 'md', stackOnMobile, statusPlacement = 'center', } = props;
26
27
  const atStart = props.page === undefined ? !props.canPrev : props.page <= 1;
27
28
  const atEnd = props.page === undefined ? !props.canNext : props.page >= props.pageCount;
28
29
  const goPrev = () => props.page === undefined ? props.onPrev() : props.onPageChange(props.page - 1);
29
30
  const goNext = () => props.page === undefined ? props.onNext() : props.onPageChange(props.page + 1);
30
- return (_jsx("nav", { "aria-label": label, children: _jsxs(Stack, { direction: "horizontal", gap: "2xs", align: "center", children: [_jsx(Button, { variant: "secondary", disabled: atStart, onClick: goPrev, "aria-label": previousLabel, children: previousLabel }), _jsx("span", { "aria-current": "page", className: "font-sans text-x-slot-pagination-fg", children: status }), _jsx(Button, { variant: "secondary", disabled: atEnd, onClick: goNext, "aria-label": nextLabel, children: nextLabel })] }) }));
31
+ const prev = (_jsx(Button, { variant: "secondary", size: size, disabled: atStart, onClick: goPrev, "aria-label": previousLabel, children: previousLabel }, "prev"));
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: "secondary", size: size, disabled: atEnd, onClick: goNext, "aria-label": nextLabel, children: nextLabel }, "next"));
34
+ const order = statusPlacement === 'start'
35
+ ? [current, prev, next]
36
+ : statusPlacement === 'end'
37
+ ? [prev, next, current]
38
+ : [prev, current, next];
39
+ return (_jsx("nav", { "aria-label": label, className: className, children: _jsx(Stack, { direction: "horizontal", gap: "2xs", align: "center",
40
+ // Every class carries the `max-sm:` prefix, so a wide viewport is untouched.
41
+ className: cx(stackOnMobile === true && 'max-sm:flex-col max-sm:items-stretch'), children: order }) }));
31
42
  }
32
43
  //# sourceMappingURL=Pagination.js.map
@@ -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;AAyC3C;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,UAAU,CAAC,KAAsB;IAC/C,MAAM,EAAE,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,KAAK,CAAC;IAE1D,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,OAAO,CACL,4BAAiB,KAAK,YACpB,MAAC,KAAK,IAAC,SAAS,EAAC,YAAY,EAAC,GAAG,EAAC,KAAK,EAAC,KAAK,EAAC,QAAQ,aACpD,KAAC,MAAM,IAAC,OAAO,EAAC,WAAW,EAAC,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAc,aAAa,YACtF,aAAa,GACP,EACT,+BAAmB,MAAM,EAAC,SAAS,EAAC,qCAAqC,YACtE,MAAM,GACF,EACP,KAAC,MAAM,IAAC,OAAO,EAAC,WAAW,EAAC,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAc,SAAS,YAChF,SAAS,GACH,IACH,GACJ,CACP,CAAC;AACJ,CAAC"}
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,WAAW,EACnB,IAAI,EAAE,IAAI,EACV,QAAQ,EAAE,OAAO,EACjB,OAAO,EAAE,MAAM,gBACH,aAAa,YAExB,aAAa,IAPV,MAAM,CAQH,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,WAAW,EACnB,IAAI,EAAE,IAAI,EACV,QAAQ,EAAE,KAAK,EACf,OAAO,EAAE,MAAM,gBACH,SAAS,YAEpB,SAAS,IAPN,MAAM,CAQH,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"}
@@ -1,7 +1,17 @@
1
1
  import type { ReactNode } from 'react';
2
2
  export interface BadgeProps {
3
- /** What the badge means, not what colour it is. */
4
- tone?: 'neutral' | 'accent' | 'danger';
3
+ /**
4
+ * What the badge means, not what colour it is.
5
+ *
6
+ * 🔴 `success` / `warn` / `info` — not `ok` / `warning`. Five ships carry a success and a
7
+ * warning tone in their own badge and they do not agree on the words (clear and invoice
8
+ * say `ok`, origin says `warning`); the contract bans both synonyms, and `InlineAlert`
9
+ * already says `warn`. One vocabulary across the kit, so a tone means the same thing in a
10
+ * badge as it does in an alert (0.17.0, #422).
11
+ */
12
+ tone?: 'neutral' | 'accent' | 'danger' | 'success' | 'warn' | 'info';
13
+ /** Composed after the kit's own classes (design principle 2). */
14
+ className?: string;
5
15
  children: ReactNode;
6
16
  }
7
17
  /**
@@ -11,4 +21,4 @@ export interface BadgeProps {
11
21
  * `<Badge color="red">` becomes a lie the moment the theme changes, and there is no way to
12
22
  * find every such lie afterwards except by reading every screen.
13
23
  */
14
- export declare function Badge({ tone, children }: BadgeProps): import("react").JSX.Element;
24
+ export declare function Badge({ tone, className, children }: BadgeProps): import("react").JSX.Element;
@@ -4,6 +4,9 @@ const TONE_CLASS = {
4
4
  neutral: 'bg-x-slot-badge-neutral-bg text-x-slot-badge-neutral-fg border-x-slot-badge-neutral-border',
5
5
  accent: 'bg-x-slot-badge-accent-bg text-x-slot-badge-accent-fg border-x-slot-badge-accent-border',
6
6
  danger: 'bg-x-slot-badge-danger-bg text-x-slot-badge-danger-fg border-x-slot-badge-danger-border',
7
+ success: 'bg-x-slot-badge-success-bg text-x-slot-badge-success-fg border-x-slot-badge-success-border',
8
+ warn: 'bg-x-slot-badge-warn-bg text-x-slot-badge-warn-fg border-x-slot-badge-warn-border',
9
+ info: 'bg-x-slot-badge-info-bg text-x-slot-badge-info-fg border-x-slot-badge-info-border',
7
10
  };
8
11
  /**
9
12
  * A small status marker.
@@ -12,7 +15,7 @@ const TONE_CLASS = {
12
15
  * `<Badge color="red">` becomes a lie the moment the theme changes, and there is no way to
13
16
  * find every such lie afterwards except by reading every screen.
14
17
  */
15
- export function Badge({ tone = 'neutral', children }) {
16
- return (_jsx("span", { className: cx('inline-flex items-center rounded-x-slot-badge border px-x-slot-badge-pad-x py-x-slot-badge-pad-y font-sans', TONE_CLASS[tone]), children: children }));
18
+ export function Badge({ tone = 'neutral', className, children }) {
19
+ return (_jsx("span", { className: cx('inline-flex items-center rounded-x-slot-badge border px-x-slot-badge-pad-x py-x-slot-badge-pad-y font-sans', TONE_CLASS[tone], className), children: children }));
17
20
  }
18
21
  //# 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;AAQlC,MAAM,UAAU,GAAoD;IAClE,OAAO,EACL,4FAA4F;IAC9F,MAAM,EAAE,yFAAyF;IACjG,MAAM,EAAE,yFAAyF;CAClG,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,UAAU,KAAK,CAAC,EAAE,IAAI,GAAG,SAAS,EAAE,QAAQ,EAAc;IAC9D,OAAO,CACL,eACE,SAAS,EAAE,EAAE,CACX,4GAA4G,EAC5G,UAAU,CAAC,IAAI,CAAC,CACjB,YAEA,QAAQ,GACJ,CACR,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"Badge.js","sourceRoot":"","sources":["../../src/feedback/Badge.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAkBlC,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,MAAM,UAAU,KAAK,CAAC,EAAE,IAAI,GAAG,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAc;IACzE,OAAO,CACL,eACE,SAAS,EAAE,EAAE,CACX,4GAA4G,EAC5G,UAAU,CAAC,IAAI,CAAC,EAChB,SAAS,CACV,YAEA,QAAQ,GACJ,CACR,CAAC;AACJ,CAAC"}
@@ -37,6 +37,8 @@ export interface FormFieldProps {
37
37
  * Folding the two together would mean the kit picking "*" for every locale.
38
38
  */
39
39
  requiredMarker?: ReactNode;
40
+ /** Composed after the kit's own classes (design principle 2). Lands on the outer `<div>`. */
41
+ className?: string;
40
42
  children: ReactNode;
41
43
  }
42
44
  /**
@@ -54,4 +56,4 @@ export interface FormFieldProps {
54
56
  * 🔴 The hint stays visible when there is an error. nene-profile hides it in that case, and
55
57
  * that is the moment the user most needs it; the error is read first instead.
56
58
  */
57
- export declare function FormField({ id, label, error, warning, hint, labelAdornment, required, requiredMarker, children, }: FormFieldProps): import("react").JSX.Element;
59
+ export declare function FormField({ id, label, error, warning, hint, labelAdornment, required, requiredMarker, className, children, }: FormFieldProps): import("react").JSX.Element;
@@ -1,6 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useMemo } from 'react';
3
3
  import { FieldContext } from './field-context.js';
4
+ import { cx } from '../lib/cx.js';
4
5
  /**
5
6
  * Labelled form field wrapper: associates a `<label>` with its control, and links the
6
7
  * control to its help text and its validation error.
@@ -16,12 +17,12 @@ import { FieldContext } from './field-context.js';
16
17
  * 🔴 The hint stays visible when there is an error. nene-profile hides it in that case, and
17
18
  * that is the moment the user most needs it; the error is read first instead.
18
19
  */
19
- export function FormField({ id, label, error = null, warning = null, hint, labelAdornment, required = false, requiredMarker, children, }) {
20
+ export function FormField({ id, label, error = null, warning = null, hint, labelAdornment, required = false, requiredMarker, className, children, }) {
20
21
  const errorId = error === null ? null : `${id}-error`;
21
22
  const warningId = warning === null ? null : `${id}-warning`;
22
23
  const hintId = hint === undefined || hint === null ? null : `${id}-hint`;
23
24
  const value = useMemo(() => ({ id, errorId, warningId, hintId, required }), [id, errorId, warningId, hintId, required]);
24
- return (_jsx(FieldContext.Provider, { value: value, children: _jsxs("div", { className: "flex flex-col gap-x-slot-field-gap", children: [_jsxs("label", { htmlFor: id, className: "font-sans font-x-slot-field-label text-x-slot-field-label-size text-x-slot-field-label", children: [label, required && requiredMarker !== undefined && requiredMarker !== null ? (_jsx("span", { className: "text-x-slot-field-required-marker", children: requiredMarker })) : null, labelAdornment] }), children, hintId === null ? null : (_jsx("span", { id: hintId, className: "font-sans text-x-slot-field-hint-size text-x-slot-field-hint", children: hint })), warningId === null ? null : (
25
+ return (_jsx(FieldContext.Provider, { value: value, children: _jsxs("div", { className: cx('flex flex-col gap-x-slot-field-gap', className), children: [_jsxs("label", { htmlFor: id, className: "font-sans font-x-slot-field-label text-x-slot-field-label-size text-x-slot-field-label", children: [label, required && requiredMarker !== undefined && requiredMarker !== null ? (_jsx("span", { className: "text-x-slot-field-required-marker", children: requiredMarker })) : null, labelAdornment] }), children, hintId === null ? null : (_jsx("span", { id: hintId, className: "font-sans text-x-slot-field-hint-size text-x-slot-field-hint", children: hint })), warningId === null ? null : (
25
26
  // role="status" ではなく role="alert" にすると、入力の途中で読み上げを割り込む。
26
27
  // 警告は「見直す価値がある」であって「止まれ」ではないので、次の切れ目で読ませる。
27
28
  _jsx("p", { id: warningId, role: "status", className: "font-sans text-x-slot-field-error-size text-x-slot-field-warning-fg", children: warning })), errorId === null ? null : (_jsx("p", { id: errorId, role: "alert", className: "font-sans text-x-slot-field-error-size text-x-slot-field-error", children: error }))] }) }));
@@ -1 +1 @@
1
- {"version":3,"file":"FormField.js","sourceRoot":"","sources":["../../src/forms/FormField.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,OAAO,EAAkB,MAAM,OAAO,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AA2ClD;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,SAAS,CAAC,EACxB,EAAE,EACF,KAAK,EACL,KAAK,GAAG,IAAI,EACZ,OAAO,GAAG,IAAI,EACd,IAAI,EACJ,cAAc,EACd,QAAQ,GAAG,KAAK,EAChB,cAAc,EACd,QAAQ,GACO;IACf,MAAM,OAAO,GAAG,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,QAAQ,CAAC;IACtD,MAAM,SAAS,GAAG,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,UAAU,CAAC;IAC5D,MAAM,MAAM,GAAG,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,OAAO,CAAC;IACzE,MAAM,KAAK,GAAG,OAAO,CACnB,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,EACpD,CAAC,EAAE,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,CAAC,CAC3C,CAAC;IAEF,OAAO,CACL,KAAC,YAAY,CAAC,QAAQ,IAAC,KAAK,EAAE,KAAK,YACjC,eAAK,SAAS,EAAC,oCAAoC,aACjD,iBACE,OAAO,EAAE,EAAE,EACX,SAAS,EAAC,wFAAwF,aAEjG,KAAK,EACL,QAAQ,IAAI,cAAc,KAAK,SAAS,IAAI,cAAc,KAAK,IAAI,CAAC,CAAC,CAAC,CACrE,eAAM,SAAS,EAAC,mCAAmC,YAAE,cAAc,GAAQ,CAC5E,CAAC,CAAC,CAAC,IAAI,EACP,cAAc,IACT,EACP,QAAQ,EACR,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CACxB,eACE,EAAE,EAAE,MAAM,EACV,SAAS,EAAC,8DAA8D,YAEvE,IAAI,GACA,CACR,EACA,SAAS,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;gBAC3B,wDAAwD;gBACxD,2CAA2C;gBAC3C,YACE,EAAE,EAAE,SAAS,EACb,IAAI,EAAC,QAAQ,EACb,SAAS,EAAC,qEAAqE,YAE9E,OAAO,GACN,CACL,EACA,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CACzB,YACE,EAAE,EAAE,OAAO,EACX,IAAI,EAAC,OAAO,EACZ,SAAS,EAAC,gEAAgE,YAEzE,KAAK,GACJ,CACL,IACG,GACgB,CACzB,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"FormField.js","sourceRoot":"","sources":["../../src/forms/FormField.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,OAAO,EAAkB,MAAM,OAAO,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AA6ClC;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,SAAS,CAAC,EACxB,EAAE,EACF,KAAK,EACL,KAAK,GAAG,IAAI,EACZ,OAAO,GAAG,IAAI,EACd,IAAI,EACJ,cAAc,EACd,QAAQ,GAAG,KAAK,EAChB,cAAc,EACd,SAAS,EACT,QAAQ,GACO;IACf,MAAM,OAAO,GAAG,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,QAAQ,CAAC;IACtD,MAAM,SAAS,GAAG,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,UAAU,CAAC;IAC5D,MAAM,MAAM,GAAG,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,OAAO,CAAC;IACzE,MAAM,KAAK,GAAG,OAAO,CACnB,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,EACpD,CAAC,EAAE,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,CAAC,CAC3C,CAAC;IAEF,OAAO,CACL,KAAC,YAAY,CAAC,QAAQ,IAAC,KAAK,EAAE,KAAK,YACjC,eAAK,SAAS,EAAE,EAAE,CAAC,oCAAoC,EAAE,SAAS,CAAC,aACjE,iBACE,OAAO,EAAE,EAAE,EACX,SAAS,EAAC,wFAAwF,aAEjG,KAAK,EACL,QAAQ,IAAI,cAAc,KAAK,SAAS,IAAI,cAAc,KAAK,IAAI,CAAC,CAAC,CAAC,CACrE,eAAM,SAAS,EAAC,mCAAmC,YAAE,cAAc,GAAQ,CAC5E,CAAC,CAAC,CAAC,IAAI,EACP,cAAc,IACT,EACP,QAAQ,EACR,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CACxB,eACE,EAAE,EAAE,MAAM,EACV,SAAS,EAAC,8DAA8D,YAEvE,IAAI,GACA,CACR,EACA,SAAS,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;gBAC3B,wDAAwD;gBACxD,2CAA2C;gBAC3C,YACE,EAAE,EAAE,SAAS,EACb,IAAI,EAAC,QAAQ,EACb,SAAS,EAAC,qEAAqE,YAE9E,OAAO,GACN,CACL,EACA,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CACzB,YACE,EAAE,EAAE,OAAO,EACX,IAAI,EAAC,OAAO,EACZ,SAAS,EAAC,gEAAgE,YAEzE,KAAK,GACJ,CACL,IACG,GACgB,CACzB,CAAC;AACJ,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hideyukimori/nene2-ui",
3
- "version": "0.16.1",
3
+ "version": "0.17.1",
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",
@@ -43,6 +43,22 @@
43
43
  --color-on-warn: oklch(21% 0.04 75);
44
44
  --color-danger-soft: oklch(95% 0.03 30);
45
45
 
46
+ /* 🔴 Six more contract colours, added in 0.17.0 for `Badge` (#422). Five ships carry a
47
+ * success tone and a warning tone in their own badge (clear / field / invoice / origin /
48
+ * vault) and four carry `info`, so a kit badge with three tones could not say what their
49
+ * screens already say. Hues follow the contract's reference theme; lightness is measured:
50
+ * white on this `success` is 5.35:1 and on this `info` 5.78:1 (both clear 4.5:1 for text),
51
+ * the fills are 5.51:1 / 5.95:1 against `surface-raised`, and `text-primary` on either
52
+ * soft is ≥ 13.8:1 — computed with the same OKLCH→sRGB pipeline that reproduces the
53
+ * `warn` figures above (3.48 / 3.58 / 4.97), so the calculator has a positive control.
54
+ * Fourteen contract colours are still undefined — see the README. */
55
+ --color-success: oklch(50% 0.14 155);
56
+ --color-success-soft: oklch(95% 0.03 155);
57
+ --color-on-success: oklch(99% 0 0);
58
+ --color-info: oklch(50% 0.12 245);
59
+ --color-info-soft: oklch(95% 0.03 245);
60
+ --color-on-info: oklch(99% 0 0);
61
+
46
62
  /* The shadow scale. Three steps, chosen the way the spacing and radius scales were —
47
63
  * measured from what the fleet already ships, not invented here (#386).
48
64
  *
@@ -303,6 +319,17 @@
303
319
  --color-x-slot-badge-danger-bg: var(--color-danger);
304
320
  --color-x-slot-badge-danger-fg: var(--color-on-accent);
305
321
  --color-x-slot-badge-danger-border: var(--color-danger);
322
+ /* 0.17.0 (#422). Filled, like `accent` and `danger`: a status badge is read at a glance
323
+ * and an outlined success next to a filled danger would weigh the two unequally. */
324
+ --color-x-slot-badge-success-bg: var(--color-success);
325
+ --color-x-slot-badge-success-fg: var(--color-on-success);
326
+ --color-x-slot-badge-success-border: var(--color-success);
327
+ --color-x-slot-badge-warn-bg: var(--color-warn);
328
+ --color-x-slot-badge-warn-fg: var(--color-on-warn);
329
+ --color-x-slot-badge-warn-border: var(--color-warn);
330
+ --color-x-slot-badge-info-bg: var(--color-info);
331
+ --color-x-slot-badge-info-fg: var(--color-on-info);
332
+ --color-x-slot-badge-info-border: var(--color-info);
306
333
 
307
334
  --color-x-slot-toast-bg: var(--color-surface-raised);
308
335
  --color-x-slot-toast-fg: var(--color-text-primary);