@hideyukimori/nene2-ui 0.17.1 → 0.18.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
@@ -137,12 +137,13 @@ The theme has two layers, and the line between them is the point.
137
137
 
138
138
  ### ② Slots — 🟢 redefine these
139
139
 
140
- Every design value a component uses comes from a slot, and slots are named per component:
140
+ Every design value a component takes **from the theme** comes from a slot, and slots are named
141
+ per component:
141
142
 
142
143
  ```css
143
144
  /* your product's theme, loaded after the kit's */
144
145
  @theme {
145
- --spacing-x-slot-card-pad: var(--spacing-x-lg); /* roomier cards, everywhere */
146
+ --spacing-x-slot-modal-pad: var(--spacing-x-lg); /* roomier modals, everywhere */
146
147
  --color-x-slot-field-label: var(--color-text-primary); /* darker field labels */
147
148
  --radius-x-slot-control: var(--radius-x-md);
148
149
  }
@@ -151,6 +152,18 @@ Every design value a component uses comes from a slot, and slots are named per c
151
152
  This is where your product decides how it looks. Change a slot and every instance of that
152
153
  component follows.
153
154
 
155
+ 🔴 **"From the theme" is the limit of that sentence, and the limit is load-bearing.** The
156
+ **layout components take their spacing from props, not from slots** — `Box` and `Card` (`pad`),
157
+ `Stack` (`gap`), `Section` and `Grid` (both). That is deliberate rather than an omission: layout
158
+ spacing is a decision the *caller* makes per instance, so it is chosen at the call site. Those
159
+ props still pick a **step from the scale** (`pad="lg"`), so a product cannot invent a value here
160
+ either — but **no slot exists for them**.
161
+
162
+ ⚠️ **This is the part that bites.** Writing `--spacing-x-slot-card-pad` in your theme does
163
+ nothing at all: **there is no such slot**, and nothing warns you — not an error, not a console
164
+ message, not a failing build. To make every card roomier, pass `pad` where you use `Card`, or
165
+ wrap it once in a component of your own.
166
+
154
167
  ### ① The scale — 🔒 do not redefine
155
168
 
156
169
  `--spacing-x-3xs` … `--spacing-x-2xl`, `--radius-x-none` … `--radius-x-3xl` plus
@@ -223,9 +236,12 @@ second only under `@media (pointer: coarse)`.
223
236
 
224
237
  ### Composing a slot
225
238
 
226
- A slot can hold several steps — four-sided padding is just CSS:
239
+ A slot can hold several steps — four-sided padding is just CSS. The slot below belongs to a
240
+ component **of your own**, not to the kit (`login-form` is not a kit component); a product
241
+ names slots for its own parts the same way the kit does:
227
242
 
228
243
  ```css
244
+ /* in your product, for your own <LoginForm> */
229
245
  --spacing-x-slot-login-form-pad: var(--spacing-x-xl) var(--spacing-x-md) var(--spacing-x-lg)
230
246
  var(--spacing-x-md);
231
247
  ```
@@ -5,8 +5,14 @@ import { CLICKABLE_CLASS } from '../lib/states.js';
5
5
  import { ToastContext } from './toast-context.js';
6
6
  const TONE_CLASS = {
7
7
  info: 'bg-x-slot-toast-bg text-x-slot-toast-fg border-x-slot-toast-border',
8
+ success: 'bg-x-slot-toast-bg text-x-slot-toast-success-fg border-x-slot-toast-success-border',
8
9
  danger: 'bg-x-slot-toast-bg text-x-slot-toast-danger-fg border-x-slot-toast-danger-border',
9
10
  };
11
+ // 🔴 `success` は polite 側。`assertive` は読み上げを中断させるので、成功の報告に使うと
12
+ // 利用者の作業を割り込みで止める。中断してよいのは danger だけ、というのが2リージョンに
13
+ // 分けた元の理由なので、語彙が増えてもその線は動かさない(#457)。
14
+ const POLITE_TONES = ['info', 'success'];
15
+ const ASSERTIVE_TONES = ['danger'];
10
16
  /**
11
17
  * Hosts the toast queue and the live regions that announce it.
12
18
  *
@@ -34,7 +40,18 @@ export function ToastProvider({ regionLabel, dismissLabel, defaultDurationMs = 5
34
40
  }, []);
35
41
  const show = useCallback((message, options) => {
36
42
  const id = `toast-${(nextId.current += 1)}`;
37
- setToasts((current) => [...current, { id, message, tone: options?.tone ?? 'info' }]);
43
+ const description = options?.description;
44
+ setToasts((current) => [
45
+ ...current,
46
+ {
47
+ id,
48
+ message,
49
+ tone: options?.tone ?? 'info',
50
+ // exactOptionalPropertyTypes: 省略と `undefined` を渡すことは別物なので、
51
+ // 渡されなかった場合はキーごと作らない。
52
+ ...(description === undefined ? {} : { description }),
53
+ },
54
+ ]);
38
55
  timers.current.set(id, setTimeout(() => dismiss(id), options?.durationMs ?? defaultDurationMs));
39
56
  return id;
40
57
  }, [defaultDurationMs, dismiss]);
@@ -48,9 +65,11 @@ export function ToastProvider({ regionLabel, dismissLabel, defaultDurationMs = 5
48
65
  };
49
66
  }, []);
50
67
  const api = useMemo(() => ({ show, dismiss }), [show, dismiss]);
51
- const region = (tone, live) => (_jsx("div", { "aria-live": live, "aria-label": regionLabel, role: "region", className: "flex flex-col gap-x-slot-toast-gap", children: toasts
52
- .filter((toast) => toast.tone === tone)
53
- .map((toast) => (_jsxs("div", { className: cx('flex items-start gap-x-slot-toast-gap rounded-x-slot-toast border p-x-slot-toast-pad font-sans shadow-x-slot-toast', TONE_CLASS[toast.tone]), children: [_jsx("span", { children: toast.message }), _jsx("button", { type: "button", "aria-label": dismissLabel, onClick: () => dismiss(toast.id), className: cx('rounded-x-slot-toast px-x-slot-toast-dismiss-pad-x', CLICKABLE_CLASS), children: dismissLabel })] }, toast.id))) }));
54
- return (_jsxs(ToastContext.Provider, { value: api, children: [children, region('info', 'polite'), region('danger', 'assertive')] }));
68
+ const region = (tones, live) => (_jsx("div", { "aria-live": live, "aria-label": regionLabel, role: "region", className: "flex flex-col gap-x-slot-toast-gap", children: toasts
69
+ // 複数トーンを1つのリージョンへ。元の配列を filter するので、同じリージョンに
70
+ // 入るトースト同士の**表示順は push された順のまま**になる。
71
+ .filter((toast) => tones.includes(toast.tone))
72
+ .map((toast) => (_jsxs("div", { className: cx('flex items-start gap-x-slot-toast-gap rounded-x-slot-toast border p-x-slot-toast-pad font-sans shadow-x-slot-toast', TONE_CLASS[toast.tone]), children: [toast.description === undefined ? (_jsx("span", { children: toast.message })) : (_jsxs("span", { className: "flex flex-col gap-x-slot-toast-description-gap", children: [_jsx("span", { children: toast.message }), _jsx("span", { className: "text-x-slot-toast-description-fg", children: toast.description })] })), _jsx("button", { type: "button", "aria-label": dismissLabel, onClick: () => dismiss(toast.id), className: cx('rounded-x-slot-toast px-x-slot-toast-dismiss-pad-x', CLICKABLE_CLASS), children: dismissLabel })] }, toast.id))) }));
73
+ return (_jsxs(ToastContext.Provider, { value: api, children: [children, region(POLITE_TONES, 'polite'), region(ASSERTIVE_TONES, 'assertive')] }));
55
74
  }
56
75
  //# sourceMappingURL=ToastProvider.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ToastProvider.js","sourceRoot":"","sources":["../../src/feedback/ToastProvider.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ToastProvider.js","sourceRoot":"","sources":["../../src/feedback/ToastProvider.tsx"],"names":[],"mappings":"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"}
@@ -1,8 +1,27 @@
1
- export type ToastTone = 'info' | 'danger';
1
+ /**
2
+ * 🔴 `success` は 0.17.x まで無く、`info | danger` の2語彙だった。`Badge` と `InlineAlert`
3
+ * は既に `success` を持っており(Badge は neutral|accent|danger|success|warn|info)、
4
+ * **トーストだけ語彙が2つ**という状態は 0.17.0 #422 の「一つの語彙をキット全体で」と
5
+ * 噛み合わない。nene-deal は完了を緑で伝えており、`info` に寄せると保存・移動・削除の
6
+ * 完了が中立色になって、エラーとの差が「赤かどうか」だけになる(#457)。
7
+ */
8
+ export type ToastTone = 'info' | 'success' | 'danger';
2
9
  export interface ToastOptions {
3
10
  tone?: ToastTone;
4
11
  /** Overrides the provider's default. */
5
12
  durationMs?: number;
13
+ /**
14
+ * Localized second line: what the action applied to.
15
+ *
16
+ * 🔴 Not decoration. nene-deal's success toasts carry one at **7 of 7** call sites — the
17
+ * deal that moved, the stage it moved to, the range that was exported. `show(message)`
18
+ * alone drops that text, and joining the two halves is not available to the ship: they are
19
+ * separate catalog keys, so the separator would be a string owned by the ship, against
20
+ * principle 4 (#457).
21
+ *
22
+ * Omit it and the render is what it was before this prop existed.
23
+ */
24
+ description?: string;
6
25
  }
7
26
  export interface ToastApi {
8
27
  /** Shows a toast and returns its id, so a caller can dismiss it early. */
@@ -1 +1 @@
1
- {"version":3,"file":"toast-context.js","sourceRoot":"","sources":["../../src/feedback/toast-context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AAgBlD,MAAM,CAAC,MAAM,YAAY,GAAG,aAAa,CAAkB,IAAI,CAAC,CAAC;AAEjE;;;;;;GAMG;AACH,MAAM,UAAU,QAAQ;IACtB,MAAM,GAAG,GAAG,UAAU,CAAC,YAAY,CAAC,CAAC;IACrC,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;IACpE,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
1
+ {"version":3,"file":"toast-context.js","sourceRoot":"","sources":["../../src/feedback/toast-context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AAmClD,MAAM,CAAC,MAAM,YAAY,GAAG,aAAa,CAAkB,IAAI,CAAC,CAAC;AAEjE;;;;;;GAMG;AACH,MAAM,UAAU,QAAQ;IACtB,MAAM,GAAG,GAAG,UAAU,CAAC,YAAY,CAAC,CAAC;IACrC,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;IACpE,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
package/dist/index.js CHANGED
@@ -39,8 +39,10 @@ export { Pagination } from './data/Pagination.js';
39
39
  export { tokens } from './theme/tokens.js';
40
40
  // Internal helpers, exported so downstream components can compose consistently.
41
41
  export { cx } from './lib/cx.js';
42
- // Controls the kit does not ship yet (Textarea has 7 independent implementations in the
43
- // fleet) can at least carry the same focus and disabled behaviour instead of inventing it.
42
+ // A control the kit does not ship — one a product writes for itself, or one still waiting for
43
+ // a slot in the kit — can at least carry the same focus and disabled behaviour instead of
44
+ // inventing it. (Written when `Textarea` was the example, with 7 independent implementations
45
+ // across the fleet; `Textarea` ships now, so the example is gone but the reason is not.)
44
46
  export { CLICKABLE_CLASS, CONTROL_CLASS, DISABLED_CLASS, FOCUS_CLASS, HOVER_CLASS, } from './lib/states.js';
45
47
  // Lets a consumer's build prove the kit is in its Tailwind `@source` (#316).
46
48
  export { SOURCE_PROBE_CLASS } from './lib/source-probe.js';
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,aAAa;AACb,OAAO,EAAE,MAAM,EAAoB,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,KAAK,EAAmB,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,MAAM,EAAoB,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,OAAO,EAAqB,MAAM,yBAAyB,CAAC;AACrE,OAAO,EAAE,IAAI,EAAkB,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,QAAQ,EAAsB,MAAM,0BAA0B,CAAC;AACxE,OAAO,EAAE,IAAI,EAAkB,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,QAAQ,EAAsB,MAAM,0BAA0B,CAAC;AACxE,OAAO,EAAE,KAAK,EAAmB,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,MAAM,EAAoB,MAAM,wBAAwB,CAAC;AAElE,SAAS;AACT,OAAO,EAAE,UAAU,EAAwB,MAAM,wBAAwB,CAAC;AAC1E,OAAO,EAAE,KAAK,EAAmB,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,IAAI,EAAkB,MAAM,kBAAkB,CAAC;AACxD,OAAO,EAAE,GAAG,EAAiB,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAE,OAAO,EAAqB,MAAM,qBAAqB,CAAC;AACjE,OAAO,EAAE,IAAI,EAAkB,MAAM,kBAAkB,CAAC;AAKxD,QAAQ;AACR,OAAO,EAAE,SAAS,EAAuB,MAAM,sBAAsB,CAAC;AAEtE,sFAAsF;AACtF,sDAAsD;AACtD,OAAO,EAAE,YAAY,EAA0B,MAAM,0BAA0B,CAAC;AAChF,OAAO,EAAE,UAAU,EAAwB,MAAM,wBAAwB,CAAC;AAC1E,OAAO,EAAE,UAAU,EAAwB,MAAM,wBAAwB,CAAC;AAE1E,UAAU;AACV,OAAO,EAAE,KAAK,EAAmB,MAAM,oBAAoB,CAAC;AAC5D,OAAO,EAAE,aAAa,EAA2B,MAAM,4BAA4B,CAAC;AAEpF,WAAW;AACX,OAAO,EAAE,KAAK,EAAmB,MAAM,qBAAqB,CAAC;AAC7D,OAAO,EAAE,WAAW,EAAyB,MAAM,2BAA2B,CAAC;AAC/E,OAAO,EAAE,aAAa,EAA2B,MAAM,6BAA6B,CAAC;AACrF,OAAO,EACL,QAAQ,GAIT,MAAM,6BAA6B,CAAC;AAErC,OAAO;AACP,OAAO,EAAE,UAAU,EAAwC,MAAM,sBAAsB,CAAC;AACxF,OAAO,EAAE,SAAS,EAAwC,MAAM,qBAAqB,CAAC;AACtF,OAAO,EAAE,UAAU,EAAwB,MAAM,sBAAsB,CAAC;AAExE,QAAQ;AACR,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAE3C,gFAAgF;AAChF,OAAO,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AACjC,wFAAwF;AACxF,2FAA2F;AAC3F,OAAO,EACL,eAAe,EACf,aAAa,EACb,cAAc,EACd,WAAW,EACX,WAAW,GACZ,MAAM,iBAAiB,CAAC;AACzB,6EAA6E;AAC7E,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,aAAa;AACb,OAAO,EAAE,MAAM,EAAoB,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,KAAK,EAAmB,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,MAAM,EAAoB,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,OAAO,EAAqB,MAAM,yBAAyB,CAAC;AACrE,OAAO,EAAE,IAAI,EAAkB,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,QAAQ,EAAsB,MAAM,0BAA0B,CAAC;AACxE,OAAO,EAAE,IAAI,EAAkB,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,QAAQ,EAAsB,MAAM,0BAA0B,CAAC;AACxE,OAAO,EAAE,KAAK,EAAmB,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,MAAM,EAAoB,MAAM,wBAAwB,CAAC;AAElE,SAAS;AACT,OAAO,EAAE,UAAU,EAAwB,MAAM,wBAAwB,CAAC;AAC1E,OAAO,EAAE,KAAK,EAAmB,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,IAAI,EAAkB,MAAM,kBAAkB,CAAC;AACxD,OAAO,EAAE,GAAG,EAAiB,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAE,OAAO,EAAqB,MAAM,qBAAqB,CAAC;AACjE,OAAO,EAAE,IAAI,EAAkB,MAAM,kBAAkB,CAAC;AAKxD,QAAQ;AACR,OAAO,EAAE,SAAS,EAAuB,MAAM,sBAAsB,CAAC;AAEtE,sFAAsF;AACtF,sDAAsD;AACtD,OAAO,EAAE,YAAY,EAA0B,MAAM,0BAA0B,CAAC;AAChF,OAAO,EAAE,UAAU,EAAwB,MAAM,wBAAwB,CAAC;AAC1E,OAAO,EAAE,UAAU,EAAwB,MAAM,wBAAwB,CAAC;AAE1E,UAAU;AACV,OAAO,EAAE,KAAK,EAAmB,MAAM,oBAAoB,CAAC;AAC5D,OAAO,EAAE,aAAa,EAA2B,MAAM,4BAA4B,CAAC;AAEpF,WAAW;AACX,OAAO,EAAE,KAAK,EAAmB,MAAM,qBAAqB,CAAC;AAC7D,OAAO,EAAE,WAAW,EAAyB,MAAM,2BAA2B,CAAC;AAC/E,OAAO,EAAE,aAAa,EAA2B,MAAM,6BAA6B,CAAC;AACrF,OAAO,EACL,QAAQ,GAIT,MAAM,6BAA6B,CAAC;AAErC,OAAO;AACP,OAAO,EAAE,UAAU,EAAwC,MAAM,sBAAsB,CAAC;AACxF,OAAO,EAAE,SAAS,EAAwC,MAAM,qBAAqB,CAAC;AACtF,OAAO,EAAE,UAAU,EAAwB,MAAM,sBAAsB,CAAC;AAExE,QAAQ;AACR,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAE3C,gFAAgF;AAChF,OAAO,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AACjC,8FAA8F;AAC9F,0FAA0F;AAC1F,6FAA6F;AAC7F,yFAAyF;AACzF,OAAO,EACL,eAAe,EACf,aAAa,EACb,cAAc,EACd,WAAW,EACX,WAAW,GACZ,MAAM,iBAAiB,CAAC;AACzB,6EAA6E;AAC7E,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC"}
@@ -4,7 +4,7 @@ import { CLICKABLE_CLASS, TOUCH_CLASS } from '../lib/states.js';
4
4
  const VARIANT_CLASS = {
5
5
  primary: 'bg-x-slot-button-primary-bg text-x-slot-button-primary-fg shadow-x-slot-button-primary',
6
6
  secondary: 'bg-x-slot-button-secondary-bg text-x-slot-button-secondary-fg border-x-slot-button-secondary-border',
7
- danger: 'bg-x-slot-button-danger-bg text-x-slot-button-danger-fg',
7
+ danger: 'bg-x-slot-button-danger-bg text-x-slot-button-danger-fg border-x-slot-button-danger-border',
8
8
  // No fill and no border: for the third action in a row, where two framed buttons would
9
9
  // compete with each other. nene-vault ships this variant already.
10
10
  ghost: 'bg-transparent text-x-slot-button-ghost-fg',
@@ -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;AAchE,MAAM,aAAa,GAAwD;IACzE,OAAO,EAAE,wFAAwF;IACjG,SAAS,EACP,qGAAqG;IACvG,MAAM,EAAE,yDAAyD;IACjE,uFAAuF;IACvF,kEAAkE;IAClE,KAAK,EAAE,4CAA4C;CACpD,CAAC;AAEF,MAAM,UAAU,GAAqD;IACnE,EAAE,EAAE,uEAAuE;IAC3E,EAAE,EAAE,gFAAgF;CACrF,CAAC;AAEF,2FAA2F;AAC3F,4FAA4F;AAC5F,0FAA0F;AAC1F,wFAAwF;AACxF,6FAA6F;AAC7F,yFAAyF;AACzF,kCAAkC;AAClC,EAAE;AACF,0FAA0F;AAC1F,8FAA8F;AAC9F,8FAA8F;AAC9F,0FAA0F;AAC1F,EAAE;AACF,wFAAwF;AACxF,uFAAuF;AACvF,0FAA0F;AAC1F,6FAA6F;AAC7F,mDAAmD;AACnD,2FAA2F;AAC3F,6FAA6F;AAC7F,4FAA4F;AAC5F,yDAAyD;AACzD,EAAE;AACF,2FAA2F;AAC3F,0FAA0F;AAC1F,yFAAyF;AACzF,yFAAyF;AACzF,yCAAyC;AACzC,MAAM,SAAS,GAAG,mEAAmE,CAAC;AAEtF,MAAM,UAAU,GAAG,8IAA8I,SAAS,IAAI,WAAW,IAAI,eAAe,EAAE,CAAC;AAE/M,MAAM,UAAU,MAAM,CAAC,EACrB,OAAO,GAAG,SAAS,EACnB,IAAI,GAAG,IAAI,EACX,QAAQ,EACR,IAAI,GAAG,QAAQ,EACf,SAAS,EACT,GAAG,IAAI,EACK;IACZ,OAAO,CACL,iBACE,IAAI,EAAE,IAAI,EACV,SAAS,EAAE,EAAE,CAAC,UAAU,EAAE,UAAU,CAAC,IAAI,CAAC,EAAE,aAAa,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC,KAC1E,IAAI,YAEP,QAAQ,GACF,CACV,CAAC;AACJ,CAAC"}
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;AAchE,MAAM,aAAa,GAAwD;IACzE,OAAO,EAAE,wFAAwF;IACjG,SAAS,EACP,qGAAqG;IACvG,MAAM,EACJ,4FAA4F;IAC9F,uFAAuF;IACvF,kEAAkE;IAClE,KAAK,EAAE,4CAA4C;CACpD,CAAC;AAEF,MAAM,UAAU,GAAqD;IACnE,EAAE,EAAE,uEAAuE;IAC3E,EAAE,EAAE,gFAAgF;CACrF,CAAC;AAEF,2FAA2F;AAC3F,4FAA4F;AAC5F,0FAA0F;AAC1F,wFAAwF;AACxF,6FAA6F;AAC7F,yFAAyF;AACzF,kCAAkC;AAClC,EAAE;AACF,0FAA0F;AAC1F,8FAA8F;AAC9F,8FAA8F;AAC9F,0FAA0F;AAC1F,EAAE;AACF,wFAAwF;AACxF,uFAAuF;AACvF,0FAA0F;AAC1F,6FAA6F;AAC7F,mDAAmD;AACnD,2FAA2F;AAC3F,6FAA6F;AAC7F,4FAA4F;AAC5F,yDAAyD;AACzD,EAAE;AACF,2FAA2F;AAC3F,0FAA0F;AAC1F,yFAAyF;AACzF,yFAAyF;AACzF,yCAAyC;AACzC,MAAM,SAAS,GAAG,mEAAmE,CAAC;AAEtF,MAAM,UAAU,GAAG,8IAA8I,SAAS,IAAI,WAAW,IAAI,eAAe,EAAE,CAAC;AAE/M,MAAM,UAAU,MAAM,CAAC,EACrB,OAAO,GAAG,SAAS,EACnB,IAAI,GAAG,IAAI,EACX,QAAQ,EACR,IAAI,GAAG,QAAQ,EACf,SAAS,EACT,GAAG,IAAI,EACK;IACZ,OAAO,CACL,iBACE,IAAI,EAAE,IAAI,EACV,SAAS,EAAE,EAAE,CAAC,UAAU,EAAE,UAAU,CAAC,IAAI,CAAC,EAAE,aAAa,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC,KAC1E,IAAI,YAEP,QAAQ,GACF,CACV,CAAC;AACJ,CAAC"}
@@ -11,5 +11,18 @@ export interface EmptyStateProps {
11
11
  align?: 'center' | 'start';
12
12
  /** Localized message. The kit never ships strings — see README. */
13
13
  message: string;
14
+ /**
15
+ * Localized second line: what the empty area would hold, or how to fill it.
16
+ *
17
+ * 🔴 Not decoration. nene-deal's empty states carry two lines at three of their four call
18
+ * sites ("No deals yet" / "Create one from the board"), and folding them into `message`
19
+ * is not available to it: the two halves are separate catalog keys (`*.empty.title` and
20
+ * `*.empty.description`), so joining them would put the separator — a string — in the
21
+ * ship, against principle 4. Without this prop the second line has nowhere to go and the
22
+ * text is simply dropped (#456).
23
+ *
24
+ * Omit it and the render is byte-for-byte what it was before this prop existed.
25
+ */
26
+ description?: string;
14
27
  }
15
- export declare function EmptyState({ message, align, className }: EmptyStateProps): import("react").JSX.Element;
28
+ export declare function EmptyState({ message, description, align, className }: EmptyStateProps): import("react").JSX.Element;
@@ -1,6 +1,6 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { cx } from '../lib/cx.js';
3
- export function EmptyState({ message, align = 'center', className }) {
4
- return (_jsx("div", { className: cx('py-x-slot-state-pad-y font-sans text-x-slot-empty-state-fg', align === 'center' && 'text-center', className), role: "status", children: message }));
3
+ export function EmptyState({ message, description, align = 'center', className }) {
4
+ return (_jsx("div", { className: cx('py-x-slot-state-pad-y font-sans text-x-slot-empty-state-fg', align === 'center' && 'text-center', className), role: "status", children: description === undefined ? (message) : (_jsxs(_Fragment, { children: [_jsx("p", { children: message }), _jsx("p", { className: "mt-x-slot-empty-state-gap text-x-slot-empty-state-description-fg", children: description })] })) }));
5
5
  }
6
6
  //# sourceMappingURL=EmptyState.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"EmptyState.js","sourceRoot":"","sources":["../../src/states/EmptyState.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAgBlC,MAAM,UAAU,UAAU,CAAC,EAAE,OAAO,EAAE,KAAK,GAAG,QAAQ,EAAE,SAAS,EAAmB;IAClF,OAAO,CACL,cACE,SAAS,EAAE,EAAE,CACX,4DAA4D,EAC5D,KAAK,KAAK,QAAQ,IAAI,aAAa,EACnC,SAAS,CACV,EACD,IAAI,EAAC,QAAQ,YAEZ,OAAO,GACJ,CACP,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"EmptyState.js","sourceRoot":"","sources":["../../src/states/EmptyState.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AA6BlC,MAAM,UAAU,UAAU,CAAC,EAAE,OAAO,EAAE,WAAW,EAAE,KAAK,GAAG,QAAQ,EAAE,SAAS,EAAmB;IAC/F,OAAO,CACL,cACE,SAAS,EAAE,EAAE,CACX,4DAA4D,EAC5D,KAAK,KAAK,QAAQ,IAAI,aAAa,EACnC,SAAS,CACV,EACD,IAAI,EAAC,QAAQ,YAKZ,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,CAC3B,OAAO,CACR,CAAC,CAAC,CAAC,CACF,8BACE,sBAAI,OAAO,GAAK,EAChB,YAAG,SAAS,EAAC,kEAAkE,YAC5E,WAAW,GACV,IACH,CACJ,GACG,CACP,CAAC;AACJ,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hideyukimori/nene2-ui",
3
- "version": "0.17.1",
3
+ "version": "0.18.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",
@@ -130,10 +130,15 @@
130
130
  /* ─────────────────────────────────────────────────────────────────────────
131
131
  * ② SLOTS — a product may redefine these.
132
132
  *
133
- * Every design value a component uses comes from here, and every slot's default points
134
- * back at the scale above. That split is the whole idea: a product decides **which step
135
- * a part uses**, and cannot invent a step. Change `--spacing-x-slot-card-pad` to
136
- * `var(--spacing-x-lg)` and cards get roomier everywhere; you still cannot write `2.25`.
133
+ * Every design value a component takes **from the theme** comes from here, and every slot's
134
+ * default points back at the scale above. That split is the whole idea: a product decides
135
+ * **which step a part uses**, and cannot invent a step. Change `--spacing-x-slot-modal-pad`
136
+ * to `var(--spacing-x-lg)` and every modal gets roomier; you still cannot write `2.25`.
137
+ *
138
+ * 🔴 The layout components (`Box`, `Card`, `Stack`, `Section`, `Grid`) are the exception:
139
+ * their padding and gap come from **props**, not from slots, because the caller decides
140
+ * them per instance. There is no `--spacing-x-slot-card-pad` — setting one does nothing,
141
+ * silently. See README §② (#389).
137
142
  *
138
143
  * Named per component rather than per role (hide's ruling, 2026-08-23): sharing one slot
139
144
  * between `Modal` and `Card` can be arranged later by pointing both at the same value,
@@ -173,6 +178,8 @@
173
178
  --spacing-x-slot-detail-row-pad-y: var(--spacing-x-xs);
174
179
  --spacing-x-slot-state-pad-y: var(--spacing-x-xl);
175
180
  --spacing-x-slot-state-action-pad-y: var(--spacing-x-xs);
181
+ /* Between an EmptyState's two lines (#456). Only read when `description` is passed. */
182
+ --spacing-x-slot-empty-state-gap: var(--spacing-x-3xs);
176
183
  --spacing-x-slot-page-header-pad-y: var(--spacing-x-md);
177
184
 
178
185
  --radius-x-slot-button: var(--radius-x-md);
@@ -273,6 +280,13 @@
273
280
  --color-x-slot-button-secondary-border: var(--color-border);
274
281
  --color-x-slot-button-danger-bg: var(--color-danger);
275
282
  --color-x-slot-button-danger-fg: var(--color-on-accent);
283
+ /* 🔴 Defaults to the fill, so a filled danger button looks exactly as it did: the border
284
+ * and the background are the same colour, which is what `border-transparent` over a filled
285
+ * background already rendered. The slot exists for the ships whose danger button is an
286
+ * outline rather than a fill — nene-deal's is `background: transparent` with a tinted
287
+ * border (#455), and it could not express that: the variant emitted no border class at
288
+ * all, so `border-transparent` from BASE_CLASS won and no slot value could reach it. */
289
+ --color-x-slot-button-danger-border: var(--color-danger);
276
290
  --color-x-slot-button-ghost-fg: var(--color-text-primary);
277
291
 
278
292
  /* Shared by Input, Select and Textarea — they are one control with three shapes, and a
@@ -336,6 +350,13 @@
336
350
  --color-x-slot-toast-border: var(--color-border);
337
351
  --color-x-slot-toast-danger-fg: var(--color-danger);
338
352
  --color-x-slot-toast-danger-border: var(--color-danger);
353
+ /* `success` tone (#457). Badge and InlineAlert already carry this meaning; the toast is
354
+ * the one surface that had only two. */
355
+ --color-x-slot-toast-success-fg: var(--color-success);
356
+ --color-x-slot-toast-success-border: var(--color-success);
357
+ /* The toast's second line (#457). Only read when `description` is passed. */
358
+ --color-x-slot-toast-description-fg: var(--color-text-muted);
359
+ --spacing-x-slot-toast-description-gap: var(--spacing-x-3xs);
339
360
 
340
361
  --color-x-slot-card-bg: var(--color-surface-raised);
341
362
  --color-x-slot-card-border: var(--color-border);
@@ -361,6 +382,10 @@
361
382
  --color-x-slot-text-muted-fg: var(--color-text-muted);
362
383
  --color-x-slot-spinner-fg: var(--color-text-muted);
363
384
  --color-x-slot-empty-state-fg: var(--color-text-muted);
385
+ /* The second line of an EmptyState (#456). Same value as the first by default, so a ship
386
+ * that adopts `description` gets one uniform block until it decides otherwise; a ship that
387
+ * wants the hierarchy overrides one of the two. No existing render reads this. */
388
+ --color-x-slot-empty-state-description-fg: var(--color-text-muted);
364
389
  --color-x-slot-error-state-fg: var(--color-danger);
365
390
  /* 🔴 The required marker, not the error message — that one is `--color-x-slot-field-error`.
366
391
  * Named `-error-fg` when the colour slots were swept in (0.9.0, same day), which reads as