@bysages/react 0.0.1 → 0.1.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/dist/index.mjs CHANGED
@@ -1,32 +1,42 @@
1
1
  import { injectComponentStyle } from "@bysages/core";
2
2
  import { Accordion as Accordion$1 } from "@ark-ui/react/accordion";
3
- import { renderHtml } from "@tanstack/markdown/html";
4
- import { Children, cloneElement, createContext, isValidElement, useContext, useEffect, useLayoutEffect, useMemo, useReducer, useRef } from "react";
5
3
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
4
+ import { Children, cloneElement, createContext, isValidElement, useContext, useEffect, useId, useImperativeHandle, useLayoutEffect, useMemo, useReducer, useRef, useState } from "react";
5
+ import { Field as Field$1, useFieldContext } from "@ark-ui/react/field";
6
+ import { Popover as Popover$1 } from "@ark-ui/react/popover";
7
+ import { Portal } from "@ark-ui/react/portal";
6
8
  import { Collapsible as Collapsible$1 } from "@ark-ui/react/collapsible";
7
- import { Field as Field$1 } from "@ark-ui/react/field";
9
+ import { renderHtml } from "@tanstack/markdown/html";
8
10
  import { AngleSlider as AngleSlider$1 } from "@ark-ui/react/angle-slider";
11
+ import { createFileTreeCollection, createGridCollection, createTreeCollection, useAsyncList, useListCollection, useListCollection as useListCollection$1, useListSelection } from "@ark-ui/react/collection";
12
+ import { Combobox as Combobox$1 } from "@ark-ui/react/combobox";
9
13
  import { Avatar as Avatar$1 } from "@ark-ui/react/avatar";
10
14
  import { DatePicker as DatePicker$1 } from "@ark-ui/react/date-picker";
15
+ import { useEnvironmentContext } from "@ark-ui/react/environment";
16
+ import { useLocaleContext } from "@ark-ui/react/locale";
17
+ import * as cascade from "@zag-js/cascade-select";
18
+ import { normalizeProps, useMachine } from "@zag-js/react";
11
19
  import { Carousel as Carousel$1 } from "@ark-ui/react/carousel";
12
20
  import { Checkbox as Checkbox$1 } from "@ark-ui/react/checkbox";
13
21
  import { Clipboard as Clipboard$1 } from "@ark-ui/react/clipboard";
22
+ import { ClientOnly } from "@ark-ui/react/client-only";
14
23
  import { ColorPicker as ColorPicker$1 } from "@ark-ui/react/color-picker";
15
- import { Combobox as Combobox$1 } from "@ark-ui/react/combobox";
16
- import { DateInput as DateInput$1 } from "@ark-ui/react/date-input";
17
24
  import { Dialog as Dialog$1 } from "@ark-ui/react/dialog";
25
+ import { DateInput as DateInput$1 } from "@ark-ui/react/date-input";
26
+ import { DownloadTrigger, useDownload } from "@ark-ui/react/download-trigger";
18
27
  import { Drawer as Drawer$1 } from "@ark-ui/react/drawer";
19
28
  import { Editable as Editable$1 } from "@ark-ui/react/editable";
20
29
  import { Fieldset as Fieldset$1 } from "@ark-ui/react/fieldset";
21
30
  import { FileUpload as FileUpload$1 } from "@ark-ui/react/file-upload";
22
31
  import { FloatingPanel as FloatingPanel$1 } from "@ark-ui/react/floating-panel";
32
+ import { FocusTrap } from "@ark-ui/react/focus-trap";
23
33
  import { Format as Format$1 } from "@ark-ui/react/format";
24
34
  import { Frame as Frame$1 } from "@ark-ui/react/frame";
25
35
  import { Highlight as Highlight$1 } from "@ark-ui/react/highlight";
26
36
  import { HoverCard as HoverCard$1 } from "@ark-ui/react/hover-card";
27
37
  import { ImageCropper as ImageCropper$1 } from "@ark-ui/react/image-cropper";
28
38
  import { JsonTreeView as JsonTreeView$1 } from "@ark-ui/react/json-tree-view";
29
- import { Listbox as Listbox$1, createListCollection } from "@ark-ui/react/listbox";
39
+ import { Listbox as Listbox$1 } from "@ark-ui/react/listbox";
30
40
  import { Marquee as Marquee$1 } from "@ark-ui/react/marquee";
31
41
  import { Menu as Menu$1 } from "@ark-ui/react/menu";
32
42
  import { NavigationMenu as NavigationMenu$1 } from "@ark-ui/react/navigation-menu";
@@ -34,7 +44,7 @@ import { NumberInput as NumberInput$1 } from "@ark-ui/react/number-input";
34
44
  import { Pagination as Pagination$1 } from "@ark-ui/react/pagination";
35
45
  import { PasswordInput as PasswordInput$1 } from "@ark-ui/react/password-input";
36
46
  import { PinInput as PinInput$1 } from "@ark-ui/react/pin-input";
37
- import { Popover as Popover$1 } from "@ark-ui/react/popover";
47
+ import { Presence, PresenceProvider, usePresence, usePresenceContext } from "@ark-ui/react/presence";
38
48
  import { Progress as Progress$1 } from "@ark-ui/react/progress";
39
49
  import { QrCode as QrCode$1 } from "@ark-ui/react/qr-code";
40
50
  import { RadioGroup as RadioGroup$1 } from "@ark-ui/react/radio-group";
@@ -59,7 +69,7 @@ import { Toggle as Toggle$1 } from "@ark-ui/react/toggle";
59
69
  import { ToggleGroup as ToggleGroup$1 } from "@ark-ui/react/toggle-group";
60
70
  import { Tooltip as Tooltip$1 } from "@ark-ui/react/tooltip";
61
71
  import { Tour as Tour$1, useTour } from "@ark-ui/react/tour";
62
- import { TreeView as TreeView$1 } from "@ark-ui/react/tree-view";
72
+ import { TreeView as TreeView$1, createTreeCollection as createTreeCollection$1 } from "@ark-ui/react/tree-view";
63
73
  export * from "@bysages/core";
64
74
  //#region src/components/accordion/index.tsx
65
75
  /** Ark's Accordion, dressed in the paper-and-ink system: a ruled sheet
@@ -68,6 +78,21 @@ export * from "@bysages/core";
68
78
  const Accordion = Accordion$1;
69
79
  injectComponentStyle("accordion");
70
80
  //#endregion
81
+ //#region src/components/affix/index.tsx
82
+ function Affix({ offsetTop = "0px", offsetBottom = "0px", ...rest }) {
83
+ return /* @__PURE__ */ jsx("div", {
84
+ ...rest,
85
+ style: {
86
+ ...rest.style,
87
+ top: offsetTop,
88
+ bottom: offsetBottom
89
+ },
90
+ "data-scope": "affix",
91
+ "data-part": "root"
92
+ });
93
+ }
94
+ injectComponentStyle("affix");
95
+ //#endregion
71
96
  //#region src/components/button/index.tsx
72
97
  function Button({ variant = "solid", tone = "ink", size = "md", square = false, asChild = false, disabled = false, type = "button", children, ...rest }) {
73
98
  const partProps = {
@@ -93,12 +118,31 @@ function Button({ variant = "solid", tone = "ink", size = "md", square = false,
93
118
  }
94
119
  injectComponentStyle("button");
95
120
  //#endregion
96
- //#region src/components/collapsible/index.tsx
97
- /** Ark's Collapsible, dressed in the paper-and-ink system: one control on
98
- * the paper, its panel dissolving open to the machine's measured height.
99
- * The API is Ark's own — Root, Trigger, Content, Indicator. */
100
- const Collapsible = Collapsible$1;
101
- injectComponentStyle("collapsible");
121
+ //#region src/components/ai-action/index.tsx
122
+ function Action({ label, children, ...rest }) {
123
+ return /* @__PURE__ */ jsx(Button, {
124
+ variant: "ghost",
125
+ size: "sm",
126
+ square: true,
127
+ "aria-label": label,
128
+ title: label,
129
+ ...rest,
130
+ children
131
+ });
132
+ }
133
+ injectComponentStyle("ai");
134
+ //#endregion
135
+ //#region src/components/ai-message/index.tsx
136
+ function Message({ role = "assistant", children, ...rest }) {
137
+ return /* @__PURE__ */ jsx("article", {
138
+ ...rest,
139
+ "data-scope": "ai",
140
+ "data-part": "message",
141
+ "data-role": role,
142
+ children
143
+ });
144
+ }
145
+ injectComponentStyle("ai");
102
146
  //#endregion
103
147
  //#region src/components/field/index.tsx
104
148
  /** Ark's Field, dressed in the paper-and-ink system: a tracked label, a
@@ -108,38 +152,308 @@ injectComponentStyle("collapsible");
108
152
  const Field = Field$1;
109
153
  injectComponentStyle("field");
110
154
  //#endregion
111
- //#region src/components/ai/index.tsx
112
- /** A conversation column: Root is the log, Message carries a role, and
113
- * the speaking parts — Response, Reasoning, Tool, Sources — part the
114
- * stream. The interactive folds are the shared Collapsible wearing a
115
- * `data-ai` marker, so the machine work is never ours. Parts stay
116
- * agnostic of any client; consumers map their message format (e.g. the
117
- * `UIMessage` parts re-exported below) onto these primitives. */
118
- function part$9(name, tag, extra = {}) {
119
- const Tag = tag;
120
- const Component = ({ children, ...rest }) => /* @__PURE__ */ jsx(Tag, {
121
- ...extra,
155
+ //#region src/components/mentions/use-mentions.ts
156
+ /** The @-detection machinery behind a mention field: watch the caret,
157
+ * offer the matching candidates, and answer for the keys that drive
158
+ * them. The field element arrives as a getter because hosts wrap it
159
+ * differently (a bare textarea, a field part's ref).
160
+ *
161
+ * `onKeydown` answers whether the vessel consumed the key, so a host
162
+ * with its own Enter semantics — a composer that sends — can yield to
163
+ * the candidates first and act only when the vessel stands down. */
164
+ function useMentions(options, textarea, handlers) {
165
+ const [popupOpen, setPopupOpen] = useState(false);
166
+ const [matches, setMatches] = useState([]);
167
+ const [active, setActive] = useState(0);
168
+ const anchorIndex = useRef(0);
169
+ const caretIndex = useRef(0);
170
+ const resolve = () => typeof options === "function" ? options() : options;
171
+ const closePopup = () => {
172
+ setPopupOpen(false);
173
+ setMatches([]);
174
+ };
175
+ const detect = () => {
176
+ const text = handlers.getText();
177
+ const caret = textarea()?.selectionStart ?? text.length;
178
+ caretIndex.current = caret;
179
+ const head = text.slice(0, caret);
180
+ const char = resolve().trigger ?? "@";
181
+ const anchor = head.lastIndexOf(char);
182
+ const token = anchor === -1 ? "" : head.slice(anchor + char.length);
183
+ if (anchor === -1 || /\s/.test(token)) {
184
+ closePopup();
185
+ return;
186
+ }
187
+ const found = resolve().items.filter((entry) => entry.label.toLowerCase().startsWith(token.toLowerCase()));
188
+ setMatches(found);
189
+ setActive(0);
190
+ anchorIndex.current = anchor;
191
+ setPopupOpen(found.length > 0);
192
+ };
193
+ const insert = (entry) => {
194
+ const text = handlers.getText();
195
+ const char = resolve().trigger ?? "@";
196
+ const next = text.slice(0, anchorIndex.current) + char + entry.label + " " + text.slice(caretIndex.current);
197
+ handlers.setText(next);
198
+ closePopup();
199
+ setTimeout(() => {
200
+ const el = textarea();
201
+ if (!el) return;
202
+ const caret = anchorIndex.current + char.length + entry.label.length + 1;
203
+ el.focus();
204
+ el.setSelectionRange(caret, caret);
205
+ }, 0);
206
+ };
207
+ /** Feed the field's input events through here — the vessel watches
208
+ * the text as it lands, from the element itself. */
209
+ const onInput = () => detect();
210
+ /** Arrows move, Enter inserts, Escape dismisses. Answers `true` when
211
+ * the vessel consumed the key. */
212
+ const onKeydown = (event) => {
213
+ if (!popupOpen || matches.length === 0) return false;
214
+ if (event.key === "ArrowDown") {
215
+ event.preventDefault();
216
+ setActive((current) => (current + 1) % matches.length);
217
+ } else if (event.key === "ArrowUp") {
218
+ event.preventDefault();
219
+ setActive((current) => (current - 1 + matches.length) % matches.length);
220
+ } else if (event.key === "Enter") {
221
+ event.preventDefault();
222
+ insert(matches[active]);
223
+ } else if (event.key === "Escape") closePopup();
224
+ else return false;
225
+ return true;
226
+ };
227
+ return {
228
+ open: popupOpen,
229
+ matches,
230
+ active,
231
+ setActive,
232
+ insert,
233
+ close: closePopup,
234
+ onInput,
235
+ onKeydown
236
+ };
237
+ }
238
+ //#endregion
239
+ //#region src/components/mentions/index.tsx
240
+ /** The vessel: the candidates themselves as a floating card. The anchor
241
+ * is virtual — a live rectangle off the host's field — so a host keeps
242
+ * its own anatomy (the textarea rides where the host puts it) and the
243
+ * vessel still points at the right place. Shares the detection state
244
+ * with the host through `useMentions`. */
245
+ function MentionsVessel({ open = false, matches = [], active = 0, anchor = null, onInsert, onActiveChange, onOpenChange }) {
246
+ return /* @__PURE__ */ jsx(Popover$1.Root, {
247
+ open,
248
+ onOpenChange: (details) => onOpenChange?.(details.open),
249
+ positioning: {
250
+ placement: "bottom-start",
251
+ getAnchorRect: () => anchor?.getBoundingClientRect() ?? null
252
+ },
253
+ children: /* @__PURE__ */ jsx(Portal, { children: /* @__PURE__ */ jsx(Popover$1.Positioner, { children: /* @__PURE__ */ jsx(Popover$1.Content, {
254
+ asChild: true,
255
+ children: /* @__PURE__ */ jsx("div", {
256
+ "data-scope": "mentions",
257
+ "data-part": "popup",
258
+ children: matches.map((entry, index) => /* @__PURE__ */ jsx("div", {
259
+ "data-scope": "mentions",
260
+ "data-part": "option",
261
+ "data-active": index === active ? "" : void 0,
262
+ onMouseEnter: () => onActiveChange?.(index),
263
+ onMouseDown: (event) => event.preventDefault(),
264
+ onClick: () => onInsert?.(entry),
265
+ children: entry.label
266
+ }, entry.value))
267
+ })
268
+ }) }) })
269
+ });
270
+ }
271
+ function Mentions({ items = [], value, trigger = "@", placeholder, autoresize = false, invalid = false, onValueChange, children, ...rest }) {
272
+ const [internal, setInternal] = useState("");
273
+ const fieldRef = useRef(null);
274
+ const el = () => fieldRef.current;
275
+ const current = value ?? internal;
276
+ const mentions = useMentions({
277
+ items,
278
+ trigger
279
+ }, el, {
280
+ getText: () => el()?.value ?? current,
281
+ setText: (next) => {
282
+ setInternal(next);
283
+ onValueChange?.(next);
284
+ }
285
+ });
286
+ const handleChange = (event) => {
287
+ const node = event.currentTarget;
288
+ setInternal(node.value);
289
+ onValueChange?.(node.value);
290
+ mentions.onInput();
291
+ };
292
+ return /* @__PURE__ */ jsxs("div", {
122
293
  ...rest,
123
- "data-scope": "ai",
124
- "data-part": name.toLowerCase(),
125
- children
294
+ "data-scope": "mentions",
295
+ "data-part": "root",
296
+ children: [
297
+ /* @__PURE__ */ jsx(Field.Textarea, {
298
+ ref: fieldRef,
299
+ autoresize,
300
+ rows: 3,
301
+ placeholder,
302
+ value: current,
303
+ onChange: handleChange,
304
+ onKeyDown: (event) => mentions.onKeydown(event),
305
+ "data-invalid": invalid || void 0,
306
+ "data-scope": "mentions",
307
+ "data-part": "textarea"
308
+ }),
309
+ /* @__PURE__ */ jsx(MentionsVessel, {
310
+ open: mentions.open,
311
+ matches: mentions.matches,
312
+ active: mentions.active,
313
+ anchor: el(),
314
+ onInsert: mentions.insert,
315
+ onActiveChange: mentions.setActive,
316
+ onOpenChange: (open) => {
317
+ if (!open) mentions.close();
318
+ }
319
+ }),
320
+ children
321
+ ]
126
322
  });
127
- Component.displayName = "Ai" + name;
128
- return Component;
129
323
  }
130
- const Conversation = part$9("Conversation", "div", {
131
- role: "log",
132
- "aria-label": "Conversation"
324
+ injectComponentStyle("mentions");
325
+ //#endregion
326
+ //#region src/components/ai-prompt-input/index.tsx
327
+ const arrowUpGlyph = /* @__PURE__ */ jsx("svg", {
328
+ viewBox: "0 0 16 16",
329
+ width: 14,
330
+ height: 14,
331
+ "aria-hidden": "true",
332
+ fill: "none",
333
+ stroke: "currentColor",
334
+ strokeWidth: 1.5,
335
+ strokeLinecap: "square",
336
+ children: /* @__PURE__ */ jsx("path", { d: "M8 13V3M3.5 7.5 8 3l4.5 4.5" })
133
337
  });
134
- const MessageContent = part$9("Content", "div");
135
- const Sources = part$9("Sources", "ol");
136
- const Actions$3 = part$9("Actions", "div");
137
- const Loader = part$9("Loader", "span", {
138
- role: "status",
139
- "aria-label": "Loading"
338
+ const stopGlyph = /* @__PURE__ */ jsx("svg", {
339
+ viewBox: "0 0 16 16",
340
+ width: 14,
341
+ height: 14,
342
+ "aria-hidden": "true",
343
+ children: /* @__PURE__ */ jsx("rect", {
344
+ x: 4.5,
345
+ y: 4.5,
346
+ width: 7,
347
+ height: 7,
348
+ fill: "currentColor"
349
+ })
140
350
  });
351
+ /** An empty slot leaves no part in the anatomy — the bare vessel keeps
352
+ * its single-line posture. */
353
+ function row(part, content) {
354
+ if (content == null || Array.isArray(content) && content.length === 0) return null;
355
+ return /* @__PURE__ */ jsx("div", {
356
+ "data-scope": "ai",
357
+ "data-part": part,
358
+ children: content
359
+ });
360
+ }
361
+ function PromptInput({ value, onValueChange, onSubmit, onStop, placeholder = "Send a message", disabled = false, busy = false, mentions, header, leading, trailing, footer, footerEnd, ...rest }) {
362
+ const fieldRef = useRef(null);
363
+ const mentionState = useMentions(() => ({
364
+ items: mentions?.items ?? [],
365
+ trigger: mentions?.trigger
366
+ }), () => fieldRef.current, {
367
+ getText: () => fieldRef.current?.value ?? value,
368
+ setText: (next) => onValueChange?.(next)
369
+ });
370
+ const mentionsActive = mentions != null;
371
+ const submit = () => {
372
+ const text = value.trim();
373
+ if (!text || disabled || busy) return;
374
+ onSubmit?.(text);
375
+ onValueChange?.("");
376
+ };
377
+ const seal = busy ? /* @__PURE__ */ jsx(Button, {
378
+ variant: "solid",
379
+ size: "sm",
380
+ square: true,
381
+ type: "button",
382
+ "aria-label": "Stop",
383
+ disabled,
384
+ onClick: () => onStop?.(),
385
+ children: stopGlyph
386
+ }) : /* @__PURE__ */ jsx(Button, {
387
+ variant: "solid",
388
+ size: "sm",
389
+ square: true,
390
+ type: "submit",
391
+ "aria-label": "Send",
392
+ disabled: disabled || !value.trim(),
393
+ children: arrowUpGlyph
394
+ });
395
+ const hasFooter = footer != null && (!Array.isArray(footer) || footer.length > 0);
396
+ return /* @__PURE__ */ jsxs("form", {
397
+ ...rest,
398
+ "data-scope": "ai",
399
+ "data-part": "prompt",
400
+ onSubmit: (event) => {
401
+ event.preventDefault();
402
+ submit();
403
+ },
404
+ children: [
405
+ row("prompt-header", header),
406
+ /* @__PURE__ */ jsxs("div", {
407
+ "data-scope": "ai",
408
+ "data-part": "prompt-main",
409
+ children: [
410
+ row("prompt-leading", leading),
411
+ /* @__PURE__ */ jsx(Field.Root, { children: /* @__PURE__ */ jsx(Field.Textarea, {
412
+ ref: fieldRef,
413
+ autoresize: true,
414
+ rows: 1,
415
+ value,
416
+ placeholder,
417
+ disabled,
418
+ onChange: (event) => {
419
+ onValueChange?.(event.target.value);
420
+ mentionState.onInput();
421
+ },
422
+ onKeyDown: (event) => {
423
+ if (mentionState.onKeydown(event)) return;
424
+ if (event.key === "Enter" && !event.shiftKey) {
425
+ event.preventDefault();
426
+ submit();
427
+ }
428
+ }
429
+ }) }),
430
+ mentionsActive ? /* @__PURE__ */ jsx(MentionsVessel, {
431
+ open: mentionState.open,
432
+ matches: mentionState.matches,
433
+ active: mentionState.active,
434
+ anchor: fieldRef.current,
435
+ onInsert: mentionState.insert,
436
+ onActiveChange: mentionState.setActive,
437
+ onOpenChange: (open) => {
438
+ if (!open) mentionState.close();
439
+ }
440
+ }) : null,
441
+ row("prompt-trailing", hasFooter ? trailing : trailing ?? seal)
442
+ ]
443
+ }),
444
+ hasFooter ? /* @__PURE__ */ jsxs("div", {
445
+ "data-scope": "ai",
446
+ "data-part": "prompt-footer",
447
+ children: [footer, row("prompt-end", footerEnd == null ? seal : /* @__PURE__ */ jsxs(Fragment, { children: [footerEnd, seal] }))]
448
+ }) : null
449
+ ]
450
+ });
451
+ }
452
+ injectComponentStyle("ai");
453
+ //#endregion
454
+ //#region src/components/ai/chevron.tsx
141
455
  /** The folding chevron the shared indicator turns. */
142
- const chevron$1 = /* @__PURE__ */ jsx("svg", {
456
+ const chevron$2 = /* @__PURE__ */ jsx("svg", {
143
457
  viewBox: "0 0 16 16",
144
458
  fill: "none",
145
459
  "aria-hidden": "true",
@@ -151,62 +465,40 @@ const chevron$1 = /* @__PURE__ */ jsx("svg", {
151
465
  strokeLinejoin: "round"
152
466
  })
153
467
  });
154
- function Message({ role = "assistant", children, ...rest }) {
155
- return /* @__PURE__ */ jsx("article", {
156
- ...rest,
157
- "data-scope": "ai",
158
- "data-part": "message",
159
- "data-role": role,
160
- children
161
- });
162
- }
163
- function Response({ content, ...rest }) {
164
- return /* @__PURE__ */ jsx("div", {
165
- ...rest,
166
- "data-scope": "ai",
167
- "data-part": "response",
168
- dangerouslySetInnerHTML: { __html: renderHtml(content) }
169
- });
170
- }
468
+ //#endregion
469
+ //#region src/components/collapsible/index.tsx
470
+ /** Ark's Collapsible, dressed in the paper-and-ink system: one control on
471
+ * the paper, its panel dissolving open to the machine's measured height.
472
+ * The API is Ark's own — Root, Trigger, Content, Indicator. */
473
+ const Collapsible = Collapsible$1;
474
+ injectComponentStyle("collapsible");
475
+ //#endregion
476
+ //#region src/components/ai-reasoning/index.tsx
171
477
  function Reasoning({ label = "Thinking", children, ...rest }) {
172
478
  return /* @__PURE__ */ jsxs(Collapsible.Root, {
173
479
  ...rest,
174
480
  "data-ai": "reasoning",
175
- children: [/* @__PURE__ */ jsxs(Collapsible.Trigger, { children: [/* @__PURE__ */ jsx("span", { children: label }), /* @__PURE__ */ jsx(Collapsible.Indicator, { children: chevron$1 })] }), /* @__PURE__ */ jsx(Collapsible.Content, { children: /* @__PURE__ */ jsx("div", {
481
+ children: [/* @__PURE__ */ jsxs(Collapsible.Trigger, { children: [/* @__PURE__ */ jsx("span", { children: label }), /* @__PURE__ */ jsx(Collapsible.Indicator, { children: chevron$2 })] }), /* @__PURE__ */ jsx(Collapsible.Content, { children: /* @__PURE__ */ jsx("div", {
176
482
  "data-scope": "ai",
177
483
  "data-part": "reasoning-content",
178
484
  children
179
485
  }) })]
180
486
  });
181
487
  }
182
- function Tool({ name, label, status, input, output, ...rest }) {
183
- return /* @__PURE__ */ jsxs(Collapsible.Root, {
488
+ injectComponentStyle("ai");
489
+ //#endregion
490
+ //#region src/components/ai-response/index.tsx
491
+ function Response({ content, highlighter, ...rest }) {
492
+ return /* @__PURE__ */ jsx("div", {
184
493
  ...rest,
185
- "data-ai": "tool",
186
- "data-status": status,
187
- children: [/* @__PURE__ */ jsxs(Collapsible.Trigger, { children: [
188
- /* @__PURE__ */ jsx("span", { children: label ?? name }),
189
- status ? /* @__PURE__ */ jsx("span", {
190
- "data-scope": "ai",
191
- "data-part": "tool-status",
192
- children: status.charAt(0).toUpperCase() + status.slice(1)
193
- }) : null,
194
- /* @__PURE__ */ jsx(Collapsible.Indicator, { children: chevron$1 })
195
- ] }), /* @__PURE__ */ jsx(Collapsible.Content, { children: /* @__PURE__ */ jsxs("div", {
196
- "data-scope": "ai",
197
- "data-part": "tool-body",
198
- children: [input ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", {
199
- "data-scope": "ai",
200
- "data-part": "tool-label",
201
- children: "Input"
202
- }), /* @__PURE__ */ jsx("pre", { children: input })] }) : null, output ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", {
203
- "data-scope": "ai",
204
- "data-part": "tool-label",
205
- children: "Output"
206
- }), /* @__PURE__ */ jsx("pre", { children: output })] }) : null]
207
- }) })]
494
+ "data-scope": "ai",
495
+ "data-part": "response",
496
+ dangerouslySetInnerHTML: { __html: renderHtml(content, highlighter ? { highlighter } : void 0) }
208
497
  });
209
498
  }
499
+ injectComponentStyle("ai");
500
+ //#endregion
501
+ //#region src/components/ai-source/index.tsx
210
502
  function Source({ href, children, ...rest }) {
211
503
  return /* @__PURE__ */ jsx("li", {
212
504
  "data-scope": "ai",
@@ -220,17 +512,17 @@ function Source({ href, children, ...rest }) {
220
512
  })
221
513
  });
222
514
  }
223
- function Action({ label, children, ...rest }) {
224
- return /* @__PURE__ */ jsx(Button, {
225
- variant: "ghost",
226
- size: "sm",
227
- square: true,
228
- "aria-label": label,
229
- title: label,
515
+ function Sources({ children, ...rest }) {
516
+ return /* @__PURE__ */ jsx("ol", {
230
517
  ...rest,
518
+ "data-scope": "ai",
519
+ "data-part": "sources",
231
520
  children
232
521
  });
233
522
  }
523
+ injectComponentStyle("ai");
524
+ //#endregion
525
+ //#region src/components/ai-suggestion/index.tsx
234
526
  function Suggestion({ prompt, onSelect, ...rest }) {
235
527
  return /* @__PURE__ */ jsx(Button, {
236
528
  variant: "outline",
@@ -240,74 +532,194 @@ function Suggestion({ prompt, onSelect, ...rest }) {
240
532
  children: prompt
241
533
  });
242
534
  }
243
- function PromptInput({ value, onValueChange, onSubmit, placeholder = "Send a message", disabled = false, ...rest }) {
244
- const send = () => {
245
- const text = value.trim();
246
- if (!text || disabled) return;
247
- onSubmit?.(text);
248
- onValueChange?.("");
249
- };
250
- return /* @__PURE__ */ jsxs("form", {
535
+ injectComponentStyle("ai");
536
+ //#endregion
537
+ //#region src/components/ai-tool/index.tsx
538
+ function Tool({ name, label, status, input, output, ...rest }) {
539
+ return /* @__PURE__ */ jsxs(Collapsible.Root, {
251
540
  ...rest,
252
- "data-scope": "ai",
253
- "data-part": "prompt",
254
- onSubmit: (event) => {
255
- event.preventDefault();
256
- send();
257
- },
258
- children: [/* @__PURE__ */ jsx(Field.Root, { children: /* @__PURE__ */ jsx(Field.Textarea, {
259
- autoresize: true,
260
- rows: 1,
261
- value,
262
- placeholder,
263
- disabled,
264
- onChange: (event) => onValueChange?.(event.target.value),
265
- onKeyDown: (event) => {
266
- if (event.key === "Enter" && !event.shiftKey) {
267
- event.preventDefault();
268
- send();
269
- }
270
- }
271
- }) }), /* @__PURE__ */ jsx("div", {
541
+ "data-ai": "tool",
542
+ "data-status": status,
543
+ children: [/* @__PURE__ */ jsxs(Collapsible.Trigger, { children: [
544
+ /* @__PURE__ */ jsx("span", { children: label ?? name }),
545
+ status ? /* @__PURE__ */ jsx("span", {
546
+ "data-scope": "ai",
547
+ "data-part": "tool-status",
548
+ children: status.charAt(0).toUpperCase() + status.slice(1)
549
+ }) : null,
550
+ /* @__PURE__ */ jsx(Collapsible.Indicator, { children: chevron$2 })
551
+ ] }), /* @__PURE__ */ jsx(Collapsible.Content, { children: /* @__PURE__ */ jsxs("div", {
272
552
  "data-scope": "ai",
273
- "data-part": "prompt-footer",
274
- children: /* @__PURE__ */ jsx(Button, {
275
- variant: "solid",
276
- size: "sm",
277
- square: true,
278
- type: "submit",
279
- "aria-label": "Send",
280
- disabled: disabled || !value.trim(),
281
- children: /* @__PURE__ */ jsx("svg", {
282
- viewBox: "0 0 16 16",
283
- width: 14,
284
- height: 14,
285
- "aria-hidden": "true",
286
- fill: "none",
287
- stroke: "currentColor",
288
- strokeWidth: 1.5,
289
- strokeLinecap: "square",
290
- children: /* @__PURE__ */ jsx("path", { d: "M8 13V3M3.5 7.5 8 3l4.5 4.5" })
291
- })
292
- })
293
- })]
553
+ "data-part": "tool-body",
554
+ children: [input ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", {
555
+ "data-scope": "ai",
556
+ "data-part": "tool-label",
557
+ children: "Input"
558
+ }), /* @__PURE__ */ jsx("pre", { children: input })] }) : null, output ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", {
559
+ "data-scope": "ai",
560
+ "data-part": "tool-label",
561
+ children: "Output"
562
+ }), /* @__PURE__ */ jsx("pre", { children: output })] }) : null]
563
+ }) })]
564
+ });
565
+ }
566
+ injectComponentStyle("ai");
567
+ //#endregion
568
+ //#region src/components/ai/index.tsx
569
+ /** A conversation column: Root is the log, Message carries a role, and
570
+ * the speaking parts — Response, Reasoning, Tool, Sources — part the
571
+ * stream. The interactive folds are the shared Collapsible wearing a
572
+ * `data-ai` marker, so the machine work is never ours. Parts stay
573
+ * agnostic of any client; consumers map their message format (e.g. the
574
+ * `UIMessage` parts re-exported here) onto these primitives. */
575
+ function part$12(name, tag, extra = {}) {
576
+ const Tag = tag;
577
+ const Component = ({ children, ...rest }) => /* @__PURE__ */ jsx(Tag, {
578
+ ...extra,
579
+ ...rest,
580
+ "data-scope": "ai",
581
+ "data-part": name.toLowerCase(),
582
+ children
294
583
  });
584
+ Component.displayName = "Ai" + name;
585
+ return Component;
295
586
  }
587
+ /** The log itself: the column every stroke lands in, a landmark to
588
+ * screen readers. */
589
+ const Conversation = part$12("Conversation", "div", {
590
+ role: "log",
591
+ "aria-label": "Conversation"
592
+ });
593
+ /** The bubble's inner measure — content that belongs to neither side
594
+ * specifically. */
595
+ const MessageContent = part$12("Content", "div");
596
+ /** The quiet row under a message — copy, retry, feedback. */
597
+ const Actions$4 = part$12("Actions", "div");
598
+ /** The while-it-works whisper for the in-flight turns. */
599
+ const Loader = part$12("Loader", "span", {
600
+ role: "status",
601
+ "aria-label": "Loading"
602
+ });
603
+ /** The whole family under one handle — `Ai.Conversation`,
604
+ * `Ai.Message`, and the rest, exactly as before the split. */
296
605
  const Ai = Object.assign(Conversation, {
297
606
  Conversation,
298
- Message,
299
607
  MessageContent,
608
+ Actions: Actions$4,
609
+ Loader,
610
+ Message,
300
611
  Response,
301
612
  Reasoning,
302
613
  Tool,
303
614
  Sources,
304
615
  Source,
305
- Actions: Actions$3,
306
616
  Action,
307
617
  Suggestion,
308
- PromptInput,
309
- Loader
618
+ PromptInput
619
+ });
620
+ injectComponentStyle("ai");
621
+ //#endregion
622
+ //#region src/components/ai-attachments/index.tsx
623
+ const imageGlyph = /* @__PURE__ */ jsxs("svg", {
624
+ viewBox: "0 0 16 16",
625
+ "aria-hidden": "true",
626
+ fill: "none",
627
+ stroke: "currentColor",
628
+ strokeWidth: 1.5,
629
+ strokeLinecap: "square",
630
+ children: [
631
+ /* @__PURE__ */ jsx("rect", {
632
+ x: 2.5,
633
+ y: 3.5,
634
+ width: 11,
635
+ height: 9
636
+ }),
637
+ /* @__PURE__ */ jsx("path", { d: "M2.5 10.5 6 7l3 3 2-1.5 2.5 2" }),
638
+ /* @__PURE__ */ jsx("circle", {
639
+ cx: 6,
640
+ cy: 6,
641
+ r: .75,
642
+ fill: "currentColor",
643
+ stroke: "none"
644
+ })
645
+ ]
646
+ });
647
+ const fileGlyph = /* @__PURE__ */ jsxs("svg", {
648
+ viewBox: "0 0 16 16",
649
+ "aria-hidden": "true",
650
+ fill: "none",
651
+ stroke: "currentColor",
652
+ strokeWidth: 1.5,
653
+ strokeLinecap: "square",
654
+ children: [/* @__PURE__ */ jsx("path", { d: "M4 2.5h5l3 3V13.5H4z" }), /* @__PURE__ */ jsx("path", { d: "M9 2.5v3h3" })]
655
+ });
656
+ const removeGlyph = /* @__PURE__ */ jsx("svg", {
657
+ viewBox: "0 0 16 16",
658
+ width: 12,
659
+ height: 12,
660
+ "aria-hidden": "true",
661
+ fill: "none",
662
+ stroke: "currentColor",
663
+ strokeWidth: 1.5,
664
+ strokeLinecap: "square",
665
+ children: /* @__PURE__ */ jsx("path", { d: "M4 4l8 8M12 4l-8 8" })
310
666
  });
667
+ const IMAGE_EXTS = [
668
+ "png",
669
+ "jpg",
670
+ "jpeg",
671
+ "gif",
672
+ "webp",
673
+ "svg",
674
+ "avif",
675
+ "bmp",
676
+ "ico"
677
+ ];
678
+ const isImage = (name) => IMAGE_EXTS.includes(name.split(".").pop()?.toLowerCase() ?? "");
679
+ const humanSize = (bytes) => {
680
+ if (bytes < 1024) return `${bytes} B`;
681
+ const units = [
682
+ "KB",
683
+ "MB",
684
+ "GB"
685
+ ];
686
+ let value = bytes;
687
+ let unit = -1;
688
+ do {
689
+ value /= 1024;
690
+ unit += 1;
691
+ } while (value >= 1024 && unit < units.length - 1);
692
+ return `${value.toFixed(1)} ${units[unit]}`;
693
+ };
694
+ function Attachment({ name, size, status = "ready", onRemove, ...rest }) {
695
+ return /* @__PURE__ */ jsxs("span", {
696
+ ...rest,
697
+ "data-scope": "ai",
698
+ "data-part": "attachment",
699
+ "data-status": status,
700
+ children: [
701
+ isImage(name) ? imageGlyph : fileGlyph,
702
+ /* @__PURE__ */ jsx("span", { children: name }),
703
+ size !== void 0 ? /* @__PURE__ */ jsx("span", { children: humanSize(size) }) : null,
704
+ /* @__PURE__ */ jsx("button", {
705
+ type: "button",
706
+ "data-remove": "",
707
+ "aria-label": `Remove ${name}`,
708
+ onClick: () => onRemove?.(),
709
+ children: removeGlyph
710
+ })
711
+ ]
712
+ });
713
+ }
714
+ /** The row the files ride in — a wrapping line of chips. */
715
+ function Attachments({ children, ...rest }) {
716
+ return /* @__PURE__ */ jsx("span", {
717
+ ...rest,
718
+ "data-scope": "ai",
719
+ "data-part": "attachments",
720
+ children
721
+ });
722
+ }
311
723
  injectComponentStyle("ai");
312
724
  //#endregion
313
725
  //#region src/components/alert/index.tsx
@@ -345,7 +757,7 @@ function AlertRoot({ status = "ink", children, ...rest }) {
345
757
  })
346
758
  });
347
759
  }
348
- function Icon$1() {
760
+ function Icon$2() {
349
761
  const status = useContext(StatusContext);
350
762
  return /* @__PURE__ */ jsx("span", {
351
763
  "data-scope": "alert",
@@ -379,7 +791,7 @@ function Description$5({ children, ...rest }) {
379
791
  }
380
792
  const Alert = Object.assign(AlertRoot, {
381
793
  Root: AlertRoot,
382
- Icon: Icon$1,
794
+ Icon: Icon$2,
383
795
  Body: Body$2,
384
796
  Title: Title$4,
385
797
  Description: Description$5
@@ -394,6 +806,48 @@ injectComponentStyle("alert");
394
806
  const AngleSlider = AngleSlider$1;
395
807
  injectComponentStyle("angle-slider");
396
808
  //#endregion
809
+ //#region src/components/aspect-ratio/index.tsx
810
+ function AspectRatio({ ratio = "1 / 1", ...rest }) {
811
+ return /* @__PURE__ */ jsx("div", {
812
+ ...rest,
813
+ style: {
814
+ ...rest.style,
815
+ "--bs-aspect-ratio": ratio
816
+ },
817
+ "data-scope": "aspect-ratio",
818
+ "data-part": "root"
819
+ });
820
+ }
821
+ injectComponentStyle("aspect-ratio");
822
+ //#endregion
823
+ //#region src/components/autocomplete/index.tsx
824
+ function AutoComplete({ value = "", items = [], placeholder, filter, onValueChange, ...rest }) {
825
+ const { collection, filter: filterItems } = useListCollection$1({
826
+ initialItems: items,
827
+ filter: (item, input) => filter ? filter(item, input) : item.toLowerCase().includes(input.toLowerCase())
828
+ });
829
+ return /* @__PURE__ */ jsxs(Combobox$1.Root, {
830
+ ...rest,
831
+ collection,
832
+ inputValue: value,
833
+ allowCustomValue: true,
834
+ onValueChange: (details) => {
835
+ const [first] = details.value;
836
+ if (first != null) onValueChange?.(first);
837
+ },
838
+ onInputValueChange: (details) => {
839
+ filterItems(details.inputValue);
840
+ onValueChange?.(details.inputValue);
841
+ },
842
+ positioning: { sameWidth: true },
843
+ children: [/* @__PURE__ */ jsx(Combobox$1.Control, { children: /* @__PURE__ */ jsx(Combobox$1.Input, { placeholder }) }), /* @__PURE__ */ jsx(Portal, { children: /* @__PURE__ */ jsx(Combobox$1.Positioner, { children: /* @__PURE__ */ jsxs(Combobox$1.Content, { children: [/* @__PURE__ */ jsx(Combobox$1.Empty, { children: "No matches" }), collection.items.map((item) => /* @__PURE__ */ jsx(Combobox$1.Item, {
844
+ item,
845
+ children: /* @__PURE__ */ jsx(Combobox$1.ItemText, { children: item })
846
+ }, item))] }) }) })]
847
+ });
848
+ }
849
+ injectComponentStyle("combobox");
850
+ //#endregion
397
851
  //#region src/components/avatar/index.tsx
398
852
  /** Ark's Avatar, dressed in the paper-and-ink system: a circular seal on
399
853
  * inset paper that holds initials until the image loads over them. The
@@ -410,7 +864,64 @@ function AvatarGroup({ children, ...rest }) {
410
864
  children
411
865
  });
412
866
  }
413
- injectComponentStyle("avatar-group");
867
+ injectComponentStyle("avatar-group");
868
+ //#endregion
869
+ //#region src/components/back-top/index.tsx
870
+ /** The single glyph a way-home control needs: one stroke pointing up. */
871
+ function chevronUp() {
872
+ return /* @__PURE__ */ jsx("svg", {
873
+ width: 16,
874
+ height: 16,
875
+ viewBox: "0 0 24 24",
876
+ fill: "none",
877
+ stroke: "currentColor",
878
+ strokeWidth: 1.75,
879
+ strokeLinecap: "round",
880
+ strokeLinejoin: "round",
881
+ "aria-hidden": "true",
882
+ children: /* @__PURE__ */ jsx("path", { d: "m6 14 6-6 6 6" })
883
+ });
884
+ }
885
+ /**
886
+ * A way home: after the page has scrolled past `threshold`, a small
887
+ * floating control rises at the page's corner and returns the reader to
888
+ * the top. The scroll itself stays native — `window.scrollTo` defers to
889
+ * the stylesheet's `scroll-behavior: smooth`, which reduced motion turns
890
+ * back into an instant jump. The button stays mounted either way so the
891
+ * entrance is a transition, never a pop.
892
+ *
893
+ * The control itself is the shared `Button` (outline, square) — the
894
+ * paper, hairline and halo are its; this family owns only the floating
895
+ * and the entrance.
896
+ */
897
+ function BackTop({ threshold = 400, label = "Back to top", ...rest }) {
898
+ const [visible, setVisible] = useState(false);
899
+ useEffect(() => {
900
+ if (typeof window === "undefined") return;
901
+ const onScroll = () => setVisible(window.scrollY > threshold);
902
+ onScroll();
903
+ window.addEventListener("scroll", onScroll, { passive: true });
904
+ return () => window.removeEventListener("scroll", onScroll);
905
+ }, [threshold]);
906
+ return /* @__PURE__ */ jsx("div", {
907
+ "data-scope": "back-top",
908
+ "data-part": "root",
909
+ "data-state": visible ? "shown" : "hidden",
910
+ children: /* @__PURE__ */ jsx(Button, {
911
+ ...rest,
912
+ variant: "outline",
913
+ square: true,
914
+ size: "lg",
915
+ type: "button",
916
+ "aria-label": label,
917
+ "aria-hidden": visible ? void 0 : "true",
918
+ tabIndex: visible ? 0 : -1,
919
+ onClick: () => window.scrollTo({ top: 0 }),
920
+ children: rest.children ?? chevronUp()
921
+ })
922
+ });
923
+ }
924
+ injectComponentStyle("back-top");
414
925
  //#endregion
415
926
  //#region src/components/badge/index.tsx
416
927
  function Badge({ tone = "ink", variant = "solid", ...rest }) {
@@ -428,7 +939,7 @@ injectComponentStyle("badge");
428
939
  /** A trail of waymarks: Root wraps the nav, List the ordered trail, and
429
940
  * each Item carries a Link — or the Current page — parted by a quiet
430
941
  * Separator. Links take href and the rest through attributes. */
431
- function part$8(name, tag, extra = {}, fallback) {
942
+ function part$11(name, tag, extra = {}, fallback) {
432
943
  const Tag = tag;
433
944
  const Component = ({ children, ...rest }) => /* @__PURE__ */ jsx(Tag, {
434
945
  ...extra,
@@ -440,28 +951,50 @@ function part$8(name, tag, extra = {}, fallback) {
440
951
  Component.displayName = "Breadcrumb" + name;
441
952
  return Component;
442
953
  }
443
- const Root$7 = part$8("Root", "nav", { "aria-label": "Breadcrumb" });
444
- const List = part$8("List", "ol");
445
- const Item$1 = part$8("Item", "li");
446
- const Link$1 = part$8("Link", "a");
447
- const Current = part$8("Current", "span", { "aria-current": "page" });
448
- const Separator$1 = part$8("Separator", "span", { "aria-hidden": "true" }, "/");
449
- const Breadcrumb = Object.assign(Root$7, {
450
- Root: Root$7,
451
- List,
452
- Item: Item$1,
954
+ const Root$12 = part$11("Root", "nav", { "aria-label": "Breadcrumb" });
955
+ const List$1 = part$11("List", "ol");
956
+ const Item$4 = part$11("Item", "li");
957
+ const Link$1 = part$11("Link", "a");
958
+ const Current = part$11("Current", "span", { "aria-current": "page" });
959
+ const Separator$1 = part$11("Separator", "span", { "aria-hidden": "true" }, "/");
960
+ const Breadcrumb = Object.assign(Root$12, {
961
+ Root: Root$12,
962
+ List: List$1,
963
+ Item: Item$4,
453
964
  Link: Link$1,
454
965
  Current,
455
966
  Separator: Separator$1
456
967
  });
457
968
  injectComponentStyle("breadcrumb");
458
969
  //#endregion
970
+ //#region src/components/button-group/index.tsx
971
+ /**
972
+ * Buttons fused into one control: the group owns only the joinery, so
973
+ * members keep every variant they were given — a solid action can sit
974
+ * beside an outline one and the seam still reads. Selection belongs to
975
+ * the toggle group; this is layout alone.
976
+ */
977
+ function Root$11({ orientation = "horizontal", size, radius, children, ...rest }) {
978
+ return /* @__PURE__ */ jsx("div", {
979
+ ...rest,
980
+ role: "group",
981
+ "data-scope": "button-group",
982
+ "data-part": "root",
983
+ "data-orientation": orientation,
984
+ "data-size": size,
985
+ "data-radius": radius,
986
+ children
987
+ });
988
+ }
989
+ const ButtonGroup = Object.assign(Root$11, { Root: Root$11 });
990
+ injectComponentStyle("button-group");
991
+ //#endregion
459
992
  //#region src/components/banner/index.tsx
460
993
  /** A page-level notice, spoken across the full measure: a wash of the
461
994
  * status pigment, one heavier hairline on the leading edge, and room
462
995
  * for actions and a quiet close. Ink is the neutral register; the four
463
996
  * semantic pigments are fixed. */
464
- const Root$6 = ({ status = "ink", children, ...rest }) => /* @__PURE__ */ jsx("div", {
997
+ const Root$10 = ({ status = "ink", children, ...rest }) => /* @__PURE__ */ jsx("div", {
465
998
  ...rest,
466
999
  role: status === "ink" ? void 0 : "status",
467
1000
  "data-scope": "banner",
@@ -469,7 +1002,7 @@ const Root$6 = ({ status = "ink", children, ...rest }) => /* @__PURE__ */ jsx("d
469
1002
  "data-status": status,
470
1003
  children
471
1004
  });
472
- function part$7(name, tag) {
1005
+ function part$10(name, tag) {
473
1006
  const Tag = tag;
474
1007
  const Component = ({ children, ...rest }) => /* @__PURE__ */ jsx(Tag, {
475
1008
  ...rest,
@@ -480,14 +1013,14 @@ function part$7(name, tag) {
480
1013
  Component.displayName = "Banner" + name;
481
1014
  return Component;
482
1015
  }
483
- const Icon = part$7("Icon", "span");
484
- const Body$1 = part$7("Body", "div");
485
- const Title$3 = part$7("Title", "p");
486
- const Description$4 = part$7("Description", "p");
487
- const Actions$2 = part$7("Actions", "div");
1016
+ const Icon$1 = part$10("Icon", "span");
1017
+ const Body$1 = part$10("Body", "div");
1018
+ const Title$3 = part$10("Title", "p");
1019
+ const Description$4 = part$10("Description", "p");
1020
+ const Actions$3 = part$10("Actions", "div");
488
1021
  /** The quiet close: a plain square-cut button; dismissal stays the
489
1022
  * consumer's state. */
490
- const Close = ({ children, ...rest }) => /* @__PURE__ */ jsx("button", {
1023
+ const Close = (rest) => /* @__PURE__ */ jsx("button", {
491
1024
  ...rest,
492
1025
  type: rest.type ?? "button",
493
1026
  "aria-label": rest["aria-label"] ?? "Dismiss",
@@ -505,19 +1038,19 @@ const Close = ({ children, ...rest }) => /* @__PURE__ */ jsx("button", {
505
1038
  })
506
1039
  })
507
1040
  });
508
- const Banner = Object.assign(Root$6, {
509
- Root: Root$6,
510
- Icon,
1041
+ const Banner = Object.assign(Root$10, {
1042
+ Root: Root$10,
1043
+ Icon: Icon$1,
511
1044
  Body: Body$1,
512
1045
  Title: Title$3,
513
1046
  Description: Description$4,
514
- Actions: Actions$2,
1047
+ Actions: Actions$3,
515
1048
  Close
516
1049
  });
517
1050
  injectComponentStyle("banner");
518
1051
  //#endregion
519
1052
  //#region src/components/calendar/index.tsx
520
- function chevron(dir) {
1053
+ function chevron$1(dir) {
521
1054
  return /* @__PURE__ */ jsx("svg", {
522
1055
  width: 16,
523
1056
  height: 16,
@@ -551,9 +1084,9 @@ function Calendar({ value, min, max, onValueChange, children, ...rest }) {
551
1084
  "data-scope": "calendar",
552
1085
  "data-part": "header",
553
1086
  children: /* @__PURE__ */ jsxs(DatePicker$1.ViewControl, { children: [
554
- /* @__PURE__ */ jsx(DatePicker$1.PrevTrigger, { children: chevron("left") }),
1087
+ /* @__PURE__ */ jsx(DatePicker$1.PrevTrigger, { children: chevron$1("left") }),
555
1088
  /* @__PURE__ */ jsx(DatePicker$1.Context, { children: (dp) => /* @__PURE__ */ jsx(DatePicker$1.ViewTrigger, { children: title(dp) }) }),
556
- /* @__PURE__ */ jsx(DatePicker$1.NextTrigger, { children: chevron("right") })
1089
+ /* @__PURE__ */ jsx(DatePicker$1.NextTrigger, { children: chevron$1("right") })
557
1090
  ] })
558
1091
  });
559
1092
  return /* @__PURE__ */ jsxs("div", {
@@ -606,12 +1139,13 @@ function Calendar({ value, min, max, onValueChange, children, ...rest }) {
606
1139
  });
607
1140
  }
608
1141
  injectComponentStyle("calendar");
1142
+ injectComponentStyle("date-picker");
609
1143
  //#endregion
610
1144
  //#region src/components/card/index.tsx
611
1145
  /** A vessel: round, resting at the first elevation, one hairline for its
612
1146
  * edge. Root, Header, Title, Description, Content, Footer — sections
613
1147
  * carry their own whitespace, so any subset composes. */
614
- function part$6(name, tag) {
1148
+ function part$9(name, tag) {
615
1149
  const Tag = tag;
616
1150
  const Component = ({ asChild, children, ...rest }) => {
617
1151
  const partProps = {
@@ -631,22 +1165,166 @@ function part$6(name, tag) {
631
1165
  Component.displayName = "Card" + name;
632
1166
  return Component;
633
1167
  }
634
- const Root$5 = part$6("Root", "section");
635
- const Header = part$6("Header", "header");
636
- const Title$2 = part$6("Title", "h3");
637
- const Description$3 = part$6("Description", "p");
638
- const Content$1 = part$6("Content", "div");
639
- const Footer = part$6("Footer", "footer");
640
- const Card = Object.assign(Root$5, {
641
- Root: Root$5,
642
- Header,
1168
+ const Root$9 = part$9("Root", "section");
1169
+ const Header$1 = part$9("Header", "header");
1170
+ const Title$2 = part$9("Title", "h3");
1171
+ const Description$3 = part$9("Description", "p");
1172
+ const Content$3 = part$9("Content", "div");
1173
+ const Footer$1 = part$9("Footer", "footer");
1174
+ const Card = Object.assign(Root$9, {
1175
+ Root: Root$9,
1176
+ Header: Header$1,
643
1177
  Title: Title$2,
644
1178
  Description: Description$3,
645
- Content: Content$1,
646
- Footer
1179
+ Content: Content$3,
1180
+ Footer: Footer$1
647
1181
  });
648
1182
  injectComponentStyle("card");
649
1183
  //#endregion
1184
+ //#region src/components/cascade-select/index.tsx
1185
+ const chevronDown$2 = /* @__PURE__ */ jsx("svg", {
1186
+ viewBox: "0 0 24 24",
1187
+ fill: "none",
1188
+ stroke: "currentColor",
1189
+ strokeWidth: 2,
1190
+ strokeLinecap: "round",
1191
+ strokeLinejoin: "round",
1192
+ "aria-hidden": "true",
1193
+ children: /* @__PURE__ */ jsx("path", { d: "m6 9 6 6 6-6" })
1194
+ });
1195
+ const chevronRight = /* @__PURE__ */ jsx("svg", {
1196
+ viewBox: "0 0 24 24",
1197
+ fill: "none",
1198
+ stroke: "currentColor",
1199
+ strokeWidth: 2,
1200
+ strokeLinecap: "round",
1201
+ strokeLinejoin: "round",
1202
+ "aria-hidden": "true",
1203
+ children: /* @__PURE__ */ jsx("path", { d: "m9 18 6-6-6-6" })
1204
+ });
1205
+ const checkGlyph$2 = /* @__PURE__ */ jsx("svg", {
1206
+ viewBox: "0 0 24 24",
1207
+ fill: "none",
1208
+ stroke: "currentColor",
1209
+ strokeWidth: 3,
1210
+ strokeLinecap: "round",
1211
+ strokeLinejoin: "round",
1212
+ "aria-hidden": "true",
1213
+ children: /* @__PURE__ */ jsx("path", { d: "m5 12.5 5 5L19 7" })
1214
+ });
1215
+ function CascadeSelect({ value, data, placeholder = "Select…", highlightTrigger, multiple = false, disabled = false, onValueChange, ...rest }) {
1216
+ const id = useId();
1217
+ const locale = useLocaleContext();
1218
+ const env = useEnvironmentContext();
1219
+ const collection = cascade.collection({
1220
+ nodeToValue: (node) => node.value,
1221
+ nodeToString: (node) => node.label,
1222
+ nodeToChildren: (node) => node.children ?? [],
1223
+ rootNode: {
1224
+ value: "ROOT",
1225
+ label: "",
1226
+ children: data
1227
+ }
1228
+ });
1229
+ const service = useMachine(cascade.machine, {
1230
+ id,
1231
+ collection,
1232
+ dir: locale.dir,
1233
+ getRootNode: env.getRootNode.bind(env),
1234
+ disabled: disabled || void 0,
1235
+ multiple: multiple || void 0,
1236
+ ...value !== void 0 ? { value } : {},
1237
+ ...highlightTrigger != null ? { highlightTrigger } : {},
1238
+ onValueChange(details) {
1239
+ onValueChange?.(details.value);
1240
+ }
1241
+ });
1242
+ const api = cascade.connect(service, normalizeProps);
1243
+ /** The machine's `valueAsString` only updates through its select
1244
+ * event, so an externally-set `value` would render the placeholder
1245
+ * forever — resolve the labels from the data instead. */
1246
+ function labelsFor(path) {
1247
+ const out = [];
1248
+ let nodes = data;
1249
+ for (const entry of path) {
1250
+ const node = nodes?.find((n) => n.value === entry);
1251
+ if (!node) return null;
1252
+ out.push(node.label);
1253
+ nodes = node.children;
1254
+ }
1255
+ return out;
1256
+ }
1257
+ const display = (value ?? []).map((path) => labelsFor(path)?.join(" / ")).filter((label) => label != null).join(", ");
1258
+ /** One column per walk of the highlighted path — the list binds to
1259
+ * the node, the next column hangs off its highlighted child. */
1260
+ function renderColumn(node, indexPath, valuePath) {
1261
+ const nodeProps = {
1262
+ item: node,
1263
+ indexPath,
1264
+ value: valuePath
1265
+ };
1266
+ const nodeState = api.getItemState(nodeProps);
1267
+ const children = collection.getNodeChildren(node);
1268
+ const list = /* @__PURE__ */ jsx("ul", {
1269
+ ...api.getListProps(nodeProps),
1270
+ children: children.map((item, index) => {
1271
+ const itemValue = collection.getNodeValue(item);
1272
+ const itemProps = {
1273
+ item,
1274
+ indexPath: [...indexPath, index],
1275
+ value: [...valuePath, itemValue]
1276
+ };
1277
+ const itemState = api.getItemState(itemProps);
1278
+ return /* @__PURE__ */ jsxs("li", {
1279
+ ...api.getItemProps(itemProps),
1280
+ children: [
1281
+ /* @__PURE__ */ jsx("span", {
1282
+ ...api.getItemTextProps(itemProps),
1283
+ children: item.label
1284
+ }),
1285
+ itemState.hasChildren ? /* @__PURE__ */ jsx("span", {
1286
+ "data-part": "branch-indicator",
1287
+ "aria-hidden": "true",
1288
+ children: chevronRight
1289
+ }) : null,
1290
+ /* @__PURE__ */ jsx("span", {
1291
+ ...api.getItemIndicatorProps(itemProps),
1292
+ children: checkGlyph$2
1293
+ })
1294
+ ]
1295
+ }, itemValue);
1296
+ })
1297
+ });
1298
+ const next = nodeState.highlightedChild;
1299
+ return [list, next != null && collection.isBranchNode(next) ? renderColumn(next, [...indexPath, nodeState.highlightedIndex], [...valuePath, collection.getNodeValue(next)]) : null];
1300
+ }
1301
+ return /* @__PURE__ */ jsxs("div", {
1302
+ ...rest,
1303
+ ...api.getRootProps(),
1304
+ children: [/* @__PURE__ */ jsx("div", {
1305
+ ...api.getControlProps(),
1306
+ children: /* @__PURE__ */ jsxs("button", {
1307
+ ...api.getTriggerProps(),
1308
+ disabled: disabled || void 0,
1309
+ children: [/* @__PURE__ */ jsx("span", {
1310
+ ...api.getValueTextProps(),
1311
+ children: display || placeholder
1312
+ }), /* @__PURE__ */ jsx("span", {
1313
+ ...api.getIndicatorProps(),
1314
+ children: chevronDown$2
1315
+ })]
1316
+ })
1317
+ }), /* @__PURE__ */ jsx(Portal, { children: /* @__PURE__ */ jsx("div", {
1318
+ ...api.getPositionerProps(),
1319
+ children: /* @__PURE__ */ jsx("div", {
1320
+ ...api.getContentProps(),
1321
+ children: renderColumn(collection.rootNode, [], [])
1322
+ })
1323
+ }) })]
1324
+ });
1325
+ }
1326
+ injectComponentStyle("cascade-select");
1327
+ //#endregion
650
1328
  //#region src/components/carousel/index.tsx
651
1329
  /** Ark's Carousel, dressed in the paper-and-ink system: slides ride in one
652
1330
  * hairline-clipped lane, the triggers are quiet outline controls, and the
@@ -664,6 +1342,52 @@ injectComponentStyle("carousel");
664
1342
  const Checkbox = Checkbox$1;
665
1343
  injectComponentStyle("checkbox");
666
1344
  //#endregion
1345
+ //#region src/components/checkbox-group/index.tsx
1346
+ const checkGlyph$1 = /* @__PURE__ */ jsx("svg", {
1347
+ viewBox: "0 0 24 24",
1348
+ fill: "none",
1349
+ stroke: "currentColor",
1350
+ strokeWidth: 3,
1351
+ strokeLinecap: "round",
1352
+ strokeLinejoin: "round",
1353
+ "aria-hidden": "true",
1354
+ children: /* @__PURE__ */ jsx("path", { d: "m5 12.5 5 5L19 7" })
1355
+ });
1356
+ /**
1357
+ * One question, many answers: a labelled stack (or row) of the seal-cut
1358
+ * checkboxes bound to a single array. Toggling a box adds or removes its
1359
+ * value; the group itself is semantics (`role="group"`), the boxes stay
1360
+ * the machine-driven originals.
1361
+ */
1362
+ function CheckboxGroup({ value = [], options, layout = "vertical", disabled = false, onValueChange, ...rest }) {
1363
+ const selected = new Set(value);
1364
+ function toggle(option) {
1365
+ const next = new Set(selected);
1366
+ if (next.has(option)) next.delete(option);
1367
+ else next.add(option);
1368
+ onValueChange?.([...next]);
1369
+ }
1370
+ return /* @__PURE__ */ jsx("div", {
1371
+ ...rest,
1372
+ role: "group",
1373
+ "data-scope": "checkbox-group",
1374
+ "data-part": "root",
1375
+ "data-layout": layout,
1376
+ children: options.map((option) => /* @__PURE__ */ jsxs(Checkbox$1.Root, {
1377
+ checked: selected.has(option.value),
1378
+ disabled: disabled || option.disabled === true,
1379
+ onCheckedChange: () => toggle(option.value),
1380
+ children: [
1381
+ /* @__PURE__ */ jsx(Checkbox$1.Control, { children: /* @__PURE__ */ jsx(Checkbox$1.Indicator, { children: checkGlyph$1 }) }),
1382
+ /* @__PURE__ */ jsx(Checkbox$1.Label, { children: option.label }),
1383
+ /* @__PURE__ */ jsx(Checkbox$1.HiddenInput, {})
1384
+ ]
1385
+ }, option.value))
1386
+ });
1387
+ }
1388
+ injectComponentStyle("checkbox-group");
1389
+ injectComponentStyle("checkbox");
1390
+ //#endregion
667
1391
  //#region src/components/chip/index.tsx
668
1392
  function Chip({ value, max, tone = "ink", variant = "solid", ...rest }) {
669
1393
  const text = max != null && value > max ? `${max}+` : String(value);
@@ -707,6 +1431,227 @@ injectComponentStyle("color-picker");
707
1431
  const Combobox = Combobox$1;
708
1432
  injectComponentStyle("combobox");
709
1433
  //#endregion
1434
+ //#region src/components/command/index.tsx
1435
+ function Command({ items = [], placeholder, open, autoFilter = true, inputValue, emptyText = "No matching commands", onSelect, onOpenChange, onInputValueChange }) {
1436
+ const [internalOpen, setInternalOpen] = useState(false);
1437
+ const [listOpen, setListOpen] = useState(true);
1438
+ const [fieldText, setFieldText] = useState("");
1439
+ const { collection, set, filter } = useListCollection$1({
1440
+ initialItems: items.map((entry) => entry.value),
1441
+ filter: (value, input) => {
1442
+ const entry = items.find((candidate) => candidate.value === value);
1443
+ if (!entry) return false;
1444
+ const query = input.toLowerCase();
1445
+ return entry.label.toLowerCase().includes(query) || value.toLowerCase().includes(query);
1446
+ }
1447
+ });
1448
+ useEffect(() => {
1449
+ set(items.map((entry) => entry.value));
1450
+ if (autoFilter) filter(fieldText);
1451
+ }, [items]);
1452
+ const currentOpen = open ?? internalOpen;
1453
+ useEffect(() => {
1454
+ if (currentOpen) setListOpen(true);
1455
+ }, [currentOpen]);
1456
+ const setOpen = (value) => {
1457
+ if (open === void 0) setInternalOpen(value);
1458
+ onOpenChange?.(value);
1459
+ };
1460
+ const available = new Set(collection.items);
1461
+ const groups = /* @__PURE__ */ new Map();
1462
+ for (const entry of items) {
1463
+ if (!available.has(entry.value)) continue;
1464
+ const key = entry.group ?? "";
1465
+ if (!groups.has(key)) groups.set(key, []);
1466
+ groups.get(key).push(entry);
1467
+ }
1468
+ const row = (entry) => /* @__PURE__ */ jsx(Combobox$1.Item, {
1469
+ item: entry.value,
1470
+ asChild: true,
1471
+ children: /* @__PURE__ */ jsxs("div", {
1472
+ "data-scope": "command",
1473
+ "data-part": "item",
1474
+ children: [/* @__PURE__ */ jsx(Combobox$1.ItemText, {
1475
+ asChild: true,
1476
+ children: /* @__PURE__ */ jsx("span", {
1477
+ "data-scope": "command",
1478
+ "data-part": "item-label",
1479
+ children: entry.label
1480
+ })
1481
+ }), entry.hint ? /* @__PURE__ */ jsx("span", {
1482
+ "data-scope": "command",
1483
+ "data-part": "item-hint",
1484
+ children: entry.hint
1485
+ }) : void 0]
1486
+ })
1487
+ }, entry.value);
1488
+ return /* @__PURE__ */ jsx(Dialog$1.Root, {
1489
+ open: currentOpen,
1490
+ onOpenChange: (details) => setOpen(details.open),
1491
+ children: /* @__PURE__ */ jsxs(Portal, { children: [/* @__PURE__ */ jsx(Dialog$1.Backdrop, {}), /* @__PURE__ */ jsx(Dialog$1.Positioner, {
1492
+ asChild: true,
1493
+ children: /* @__PURE__ */ jsx("div", {
1494
+ "data-scope": "command",
1495
+ "data-part": "positioner",
1496
+ children: /* @__PURE__ */ jsx(Dialog$1.Content, {
1497
+ asChild: true,
1498
+ children: /* @__PURE__ */ jsx("div", {
1499
+ "data-scope": "command",
1500
+ "data-part": "content",
1501
+ children: /* @__PURE__ */ jsxs(Combobox$1.Root, {
1502
+ collection,
1503
+ inputValue,
1504
+ open: listOpen,
1505
+ onOpenChange: (details) => setListOpen(details.open),
1506
+ inputBehavior: "autohighlight",
1507
+ loopFocus: true,
1508
+ onInputValueChange: (details) => {
1509
+ setFieldText(details.inputValue);
1510
+ if (autoFilter) filter(details.inputValue);
1511
+ onInputValueChange?.(details.inputValue);
1512
+ },
1513
+ onValueChange: (details) => {
1514
+ const [first] = details.value;
1515
+ if (first == null) return;
1516
+ onSelect?.(first);
1517
+ setOpen(false);
1518
+ },
1519
+ children: [/* @__PURE__ */ jsx(Combobox$1.Input, {
1520
+ asChild: true,
1521
+ children: /* @__PURE__ */ jsx("input", {
1522
+ type: "text",
1523
+ placeholder,
1524
+ "data-scope": "command",
1525
+ "data-part": "input"
1526
+ })
1527
+ }), /* @__PURE__ */ jsx(Combobox$1.Content, {
1528
+ asChild: true,
1529
+ children: /* @__PURE__ */ jsxs("div", {
1530
+ "data-scope": "command",
1531
+ "data-part": "list",
1532
+ children: [Array.from(groups, ([group, entries]) => group === "" ? entries.map(row) : /* @__PURE__ */ jsx(Combobox$1.ItemGroup, {
1533
+ asChild: true,
1534
+ children: /* @__PURE__ */ jsxs("div", {
1535
+ "data-scope": "command",
1536
+ "data-part": "group",
1537
+ children: [/* @__PURE__ */ jsx(Combobox$1.ItemGroupLabel, {
1538
+ asChild: true,
1539
+ children: /* @__PURE__ */ jsx("div", {
1540
+ "data-scope": "command",
1541
+ "data-part": "group-label",
1542
+ children: group
1543
+ })
1544
+ }), entries.map(row)]
1545
+ })
1546
+ }, group)), groups.size === 0 ? /* @__PURE__ */ jsx("div", {
1547
+ "data-scope": "command",
1548
+ "data-part": "empty",
1549
+ children: emptyText
1550
+ }) : null]
1551
+ })
1552
+ })]
1553
+ })
1554
+ })
1555
+ })
1556
+ })
1557
+ })] })
1558
+ });
1559
+ }
1560
+ injectComponentStyle("command");
1561
+ injectComponentStyle("dialog");
1562
+ //#endregion
1563
+ //#region src/components/comment/index.tsx
1564
+ function Comment({ author, datetime, avatar, actions, children, ...rest }) {
1565
+ return /* @__PURE__ */ jsxs("article", {
1566
+ ...rest,
1567
+ "data-scope": "comment",
1568
+ "data-part": "root",
1569
+ children: [avatar ? /* @__PURE__ */ jsx("div", {
1570
+ "data-scope": "comment",
1571
+ "data-part": "avatar",
1572
+ children: avatar
1573
+ }) : null, /* @__PURE__ */ jsxs("div", {
1574
+ "data-scope": "comment",
1575
+ "data-part": "body",
1576
+ children: [
1577
+ author || datetime ? /* @__PURE__ */ jsxs("header", {
1578
+ "data-scope": "comment",
1579
+ "data-part": "header",
1580
+ children: [author ? /* @__PURE__ */ jsx("span", {
1581
+ "data-scope": "comment",
1582
+ "data-part": "author",
1583
+ children: author
1584
+ }) : null, datetime ? /* @__PURE__ */ jsx("time", {
1585
+ "data-scope": "comment",
1586
+ "data-part": "datetime",
1587
+ dateTime: datetime,
1588
+ children: datetime
1589
+ }) : null]
1590
+ }) : null,
1591
+ /* @__PURE__ */ jsx("div", {
1592
+ "data-scope": "comment",
1593
+ "data-part": "content",
1594
+ children
1595
+ }),
1596
+ actions ? /* @__PURE__ */ jsx("div", {
1597
+ "data-scope": "comment",
1598
+ "data-part": "actions",
1599
+ children: actions
1600
+ }) : null
1601
+ ]
1602
+ })]
1603
+ });
1604
+ }
1605
+ injectComponentStyle("comment");
1606
+ //#endregion
1607
+ //#region src/components/config-provider/index.tsx
1608
+ const ConfigContextImpl = createContext({});
1609
+ /** The nearest provider's snapshot, or an empty one when no provider
1610
+ * wraps the caller — the hook the date and format families will consume
1611
+ * to localize their output. */
1612
+ function useConfig() {
1613
+ return useContext(ConfigContextImpl);
1614
+ }
1615
+ /**
1616
+ * The declarative host for global configuration: one element that both
1617
+ * carries the token layer's attributes — `[data-density]` and
1618
+ * `[data-accent]` fire on any element — and provides the same values to
1619
+ * descendants through `useConfig`, so interactive behavior (formatting,
1620
+ * messages) and visual theming stay one decision.
1621
+ */
1622
+ function ConfigProvider({ density, accent, dir, locale, children, ...rest }) {
1623
+ return /* @__PURE__ */ jsx(ConfigContextImpl.Provider, {
1624
+ value: {
1625
+ density,
1626
+ accent,
1627
+ dir,
1628
+ locale
1629
+ },
1630
+ children: /* @__PURE__ */ jsx("div", {
1631
+ ...rest,
1632
+ "data-scope": "config-provider",
1633
+ "data-part": "root",
1634
+ ...density != null ? { "data-density": density } : {},
1635
+ ...accent != null ? { "data-accent": accent } : {},
1636
+ ...dir != null ? { dir } : {},
1637
+ ...locale != null ? { lang: locale } : {},
1638
+ children
1639
+ })
1640
+ });
1641
+ }
1642
+ //#endregion
1643
+ //#region src/components/container/index.tsx
1644
+ function Container({ size = "readable", padding = true, ...rest }) {
1645
+ return /* @__PURE__ */ jsx("div", {
1646
+ ...rest,
1647
+ "data-scope": "container",
1648
+ "data-part": "root",
1649
+ "data-size": size,
1650
+ "data-padding": padding ? "" : void 0
1651
+ });
1652
+ }
1653
+ injectComponentStyle("container");
1654
+ //#endregion
710
1655
  //#region src/components/date-input/index.tsx
711
1656
  /** Ark's DateInput, dressed in the paper-and-ink system: a segmented
712
1657
  * field where the focused segment takes the flat ink fill. The API is
@@ -725,6 +1670,35 @@ injectComponentStyle("date-input");
725
1670
  const DatePicker = DatePicker$1;
726
1671
  injectComponentStyle("date-picker");
727
1672
  //#endregion
1673
+ //#region src/components/descriptions/index.tsx
1674
+ function DescriptionsRoot({ layout = "horizontal", children, ...rest }) {
1675
+ return /* @__PURE__ */ jsx("dl", {
1676
+ ...rest,
1677
+ "data-scope": "descriptions",
1678
+ "data-part": "root",
1679
+ "data-layout": layout,
1680
+ children
1681
+ });
1682
+ }
1683
+ function part$8(name, tag) {
1684
+ const Tag = tag;
1685
+ const Component = ({ children, ...rest }) => /* @__PURE__ */ jsx(Tag, {
1686
+ ...rest,
1687
+ "data-scope": "descriptions",
1688
+ "data-part": name.toLowerCase(),
1689
+ children
1690
+ });
1691
+ Component.displayName = "Descriptions" + name;
1692
+ return Component;
1693
+ }
1694
+ const Descriptions = {
1695
+ Root: DescriptionsRoot,
1696
+ Item: part$8("Item", "div"),
1697
+ Term: part$8("Term", "dt"),
1698
+ Detail: part$8("Detail", "dd")
1699
+ };
1700
+ injectComponentStyle("descriptions");
1701
+ //#endregion
728
1702
  //#region src/components/dialog/index.tsx
729
1703
  /** Ark's Dialog, dressed in the paper-and-ink system: the sheet dissolves
730
1704
  * in on elevation, the backdrop fades, and nested overlays stack through
@@ -742,6 +1716,98 @@ injectComponentStyle("dialog");
742
1716
  const Drawer = Drawer$1;
743
1717
  injectComponentStyle("drawer");
744
1718
  //#endregion
1719
+ //#region src/components/input/index.tsx
1720
+ function Input({ value, size = "md", invalid = false, onValueChange, ...rest }) {
1721
+ const field = useFieldContext();
1722
+ const fieldProps = field?.getInputProps() ?? {};
1723
+ return /* @__PURE__ */ jsx("input", {
1724
+ ...fieldProps,
1725
+ ...rest,
1726
+ ...value !== void 0 ? { value } : {},
1727
+ "data-scope": "input",
1728
+ "data-part": "root",
1729
+ "data-size": size,
1730
+ "data-invalid": invalid || field?.invalid ? "" : void 0,
1731
+ onChange: (event) => onValueChange?.(event.target.value)
1732
+ });
1733
+ }
1734
+ injectComponentStyle("input");
1735
+ //#endregion
1736
+ //#region src/components/dynamic-input/index.tsx
1737
+ /**
1738
+ * A column of entry rows: one Input per line, each with a quiet remove
1739
+ * seal, and an add row at the tail. The list is controlled — every edit
1740
+ * reports a fresh array through `onValueChange` and the caller's array
1741
+ * stays the only truth. Deleting never drops below `min`, adding never
1742
+ * grows past `max`, and the group always keeps one row: an entry list
1743
+ * that emptied itself would leave the reader no place to type.
1744
+ */
1745
+ function DynamicInput({ value, min = 0, max, placeholder, addLabel = "Add entry", disabled = false, invalid = false, onValueChange, children: _children, ...rest }) {
1746
+ const values = value ?? [""];
1747
+ const update = (index, next) => {
1748
+ const rows = values.slice();
1749
+ rows[index] = next;
1750
+ onValueChange?.(rows);
1751
+ };
1752
+ const remove = (index) => {
1753
+ const rows = values.filter((_, i) => i !== index);
1754
+ onValueChange?.(rows.length > 0 ? rows : [""]);
1755
+ };
1756
+ const add = () => {
1757
+ onValueChange?.([...values, ""]);
1758
+ };
1759
+ const canRemove = values.length > Math.max(min, 1);
1760
+ const canAdd = max === void 0 || values.length < max;
1761
+ return /* @__PURE__ */ jsxs("div", {
1762
+ ...rest,
1763
+ "data-scope": "dynamic-input",
1764
+ "data-part": "root",
1765
+ children: [values.map((value, index) => /* @__PURE__ */ jsxs("div", {
1766
+ "data-scope": "dynamic-input",
1767
+ "data-part": "row",
1768
+ children: [/* @__PURE__ */ jsx(Input, {
1769
+ value,
1770
+ placeholder,
1771
+ disabled,
1772
+ invalid,
1773
+ onValueChange: (next) => update(index, next)
1774
+ }), /* @__PURE__ */ jsx(Button, {
1775
+ variant: "ghost",
1776
+ square: true,
1777
+ disabled: disabled || !canRemove,
1778
+ "aria-label": `Remove entry ${index + 1}`,
1779
+ onClick: () => remove(index),
1780
+ children: crossIcon()
1781
+ })]
1782
+ }, index)), /* @__PURE__ */ jsx("div", {
1783
+ "data-scope": "dynamic-input",
1784
+ "data-part": "add",
1785
+ children: /* @__PURE__ */ jsxs(Button, {
1786
+ variant: "ghost",
1787
+ disabled: disabled || !canAdd,
1788
+ onClick: () => add(),
1789
+ children: ["+", addLabel]
1790
+ })
1791
+ })]
1792
+ });
1793
+ }
1794
+ /** The one glyph a remove seal needs: a single crossing stroke. */
1795
+ function crossIcon() {
1796
+ return /* @__PURE__ */ jsx("svg", {
1797
+ width: 16,
1798
+ height: 16,
1799
+ viewBox: "0 0 24 24",
1800
+ fill: "none",
1801
+ stroke: "currentColor",
1802
+ strokeWidth: 1.75,
1803
+ strokeLinecap: "round",
1804
+ strokeLinejoin: "round",
1805
+ "aria-hidden": "true",
1806
+ children: /* @__PURE__ */ jsx("path", { d: "M18 6 6 18M6 6l12 12" })
1807
+ });
1808
+ }
1809
+ injectComponentStyle("dynamic-input");
1810
+ //#endregion
745
1811
  //#region src/components/editable/index.tsx
746
1812
  /** Ark's Editable, dressed in the paper-and-ink system: bare ink while
747
1813
  * reading, the full field recipe while editing. The API is Ark's own —
@@ -750,11 +1816,27 @@ injectComponentStyle("drawer");
750
1816
  const Editable = Editable$1;
751
1817
  injectComponentStyle("editable");
752
1818
  //#endregion
1819
+ //#region src/components/ellipsis/index.tsx
1820
+ function Ellipsis({ lines = 1, ...rest }) {
1821
+ const multiline = lines > 1;
1822
+ return /* @__PURE__ */ jsx("span", {
1823
+ ...rest,
1824
+ style: multiline ? {
1825
+ ...rest.style,
1826
+ "--bs-ellipsis-lines": String(lines)
1827
+ } : rest.style,
1828
+ "data-scope": "ellipsis",
1829
+ "data-part": "root",
1830
+ "data-multiline": multiline ? "" : void 0
1831
+ });
1832
+ }
1833
+ injectComponentStyle("ellipsis");
1834
+ //#endregion
753
1835
  //#region src/components/empty/index.tsx
754
1836
  /** An empty state: the page holds its breath. Root centers the column,
755
1837
  * Visual carries the mark, Title and Description carry the ink, Actions
756
1838
  * the way out. Any subset composes. */
757
- function part$5(name, tag) {
1839
+ function part$7(name, tag) {
758
1840
  const Tag = tag;
759
1841
  const Component = ({ children, ...rest }) => /* @__PURE__ */ jsx(Tag, {
760
1842
  ...rest,
@@ -765,17 +1847,17 @@ function part$5(name, tag) {
765
1847
  Component.displayName = "Empty" + name;
766
1848
  return Component;
767
1849
  }
768
- const Root$4 = part$5("Root", "div");
769
- const Visual = part$5("Visual", "div");
770
- const Title$1 = part$5("Title", "h3");
771
- const Description$2 = part$5("Description", "p");
772
- const Actions$1 = part$5("Actions", "div");
773
- const Empty = Object.assign(Root$4, {
774
- Root: Root$4,
1850
+ const Root$8 = part$7("Root", "div");
1851
+ const Visual = part$7("Visual", "div");
1852
+ const Title$1 = part$7("Title", "h3");
1853
+ const Description$2 = part$7("Description", "p");
1854
+ const Actions$2 = part$7("Actions", "div");
1855
+ const Empty = Object.assign(Root$8, {
1856
+ Root: Root$8,
775
1857
  Visual,
776
1858
  Title: Title$1,
777
1859
  Description: Description$2,
778
- Actions: Actions$1
1860
+ Actions: Actions$2
779
1861
  });
780
1862
  injectComponentStyle("empty");
781
1863
  //#endregion
@@ -796,6 +1878,85 @@ injectComponentStyle("fieldset");
796
1878
  const FileUpload = FileUpload$1;
797
1879
  injectComponentStyle("file-upload");
798
1880
  //#endregion
1881
+ //#region src/components/float-button/index.tsx
1882
+ /** Context for {@link FloatButtonContextValue}, exported so a custom
1883
+ * part can read the group's state. */
1884
+ const FLOAT_BUTTON_CONTEXT = createContext(null);
1885
+ /**
1886
+ * A floating action and its fanned-out alternatives — FAB and speed
1887
+ * dial in one family. The Root moors the group at a page corner and
1888
+ * holds the openness (mirrored from `open` when controlled); the
1889
+ * Trigger flips it; each Item is a round action with its name surfacing
1890
+ * beside it while the group is open. The buttons are the shared recipe
1891
+ * (vessels here: round); this family owns only the mooring, the fan
1892
+ * and the fold.
1893
+ */
1894
+ function Root$7({ open: openProp, placement = "bottom-end", onOpenChange, children, ...rest }) {
1895
+ const [inner, setInner] = useState(false);
1896
+ const open = openProp !== void 0 ? openProp : inner;
1897
+ const setOpen = (value) => {
1898
+ setInner(value);
1899
+ onOpenChange?.(value);
1900
+ };
1901
+ return /* @__PURE__ */ jsx(FLOAT_BUTTON_CONTEXT.Provider, {
1902
+ value: {
1903
+ open,
1904
+ toggle: () => setOpen(!open),
1905
+ close: () => setOpen(false)
1906
+ },
1907
+ children: /* @__PURE__ */ jsx("div", {
1908
+ ...rest,
1909
+ "data-scope": "float-button",
1910
+ "data-part": "root",
1911
+ "data-placement": placement,
1912
+ "data-state": open ? "open" : "closed",
1913
+ children
1914
+ })
1915
+ });
1916
+ }
1917
+ function Trigger({ label, children }) {
1918
+ const context = useContext(FLOAT_BUTTON_CONTEXT);
1919
+ return /* @__PURE__ */ jsx(Button, {
1920
+ variant: "solid",
1921
+ square: true,
1922
+ size: "lg",
1923
+ onClick: () => context?.toggle(),
1924
+ "aria-label": label || "Actions",
1925
+ "aria-expanded": context ? context.open : false,
1926
+ children
1927
+ });
1928
+ }
1929
+ function Item$2({ label, disabled = false, onClick, children }) {
1930
+ const context = useContext(FLOAT_BUTTON_CONTEXT);
1931
+ return /* @__PURE__ */ jsxs("div", {
1932
+ "data-scope": "float-button",
1933
+ "data-part": "item",
1934
+ children: [/* @__PURE__ */ jsx(Button, {
1935
+ variant: "outline",
1936
+ square: true,
1937
+ size: "md",
1938
+ disabled,
1939
+ "aria-label": label,
1940
+ onClick: () => {
1941
+ onClick?.();
1942
+ context?.close();
1943
+ },
1944
+ children
1945
+ }), /* @__PURE__ */ jsx("span", {
1946
+ "data-scope": "float-button",
1947
+ "data-part": "item-label",
1948
+ "aria-hidden": "true",
1949
+ children: label
1950
+ })]
1951
+ });
1952
+ }
1953
+ const FloatButton = Object.assign(Root$7, {
1954
+ Root: Root$7,
1955
+ Trigger,
1956
+ Item: Item$2
1957
+ });
1958
+ injectComponentStyle("float-button");
1959
+ //#endregion
799
1960
  //#region src/components/floating-panel/index.tsx
800
1961
  /** Ark's FloatingPanel, dressed in the paper-and-ink system: the shared
801
1962
  * popup vessel let loose — a draggable, resizable sheet whose header is the
@@ -805,6 +1966,134 @@ injectComponentStyle("file-upload");
805
1966
  const FloatingPanel = FloatingPanel$1;
806
1967
  injectComponentStyle("floating-panel");
807
1968
  //#endregion
1969
+ //#region src/components/form/index.tsx
1970
+ const FormContext = createContext(null);
1971
+ /** Walk a Standard Schema issue's path back to the dotted name the
1972
+ * matching FormField declared. */
1973
+ function issueName(issue) {
1974
+ return (issue.path ?? []).map((segment) => typeof segment === "object" ? segment.key : segment).join(".");
1975
+ }
1976
+ /**
1977
+ * The validation scheduler: one error map, a submit that validates
1978
+ * before it fires, live re-validation on the events the `validateOn`
1979
+ * prop names, and the imperative handle. The schema is any Standard
1980
+ * Schema (valibot, zod, arktype, …) — none are bundled; a `validate`
1981
+ * function composes with it for the cases schemas can't express. Errors
1982
+ * reach their field by name, through FormField.
1983
+ */
1984
+ function Form({ state, schema, validate, validateOn = [
1985
+ "input",
1986
+ "change",
1987
+ "blur"
1988
+ ], disabled = false, onSubmit, onError, ref, children, ...rest }) {
1989
+ const [errors, setErrors] = useState(() => /* @__PURE__ */ new Map());
1990
+ const run = useRef(0);
1991
+ async function runValidate() {
1992
+ const seq = ++run.current;
1993
+ const next = /* @__PURE__ */ new Map();
1994
+ if (validate) for (const error of await validate(state)) next.set(error.name, error.message);
1995
+ if (schema) {
1996
+ const result = await schema["~standard"].validate(state);
1997
+ for (const issue of result.issues ?? []) {
1998
+ const name = issueName(issue);
1999
+ if (!next.has(name)) next.set(name, issue.message);
2000
+ }
2001
+ }
2002
+ if (seq === run.current) setErrors(next);
2003
+ return next;
2004
+ }
2005
+ function clear(name) {
2006
+ if (!name) {
2007
+ setErrors(/* @__PURE__ */ new Map());
2008
+ return;
2009
+ }
2010
+ setErrors((prev) => {
2011
+ const next = new Map(prev);
2012
+ for (const key of next.keys()) if (typeof name === "string" ? key === name : name.test(key)) next.delete(key);
2013
+ return next;
2014
+ });
2015
+ }
2016
+ function setErrorsFrom(list) {
2017
+ setErrors(new Map(list.map((error) => [error.name, error.message])));
2018
+ }
2019
+ function getErrors(name) {
2020
+ const all = [...errors].map(([entry, message]) => ({
2021
+ name: entry,
2022
+ message
2023
+ }));
2024
+ if (!name) return all;
2025
+ return all.filter((error) => typeof name === "string" ? error.name === name : name.test(error.name));
2026
+ }
2027
+ useImperativeHandle(ref, () => ({
2028
+ validate: runValidate,
2029
+ clear,
2030
+ setErrors: setErrorsFrom,
2031
+ getErrors,
2032
+ errors
2033
+ }));
2034
+ function handleSubmit(event) {
2035
+ event.preventDefault();
2036
+ runValidate().then((map) => {
2037
+ if (map.size === 0) {
2038
+ onSubmit?.(state);
2039
+ return;
2040
+ }
2041
+ onError?.([...map].map(([name, message]) => ({
2042
+ name,
2043
+ message
2044
+ })));
2045
+ });
2046
+ }
2047
+ const timer = useRef(void 0);
2048
+ function onDelegated(kind, event) {
2049
+ if (!validateOn.includes(kind)) return;
2050
+ const target = event.target;
2051
+ if (!target || !("value" in target)) return;
2052
+ clearTimeout(timer.current);
2053
+ timer.current = setTimeout(() => void runValidate(), kind === "blur" ? 0 : 300);
2054
+ }
2055
+ return /* @__PURE__ */ jsx(FormContext.Provider, {
2056
+ value: {
2057
+ errors,
2058
+ disabled
2059
+ },
2060
+ children: /* @__PURE__ */ jsx("form", {
2061
+ ...rest,
2062
+ "data-scope": "form",
2063
+ "data-part": "root",
2064
+ noValidate: true,
2065
+ onSubmit: handleSubmit,
2066
+ onInput: (event) => onDelegated("input", event),
2067
+ onChange: (event) => onDelegated("change", event),
2068
+ onBlurCapture: (event) => onDelegated("blur", event),
2069
+ children
2070
+ })
2071
+ });
2072
+ }
2073
+ function FormField({ name, label, hint, required = false, invalid = false, disabled = false, children, ...rest }) {
2074
+ const form = useContext(FormContext);
2075
+ const formError = name ? form?.errors.get(name) : void 0;
2076
+ const isInvalid = invalid || formError != null;
2077
+ const isDisabled = disabled || (form?.disabled ?? false);
2078
+ return /* @__PURE__ */ jsx("div", {
2079
+ ...rest,
2080
+ "data-form-field": name,
2081
+ children: /* @__PURE__ */ jsxs(Field$1.Root, {
2082
+ invalid: isInvalid,
2083
+ required,
2084
+ disabled: isDisabled,
2085
+ children: [
2086
+ label ? /* @__PURE__ */ jsx(Field$1.Label, { children: label }) : null,
2087
+ children,
2088
+ hint && formError == null ? /* @__PURE__ */ jsx(Field$1.HelperText, { children: hint }) : null,
2089
+ formError != null ? /* @__PURE__ */ jsx(Field$1.ErrorText, { children: formError }) : null
2090
+ ]
2091
+ })
2092
+ });
2093
+ }
2094
+ injectComponentStyle("form");
2095
+ injectComponentStyle("field");
2096
+ //#endregion
808
2097
  //#region src/components/format/index.tsx
809
2098
  /** Ark's Format, dressed in the paper-and-ink system: Intl formatting for
810
2099
  * numbers, currency, bytes and relative time. The components render bare
@@ -823,6 +2112,34 @@ const Format = Format$1;
823
2112
  * to hook. The API is Ark's own. */
824
2113
  const Frame = Frame$1;
825
2114
  //#endregion
2115
+ //#region src/components/grid/index.tsx
2116
+ /** The same named steps of the space ramp the stack uses — one
2117
+ * vocabulary of distance across the layout primitives. */
2118
+ const gapVars$2 = {
2119
+ none: "0",
2120
+ xs: "var(--bs-gap-xs)",
2121
+ sm: "var(--bs-gap-sm)",
2122
+ md: "var(--bs-gap-md)",
2123
+ lg: "var(--bs-gap-lg)",
2124
+ xl: "var(--bs-gap-xl)"
2125
+ };
2126
+ function Grid({ columns = 12, gap = "md", minChildWidth, ...rest }) {
2127
+ const style = {
2128
+ ...rest.style,
2129
+ "--bs-grid-columns": String(columns),
2130
+ "--bs-grid-gap": gapVars$2[gap] ?? gapVars$2.md,
2131
+ ...minChildWidth != null ? { "--bs-grid-min-child-width": minChildWidth } : {}
2132
+ };
2133
+ return /* @__PURE__ */ jsx("div", {
2134
+ ...rest,
2135
+ style,
2136
+ "data-scope": "grid",
2137
+ "data-part": "root",
2138
+ "data-autofill": minChildWidth != null ? "" : void 0
2139
+ });
2140
+ }
2141
+ injectComponentStyle("grid");
2142
+ //#endregion
826
2143
  //#region src/components/highlight/index.tsx
827
2144
  /** Ark's Highlight, dressed in the paper-and-ink system: query hits are
828
2145
  * strokes of pigment on the page — a quiet tint of the accent behind the
@@ -831,12 +2148,80 @@ const Frame = Frame$1;
831
2148
  const Highlight = Highlight$1;
832
2149
  injectComponentStyle("highlight");
833
2150
  //#endregion
834
- //#region src/components/hover-card/index.tsx
835
- /** Ark's HoverCard, dressed in the paper-and-ink system: a preview card
836
- * that dissolves in over a quiet inline link, never stealing focus. The
837
- * API is Ark's own — Root, Trigger, Positioner, Content, Arrow, ArrowTip. */
838
- const HoverCard = HoverCard$1;
839
- injectComponentStyle("hover-card");
2151
+ //#region src/components/hover-card/index.tsx
2152
+ /** Ark's HoverCard, dressed in the paper-and-ink system: a preview card
2153
+ * that dissolves in over a quiet inline link, never stealing focus. The
2154
+ * API is Ark's own — Root, Trigger, Positioner, Content, Arrow, ArrowTip. */
2155
+ const HoverCard = HoverCard$1;
2156
+ injectComponentStyle("hover-card");
2157
+ //#endregion
2158
+ //#region src/components/icon/index.tsx
2159
+ function Icon({ size = "inherit", label, children, ...rest }) {
2160
+ return /* @__PURE__ */ jsx("span", {
2161
+ ...rest,
2162
+ role: label != null ? "img" : void 0,
2163
+ "aria-label": label,
2164
+ "aria-hidden": label != null ? void 0 : "true",
2165
+ "data-scope": "icon",
2166
+ "data-part": "root",
2167
+ "data-size": size,
2168
+ children
2169
+ });
2170
+ }
2171
+ injectComponentStyle("icon");
2172
+ //#endregion
2173
+ //#region src/components/image/index.tsx
2174
+ /** The mark for a source that never arrived: a quiet mountain-and-sun,
2175
+ * drawn in the stylesheet's stroke and hidden from the reader. */
2176
+ function placeholderGlyph() {
2177
+ return /* @__PURE__ */ jsxs("svg", {
2178
+ viewBox: "0 0 24 24",
2179
+ fill: "none",
2180
+ stroke: "currentColor",
2181
+ "aria-hidden": "true",
2182
+ children: [
2183
+ /* @__PURE__ */ jsx("rect", {
2184
+ x: 3,
2185
+ y: 4,
2186
+ width: 18,
2187
+ height: 16,
2188
+ rx: 1.5
2189
+ }),
2190
+ /* @__PURE__ */ jsx("circle", {
2191
+ cx: 9,
2192
+ cy: 10,
2193
+ r: 1.5
2194
+ }),
2195
+ /* @__PURE__ */ jsx("path", { d: "m5.5 17.5 4.5-5 3 3.5 2.5-3 3 4.5" })
2196
+ ]
2197
+ });
2198
+ }
2199
+ function Image({ src, alt = "", fit = "cover", loading = "lazy", fallback, ...rest }) {
2200
+ const [state, setState] = useState("loading");
2201
+ useEffect(() => setState("loading"), [src]);
2202
+ return /* @__PURE__ */ jsxs("figure", {
2203
+ ...rest,
2204
+ "data-scope": "image",
2205
+ "data-part": "root",
2206
+ "data-state": state,
2207
+ "data-fit": fit,
2208
+ children: [/* @__PURE__ */ jsx("img", {
2209
+ "data-scope": "image",
2210
+ "data-part": "img",
2211
+ src,
2212
+ alt,
2213
+ loading,
2214
+ decoding: "async",
2215
+ onLoad: () => setState("loaded"),
2216
+ onError: () => setState("error")
2217
+ }), state === "error" ? /* @__PURE__ */ jsx("div", {
2218
+ "data-scope": "image",
2219
+ "data-part": "fallback",
2220
+ children: fallback ?? placeholderGlyph()
2221
+ }) : null]
2222
+ });
2223
+ }
2224
+ injectComponentStyle("image");
840
2225
  //#endregion
841
2226
  //#region src/components/image-cropper/index.tsx
842
2227
  /** Ark's ImageCropper, dressed in the paper-and-ink system: a rounded vessel
@@ -846,6 +2231,136 @@ injectComponentStyle("hover-card");
846
2231
  const ImageCropper = ImageCropper$1;
847
2232
  injectComponentStyle("image-cropper");
848
2233
  //#endregion
2234
+ //#region src/components/image-viewer/index.tsx
2235
+ const MIN_SCALE = .5;
2236
+ const MAX_SCALE = 3;
2237
+ const SCALE_STEP = .25;
2238
+ /** The toolbar's line-drawn glyphs, fresh per render. */
2239
+ const TOOL_GLYPHS = {
2240
+ zoomIn: () => /* @__PURE__ */ jsxs(Fragment, { children: [
2241
+ /* @__PURE__ */ jsx("circle", {
2242
+ cx: 11,
2243
+ cy: 11,
2244
+ r: 7
2245
+ }),
2246
+ /* @__PURE__ */ jsx("path", { d: "m16.2 16.2 4.8 4.8" }),
2247
+ /* @__PURE__ */ jsx("path", { d: "M8 11h6" }),
2248
+ /* @__PURE__ */ jsx("path", { d: "M11 8v6" })
2249
+ ] }),
2250
+ zoomOut: () => /* @__PURE__ */ jsxs(Fragment, { children: [
2251
+ /* @__PURE__ */ jsx("circle", {
2252
+ cx: 11,
2253
+ cy: 11,
2254
+ r: 7
2255
+ }),
2256
+ /* @__PURE__ */ jsx("path", { d: "m16.2 16.2 4.8 4.8" }),
2257
+ /* @__PURE__ */ jsx("path", { d: "M8 11h6" })
2258
+ ] }),
2259
+ rotate: () => /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("path", { d: "M20.49 12A8.5 8.5 0 1 1 18 6.06" }), /* @__PURE__ */ jsx("path", { d: "M20.5 3.5v4h-4" })] }),
2260
+ close: () => /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("path", { d: "m6 6 12 12" }), /* @__PURE__ */ jsx("path", { d: "M18 6 6 18" })] })
2261
+ };
2262
+ function ImageViewer({ src, alt = "", open, zoomable = true, onOpenChange }) {
2263
+ const [localOpen, setLocalOpen] = useState(false);
2264
+ const [scale, setScale] = useState(1);
2265
+ const [rotation, setRotation] = useState(0);
2266
+ const isOpen = open ?? localOpen;
2267
+ const setOpen = (value) => {
2268
+ if (open === void 0) setLocalOpen(value);
2269
+ onOpenChange?.(value);
2270
+ };
2271
+ useEffect(() => {
2272
+ if (isOpen) {
2273
+ setScale(1);
2274
+ setRotation(0);
2275
+ }
2276
+ }, [isOpen]);
2277
+ function zoom(step) {
2278
+ setScale((current) => Math.min(MAX_SCALE, Math.max(MIN_SCALE, current + step)));
2279
+ }
2280
+ function rotate() {
2281
+ setRotation((current) => (current + 90) % 360);
2282
+ }
2283
+ function toolButton(label, glyph, onClick) {
2284
+ return /* @__PURE__ */ jsx(Button, {
2285
+ variant: "ghost",
2286
+ square: true,
2287
+ size: "lg",
2288
+ "aria-label": label,
2289
+ onClick,
2290
+ children: /* @__PURE__ */ jsx("svg", {
2291
+ viewBox: "0 0 24 24",
2292
+ fill: "none",
2293
+ stroke: "currentColor",
2294
+ strokeWidth: 1.5,
2295
+ strokeLinecap: "round",
2296
+ strokeLinejoin: "round",
2297
+ "aria-hidden": "true",
2298
+ children: glyph()
2299
+ })
2300
+ });
2301
+ }
2302
+ return /* @__PURE__ */ jsx(Dialog$1.Root, {
2303
+ open: isOpen,
2304
+ onOpenChange: (details) => setOpen(details.open),
2305
+ lazyMount: true,
2306
+ unmountOnExit: true,
2307
+ children: /* @__PURE__ */ jsxs(Portal, { children: [/* @__PURE__ */ jsx(Dialog$1.Backdrop, { className: "bs-image-viewer-backdrop" }), /* @__PURE__ */ jsx(Dialog$1.Positioner, {
2308
+ className: "bs-image-viewer-positioner",
2309
+ children: /* @__PURE__ */ jsxs(Dialog$1.Content, {
2310
+ className: "bs-image-viewer-content",
2311
+ "aria-label": alt || "Image preview",
2312
+ onClick: (event) => {
2313
+ if (event.target === event.currentTarget) setOpen(false);
2314
+ },
2315
+ children: [/* @__PURE__ */ jsx("img", {
2316
+ "data-scope": "image-viewer",
2317
+ "data-part": "viewport",
2318
+ src,
2319
+ alt,
2320
+ style: { transform: `scale(${scale}) rotate(${rotation}deg)` }
2321
+ }), /* @__PURE__ */ jsx("div", {
2322
+ "data-scope": "image-viewer",
2323
+ "data-part": "toolbar",
2324
+ children: /* @__PURE__ */ jsxs(ButtonGroup, { children: [
2325
+ zoomable ? [toolButton("Zoom in", TOOL_GLYPHS.zoomIn, () => zoom(SCALE_STEP)), toolButton("Zoom out", TOOL_GLYPHS.zoomOut, () => zoom(-.25))] : null,
2326
+ toolButton("Rotate 90 degrees", TOOL_GLYPHS.rotate, rotate),
2327
+ toolButton("Close", TOOL_GLYPHS.close, () => setOpen(false))
2328
+ ] })
2329
+ })]
2330
+ })
2331
+ })] })
2332
+ });
2333
+ }
2334
+ injectComponentStyle("image-viewer");
2335
+ //#endregion
2336
+ //#region src/components/input-group/index.tsx
2337
+ function part$6(name) {
2338
+ const Component = ({ children, ...rest }) => /* @__PURE__ */ jsx("div", {
2339
+ ...rest,
2340
+ "data-scope": "input-group",
2341
+ "data-part": name.toLowerCase(),
2342
+ children
2343
+ });
2344
+ Component.displayName = "InputGroup" + name;
2345
+ return Component;
2346
+ }
2347
+ /**
2348
+ * Merged controls: attachments and the entry fused into one seal. The
2349
+ * Root draws the single hairline and carries the group's focus halo;
2350
+ * the Addon is a recessed cell for the reader's fixed words — a scheme,
2351
+ * a unit, a quiet button — placed before or after the entry. Put our
2352
+ * Input (or Textarea) inside and its own border and halo step aside in
2353
+ * favor of the group's; the stylesheet does the merging, the wrapper
2354
+ * adds no visuals of its own.
2355
+ */
2356
+ const Root$6 = part$6("Root");
2357
+ const Addon = part$6("Addon");
2358
+ const InputGroup = Object.assign(Root$6, {
2359
+ Root: Root$6,
2360
+ Addon
2361
+ });
2362
+ injectComponentStyle("input-group");
2363
+ //#endregion
849
2364
  //#region src/components/json-tree-view/index.tsx
850
2365
  /** Ark's JsonTreeView, dressed in the paper-and-ink system: the tree-view
851
2366
  * recipes re-scoped, with value nodes reading as tabular data. The API is
@@ -864,6 +2379,136 @@ function Kbd({ children, ...rest }) {
864
2379
  }
865
2380
  injectComponentStyle("kbd");
866
2381
  //#endregion
2382
+ //#region src/components/layout/index.tsx
2383
+ const LAYOUT_CONTEXT = createContext(null);
2384
+ /**
2385
+ * The application skeleton: Root, Header, Sider, Content, Footer —
2386
+ * the admin arrangement (Element Plus / AntD keep the same anatomy)
2387
+ * dressed in the paper-and-ink surfaces. The root is a full-height
2388
+ * grid; a declared `sider` turns the columns around to meet whichever
2389
+ * edge the rail stands on.
2390
+ */
2391
+ function Root$5({ sider, children, ...rest }) {
2392
+ return /* @__PURE__ */ jsx(LAYOUT_CONTEXT.Provider, {
2393
+ value: { siderPlacement: () => sider },
2394
+ children: /* @__PURE__ */ jsx("div", {
2395
+ ...rest,
2396
+ "data-scope": "layout",
2397
+ "data-part": "root",
2398
+ "data-sider": sider,
2399
+ children
2400
+ })
2401
+ });
2402
+ }
2403
+ /** A semantic block of the skeleton — header, footer, and the flow's
2404
+ * main content each land on their native element and their grid area. */
2405
+ function region(name, tag) {
2406
+ const Tag = tag;
2407
+ const Component = ({ children, ...rest }) => /* @__PURE__ */ jsx(Tag, {
2408
+ ...rest,
2409
+ "data-scope": "layout",
2410
+ "data-part": name.toLowerCase(),
2411
+ children
2412
+ });
2413
+ Component.displayName = "Layout" + name;
2414
+ return Component;
2415
+ }
2416
+ const Header = region("Header", "header");
2417
+ const Content$2 = region("Content", "main");
2418
+ const Footer = region("Footer", "footer");
2419
+ /** One step of the arrow-key resize, in px. */
2420
+ const RESIZE_STEP = 16;
2421
+ function Sider({ collapsed = false, width: widthProp, collapsedWidth = "3.5rem", resizable = false, minWidth = "12rem", maxWidth = "24rem", style, onCollapsedChange, onWidthChange, children, ...rest }) {
2422
+ const layout = useContext(LAYOUT_CONTEXT);
2423
+ const rail = useRef(null);
2424
+ const [dragging, setDragging] = useState(false);
2425
+ const [innerWidth, setInnerWidth] = useState(widthProp ?? "16rem");
2426
+ const width = widthProp !== void 0 ? widthProp : innerWidth;
2427
+ const prevCollapsed = useRef(collapsed);
2428
+ useEffect(() => {
2429
+ if (prevCollapsed.current === collapsed) return;
2430
+ prevCollapsed.current = collapsed;
2431
+ onCollapsedChange?.(collapsed);
2432
+ }, [collapsed, onCollapsedChange]);
2433
+ const innerWidthRef = useRef(innerWidth);
2434
+ innerWidthRef.current = innerWidth;
2435
+ useEffect(() => {
2436
+ if (widthProp === void 0 || widthProp === innerWidthRef.current) return;
2437
+ setInnerWidth(widthProp);
2438
+ onWidthChange?.(widthProp);
2439
+ }, [widthProp, onWidthChange]);
2440
+ const applyWidth = (next) => {
2441
+ setInnerWidth(next);
2442
+ onWidthChange?.(next);
2443
+ };
2444
+ const dragStart = useRef({
2445
+ x: 0,
2446
+ width: 0
2447
+ });
2448
+ const onPointerDown = (event) => {
2449
+ setDragging(true);
2450
+ dragStart.current = {
2451
+ x: event.clientX,
2452
+ width: rail.current ? rail.current.getBoundingClientRect().width : 0
2453
+ };
2454
+ event.currentTarget.setPointerCapture(event.pointerId);
2455
+ };
2456
+ const onPointerMove = (event) => {
2457
+ if (!dragging) return;
2458
+ const towardFlow = (layout?.siderPlacement() ?? "start") === "end" ? -1 : 1;
2459
+ applyWidth(`${Math.round(dragStart.current.width + towardFlow * (event.clientX - dragStart.current.x))}px`);
2460
+ };
2461
+ const onPointerUp = (event) => {
2462
+ setDragging(false);
2463
+ event.currentTarget.releasePointerCapture(event.pointerId);
2464
+ };
2465
+ const onKeyDown = (event) => {
2466
+ if (event.key !== "ArrowLeft" && event.key !== "ArrowRight") return;
2467
+ event.preventDefault();
2468
+ const widen = (layout?.siderPlacement() ?? "start") === "end" ? event.key === "ArrowLeft" : event.key === "ArrowRight";
2469
+ const current = rail.current ? rail.current.getBoundingClientRect().width : 0;
2470
+ applyWidth(`${Math.round(current + (widen ? RESIZE_STEP : -16))}px`);
2471
+ };
2472
+ const handle = resizable && !collapsed ? /* @__PURE__ */ jsx("div", {
2473
+ "data-scope": "layout",
2474
+ "data-part": "sider-resize",
2475
+ "data-dragging": dragging ? "" : void 0,
2476
+ role: "separator",
2477
+ "aria-orientation": "vertical",
2478
+ tabIndex: 0,
2479
+ "aria-label": "Resize sidebar",
2480
+ "aria-valuenow": Math.round(rail.current ? rail.current.getBoundingClientRect().width : 0),
2481
+ onPointerDown,
2482
+ onPointerMove,
2483
+ onPointerUp,
2484
+ onKeyDown
2485
+ }) : null;
2486
+ return /* @__PURE__ */ jsxs("aside", {
2487
+ ...rest,
2488
+ ref: rail,
2489
+ style: {
2490
+ ...style,
2491
+ "--bs-layout-sider-width": collapsed ? collapsedWidth : width,
2492
+ "--bs-layout-sider-min": collapsed ? collapsedWidth : minWidth,
2493
+ "--bs-layout-sider-max": collapsed ? collapsedWidth : maxWidth
2494
+ },
2495
+ "data-scope": "layout",
2496
+ "data-part": "sider",
2497
+ "data-collapsed": collapsed ? "" : void 0,
2498
+ "data-dragging": dragging ? "" : void 0,
2499
+ "data-resizable": resizable ? "" : void 0,
2500
+ children: [typeof children === "function" ? children({ collapsed }) : children, handle]
2501
+ });
2502
+ }
2503
+ const Layout = Object.assign(Root$5, {
2504
+ Root: Root$5,
2505
+ Header,
2506
+ Sider,
2507
+ Content: Content$2,
2508
+ Footer
2509
+ });
2510
+ injectComponentStyle("layout");
2511
+ //#endregion
867
2512
  //#region src/components/link/index.tsx
868
2513
  /** A link is ink in the accent's voice: quiet at rest, deepening under
869
2514
  * the hand, the halo at focus. The underline follows the prose —
@@ -879,6 +2524,69 @@ function Link({ underline = "hover", children, ...rest }) {
879
2524
  }
880
2525
  injectComponentStyle("link");
881
2526
  //#endregion
2527
+ //#region src/components/list/index.tsx
2528
+ /** A ledger of rows: Root is the list, Item one row, Leading the mark
2529
+ * before the words, Content the title and its quiet echo, Actions the
2530
+ * way out. The bordered variant draws the hairlines; the hoverable
2531
+ * variant gives every row the wash — and any row the caller makes
2532
+ * clickable (role="button") answers the pointer on its own. */
2533
+ function part$5(name, tag) {
2534
+ const Tag = tag;
2535
+ function Component({ children, ...rest }) {
2536
+ return /* @__PURE__ */ jsx(Tag, {
2537
+ ...rest,
2538
+ "data-scope": "list",
2539
+ "data-part": name.toLowerCase(),
2540
+ children
2541
+ });
2542
+ }
2543
+ Component.displayName = "List" + name;
2544
+ return Component;
2545
+ }
2546
+ function Root$4({ bordered = false, hoverable = false, children, ...rest }) {
2547
+ return /* @__PURE__ */ jsx("ul", {
2548
+ ...rest,
2549
+ "data-scope": "list",
2550
+ "data-part": "root",
2551
+ "data-bordered": bordered || void 0,
2552
+ "data-hoverable": hoverable || void 0,
2553
+ children
2554
+ });
2555
+ }
2556
+ Root$4.displayName = "ListRoot";
2557
+ const Item$1 = part$5("Item", "li");
2558
+ const Leading = part$5("Leading", "div");
2559
+ const Actions$1 = part$5("Actions", "div");
2560
+ function Content$1({ title, description, children, ...rest }) {
2561
+ return /* @__PURE__ */ jsxs("div", {
2562
+ ...rest,
2563
+ "data-scope": "list",
2564
+ "data-part": "content",
2565
+ children: [
2566
+ title ? /* @__PURE__ */ jsx("div", {
2567
+ "data-scope": "list",
2568
+ "data-part": "title",
2569
+ children: title
2570
+ }) : null,
2571
+ description ? /* @__PURE__ */ jsx("div", {
2572
+ "data-scope": "list",
2573
+ "data-part": "description",
2574
+ children: description
2575
+ }) : null,
2576
+ children
2577
+ ]
2578
+ });
2579
+ }
2580
+ Content$1.displayName = "ListContent";
2581
+ const List = Object.assign(Root$4, {
2582
+ Root: Root$4,
2583
+ Item: Item$1,
2584
+ Leading,
2585
+ Content: Content$1,
2586
+ Actions: Actions$1
2587
+ });
2588
+ injectComponentStyle("list");
2589
+ //#endregion
882
2590
  //#region src/components/listbox/index.tsx
883
2591
  /** Ark's Listbox, dressed in the paper-and-ink system: quiet rows of ink
884
2592
  * where the checked row alone takes the flat primary fill. The API is
@@ -895,6 +2603,32 @@ injectComponentStyle("listbox");
895
2603
  const Marquee = Marquee$1;
896
2604
  injectComponentStyle("marquee");
897
2605
  //#endregion
2606
+ //#region src/components/masonry/index.tsx
2607
+ /** The same named steps of the space ramp the stack uses — one
2608
+ * vocabulary of distance across the layout primitives. */
2609
+ const gapVars$1 = {
2610
+ none: "0",
2611
+ xs: "var(--bs-gap-xs)",
2612
+ sm: "var(--bs-gap-sm)",
2613
+ md: "var(--bs-gap-md)",
2614
+ lg: "var(--bs-gap-lg)",
2615
+ xl: "var(--bs-gap-xl)"
2616
+ };
2617
+ function Masonry({ columns = 3, gap = "md", ...rest }) {
2618
+ const style = {
2619
+ ...rest.style,
2620
+ "--bs-masonry-columns": String(columns),
2621
+ "--bs-masonry-gap": gapVars$1[gap] ?? gapVars$1.md
2622
+ };
2623
+ return /* @__PURE__ */ jsx("div", {
2624
+ ...rest,
2625
+ style,
2626
+ "data-scope": "masonry",
2627
+ "data-part": "root"
2628
+ });
2629
+ }
2630
+ injectComponentStyle("masonry");
2631
+ //#endregion
898
2632
  //#region src/components/menu/index.tsx
899
2633
  /** Ark's Menu, dressed in the paper-and-ink system: a quiet paper vessel on
900
2634
  * elevation, hover as light on the row, checked items as the flat ink fill.
@@ -904,6 +2638,36 @@ injectComponentStyle("marquee");
904
2638
  const Menu = Menu$1;
905
2639
  injectComponentStyle("menu");
906
2640
  //#endregion
2641
+ //#region src/components/menubar/index.tsx
2642
+ function Menubar({ items, onSelect, children, ...rest }) {
2643
+ return /* @__PURE__ */ jsxs("div", {
2644
+ ...rest,
2645
+ "data-scope": "menubar",
2646
+ "data-part": "root",
2647
+ role: "menubar",
2648
+ children: [items.map((group) => /* @__PURE__ */ jsxs(Menu$1.Root, {
2649
+ positioning: { placement: "bottom-start" },
2650
+ children: [/* @__PURE__ */ jsx(Menu$1.Trigger, {
2651
+ asChild: true,
2652
+ children: /* @__PURE__ */ jsx("button", {
2653
+ type: "button",
2654
+ "data-scope": "menubar",
2655
+ "data-part": "trigger",
2656
+ children: group.label
2657
+ })
2658
+ }), /* @__PURE__ */ jsx(Portal, { children: /* @__PURE__ */ jsx(Menu$1.Positioner, { children: /* @__PURE__ */ jsx(Menu$1.Content, { children: group.items.map((entry) => /* @__PURE__ */ jsx(Menu$1.Item, {
2659
+ value: entry.value,
2660
+ disabled: entry.disabled,
2661
+ "data-danger": entry.danger ? "" : void 0,
2662
+ onSelect: () => onSelect?.(entry.value),
2663
+ children: /* @__PURE__ */ jsx(Menu$1.ItemText, { children: entry.label })
2664
+ }, entry.value)) }) }) })]
2665
+ }, group.label)), children]
2666
+ });
2667
+ }
2668
+ injectComponentStyle("menubar");
2669
+ injectComponentStyle("menu");
2670
+ //#endregion
907
2671
  //#region src/components/meter/index.tsx
908
2672
  function part$4(name, tag) {
909
2673
  const Tag = tag;
@@ -918,7 +2682,7 @@ function part$4(name, tag) {
918
2682
  }
919
2683
  const Label$2 = part$4("Label", "span");
920
2684
  const ValueText = part$4("ValueText", "span");
921
- const Track = ({ children, ...rest }) => /* @__PURE__ */ jsx("span", {
2685
+ const Track = ({ ...rest }) => /* @__PURE__ */ jsx("span", {
922
2686
  ...rest,
923
2687
  "data-scope": "meter",
924
2688
  "data-part": "track",
@@ -1000,6 +2764,43 @@ injectComponentStyle("password-input");
1000
2764
  const PinInput = PinInput$1;
1001
2765
  injectComponentStyle("pin-input");
1002
2766
  //#endregion
2767
+ //#region src/components/popconfirm/index.tsx
2768
+ function Popconfirm({ message, confirmText = "Confirm", cancelText = "Cancel", children, onConfirm, onCancel }) {
2769
+ const [open, setOpen] = useState(false);
2770
+ function settle(confirmed) {
2771
+ setOpen(false);
2772
+ (confirmed ? onConfirm : onCancel)?.();
2773
+ }
2774
+ return /* @__PURE__ */ jsxs(Popover$1.Root, {
2775
+ open,
2776
+ onOpenChange: (details) => setOpen(details.open),
2777
+ positioning: { placement: "top" },
2778
+ children: [/* @__PURE__ */ jsx(Popover$1.Trigger, {
2779
+ asChild: true,
2780
+ children
2781
+ }), /* @__PURE__ */ jsx(Portal, { children: /* @__PURE__ */ jsx(Popover$1.Positioner, { children: /* @__PURE__ */ jsxs(Popover$1.Content, {
2782
+ className: "bs-popconfirm",
2783
+ children: [/* @__PURE__ */ jsx("p", {
2784
+ "data-part": "message",
2785
+ children: message
2786
+ }), /* @__PURE__ */ jsxs("div", {
2787
+ "data-part": "actions",
2788
+ children: [/* @__PURE__ */ jsx(Button, {
2789
+ variant: "ghost",
2790
+ size: "sm",
2791
+ onClick: () => settle(false),
2792
+ children: cancelText
2793
+ }), /* @__PURE__ */ jsx(Button, {
2794
+ size: "sm",
2795
+ onClick: () => settle(true),
2796
+ children: confirmText
2797
+ })]
2798
+ })]
2799
+ }) }) })]
2800
+ });
2801
+ }
2802
+ injectComponentStyle("popconfirm");
2803
+ //#endregion
1003
2804
  //#region src/components/popover/index.tsx
1004
2805
  /** Ark's Popover, dressed in the paper-and-ink system: a paper vessel that
1005
2806
  * dissolves in on elevation, anchored to its trigger by a whisker arrow. The
@@ -1016,6 +2817,59 @@ injectComponentStyle("popover");
1016
2817
  const Progress = Progress$1;
1017
2818
  injectComponentStyle("progress");
1018
2819
  //#endregion
2820
+ //#region src/components/progress-group/index.tsx
2821
+ function ProgressGroup({ segments, max, showLegend = true, ...rest }) {
2822
+ const total = max ?? segments.reduce((sum, segment) => sum + segment.value, 0);
2823
+ const share = (value) => total > 0 ? `${value / total * 100}%` : "0%";
2824
+ const nameOf = (segment, index) => segment.label ?? segment.pigment ?? `Segment ${index + 1}`;
2825
+ return /* @__PURE__ */ jsxs("div", {
2826
+ ...rest,
2827
+ "data-scope": "progress-group",
2828
+ "data-part": "root",
2829
+ children: [/* @__PURE__ */ jsx("div", {
2830
+ "data-scope": "progress-group",
2831
+ "data-part": "track",
2832
+ children: segments.map((segment, index) => /* @__PURE__ */ jsx("div", {
2833
+ "data-scope": "progress-group",
2834
+ "data-part": "segment",
2835
+ "data-pigment": segment.pigment,
2836
+ role: "progressbar",
2837
+ "aria-valuenow": segment.value,
2838
+ "aria-valuemin": 0,
2839
+ "aria-valuemax": total,
2840
+ "aria-label": nameOf(segment, index),
2841
+ style: { inlineSize: share(segment.value) }
2842
+ }, index))
2843
+ }), showLegend ? /* @__PURE__ */ jsx("div", {
2844
+ "data-scope": "progress-group",
2845
+ "data-part": "legend",
2846
+ children: segments.map((segment, index) => /* @__PURE__ */ jsxs("div", {
2847
+ "data-scope": "progress-group",
2848
+ "data-part": "legend-item",
2849
+ "data-pigment": segment.pigment,
2850
+ children: [
2851
+ /* @__PURE__ */ jsx("span", {
2852
+ "data-scope": "progress-group",
2853
+ "data-part": "swatch",
2854
+ "aria-hidden": "true"
2855
+ }),
2856
+ /* @__PURE__ */ jsx("span", {
2857
+ "data-scope": "progress-group",
2858
+ "data-part": "legend-label",
2859
+ children: nameOf(segment, index)
2860
+ }),
2861
+ /* @__PURE__ */ jsx("span", {
2862
+ "data-scope": "progress-group",
2863
+ "data-part": "legend-value",
2864
+ children: String(segment.value)
2865
+ })
2866
+ ]
2867
+ }, index))
2868
+ }) : null]
2869
+ });
2870
+ }
2871
+ injectComponentStyle("progress-group");
2872
+ //#endregion
1019
2873
  //#region src/components/qr-code/index.tsx
1020
2874
  /** Ark's QrCode, dressed in the paper-and-ink system: the pattern prints in
1021
2875
  * ink on the page, with an optional paper badge and a seal-cut download
@@ -1103,6 +2957,71 @@ injectComponentStyle("skeleton");
1103
2957
  const Slider = Slider$1;
1104
2958
  injectComponentStyle("slider");
1105
2959
  //#endregion
2960
+ //#region src/components/split-button/index.tsx
2961
+ /**
2962
+ * A primary action with its alternatives one seam away: the main button
2963
+ * fires `onClick`, the fitted arrow opens a paper vessel of the same
2964
+ * register whose entries report `onSelect` with their value. The arrow
2965
+ * is the menu machine's trigger grafting the button recipe — the
2966
+ * machine keeps the element (positioning, focus, `data-state`), the
2967
+ * button stylesheet's trigger register dresses it. The popup keeps the
2968
+ * menu parts untouched.
2969
+ */
2970
+ function SplitButton({ label, items = [], variant = "solid", tone = "ink", size = "md", disabled = false, onClick, onSelect, ...rest }) {
2971
+ return /* @__PURE__ */ jsxs("div", {
2972
+ ...rest,
2973
+ "data-scope": "split-button",
2974
+ "data-part": "root",
2975
+ children: [/* @__PURE__ */ jsx(Button, {
2976
+ variant,
2977
+ tone,
2978
+ size,
2979
+ disabled,
2980
+ onClick,
2981
+ children: label
2982
+ }), /* @__PURE__ */ jsxs(Menu$1.Root, {
2983
+ positioning: { placement: "bottom-end" },
2984
+ children: [/* @__PURE__ */ jsx(Menu$1.Trigger, {
2985
+ asChild: true,
2986
+ children: /* @__PURE__ */ jsx("button", {
2987
+ type: "button",
2988
+ disabled,
2989
+ "data-variant": variant,
2990
+ "data-tone": tone,
2991
+ "data-size": size,
2992
+ "data-square": "true",
2993
+ "data-motion": "ink-ripple lit",
2994
+ "aria-label": "More actions",
2995
+ children: chevronDown$1()
2996
+ })
2997
+ }), /* @__PURE__ */ jsx(Portal, { children: /* @__PURE__ */ jsx(Menu$1.Positioner, { children: /* @__PURE__ */ jsx(Menu$1.Content, { children: items.map((entry) => /* @__PURE__ */ jsx(Menu$1.Item, {
2998
+ value: entry.value,
2999
+ disabled: entry.disabled,
3000
+ "data-danger": entry.danger ? "" : void 0,
3001
+ onSelect: () => onSelect?.(entry.value),
3002
+ children: /* @__PURE__ */ jsx(Menu$1.ItemText, { children: entry.label })
3003
+ }, entry.value)) }) }) })]
3004
+ })]
3005
+ });
3006
+ }
3007
+ /** One stroke pointing down: all a fitted dropdown arrow needs. */
3008
+ function chevronDown$1() {
3009
+ return /* @__PURE__ */ jsx("svg", {
3010
+ width: 16,
3011
+ height: 16,
3012
+ viewBox: "0 0 24 24",
3013
+ fill: "none",
3014
+ stroke: "currentColor",
3015
+ strokeWidth: 1.75,
3016
+ strokeLinecap: "round",
3017
+ strokeLinejoin: "round",
3018
+ "aria-hidden": "true",
3019
+ children: /* @__PURE__ */ jsx("path", { d: "m6 9 6 6 6-6" })
3020
+ });
3021
+ }
3022
+ injectComponentStyle("split-button");
3023
+ injectComponentStyle("menu");
3024
+ //#endregion
1106
3025
  //#region src/components/splitter/index.tsx
1107
3026
  /** Ark's Splitter, dressed in the paper-and-ink system: panels divide on
1108
3027
  * a hairline and a small paper-seal thumb answers the hand. The API is
@@ -1110,6 +3029,35 @@ injectComponentStyle("slider");
1110
3029
  const Splitter = Splitter$1;
1111
3030
  injectComponentStyle("splitter");
1112
3031
  //#endregion
3032
+ //#region src/components/stack/index.tsx
3033
+ /** Whitespace chosen by name: the named steps point at the space ramp so
3034
+ * siblings are held apart by one token, never by ad-hoc margins. */
3035
+ const gapVars = {
3036
+ none: "0",
3037
+ xs: "var(--bs-gap-xs)",
3038
+ sm: "var(--bs-gap-sm)",
3039
+ md: "var(--bs-gap-md)",
3040
+ lg: "var(--bs-gap-lg)",
3041
+ xl: "var(--bs-gap-xl)"
3042
+ };
3043
+ function Stack({ direction = "column", gap = "md", wrap = false, align, justify, ...rest }) {
3044
+ const style = {
3045
+ ...rest.style,
3046
+ "--bs-stack-gap": gapVars[gap] ?? gapVars.md,
3047
+ alignItems: align,
3048
+ justifyContent: justify,
3049
+ flexWrap: wrap ? "wrap" : void 0
3050
+ };
3051
+ return /* @__PURE__ */ jsx("div", {
3052
+ ...rest,
3053
+ style,
3054
+ "data-scope": "stack",
3055
+ "data-part": "root",
3056
+ "data-direction": direction
3057
+ });
3058
+ }
3059
+ injectComponentStyle("stack");
3060
+ //#endregion
1113
3061
  //#region src/components/page-header/index.tsx
1114
3062
  /** The page's face: an eyebrow whisper, a serif title, one line of
1115
3063
  * description, and the actions resting beside the title on the same
@@ -1902,6 +3850,22 @@ function DataTable(rawProps) {
1902
3850
  }
1903
3851
  injectComponentStyle("table");
1904
3852
  //#endregion
3853
+ //#region src/components/textarea/index.tsx
3854
+ function Textarea({ value, invalid = false, onValueChange, ...rest }) {
3855
+ const field = useFieldContext();
3856
+ const fieldProps = field?.getTextareaProps() ?? {};
3857
+ return /* @__PURE__ */ jsx("textarea", {
3858
+ ...fieldProps,
3859
+ ...rest,
3860
+ ...value !== void 0 ? { value } : {},
3861
+ "data-scope": "textarea",
3862
+ "data-part": "root",
3863
+ "data-invalid": invalid || field?.invalid ? "" : void 0,
3864
+ onChange: (event) => onValueChange?.(event.target.value)
3865
+ });
3866
+ }
3867
+ injectComponentStyle("textarea");
3868
+ //#endregion
1905
3869
  //#region src/components/timeline/index.tsx
1906
3870
  /** A line of moments: Root is the ordered thread, Item one moment on it,
1907
3871
  * Marker the point where the thread passes, Content what the moment
@@ -2016,6 +3980,255 @@ injectComponentStyle("tooltip");
2016
3980
  const Tour = Tour$1;
2017
3981
  injectComponentStyle("tour");
2018
3982
  //#endregion
3983
+ //#region src/components/transfer/index.tsx
3984
+ const checkGlyph = /* @__PURE__ */ jsx("svg", {
3985
+ viewBox: "0 0 24 24",
3986
+ fill: "none",
3987
+ stroke: "currentColor",
3988
+ strokeWidth: 3,
3989
+ strokeLinecap: "round",
3990
+ strokeLinejoin: "round",
3991
+ "aria-hidden": "true",
3992
+ children: /* @__PURE__ */ jsx("path", { d: "m5 12.5 5 5L19 7" })
3993
+ });
3994
+ function arrowGlyph(direction) {
3995
+ return /* @__PURE__ */ jsx("svg", {
3996
+ viewBox: "0 0 24 24",
3997
+ fill: "none",
3998
+ stroke: "currentColor",
3999
+ strokeWidth: 1.75,
4000
+ strokeLinecap: "round",
4001
+ strokeLinejoin: "round",
4002
+ "aria-hidden": "true",
4003
+ children: /* @__PURE__ */ jsx("path", { d: direction === "right" ? "M5 12h14m-6-6 6 6-6 6" : "M19 12H5m6-6-6 6 6 6" })
4004
+ });
4005
+ }
4006
+ /**
4007
+ * Two ledgers and a crossing: items sit in the source column until the
4008
+ * reader checks them and walks them across — and back, the same way.
4009
+ * `value` is the target column's value list; everything else in `data`
4010
+ * stays on the left. `searchable` adds a filter line to each panel.
4011
+ */
4012
+ function Transfer({ value = [], data, titles = ["Source", "Target"], searchable = false, disabled = false, onValueChange, ...rest }) {
4013
+ const [checkedSource, setCheckedSource] = useState(() => /* @__PURE__ */ new Set());
4014
+ const [checkedTarget, setCheckedTarget] = useState(() => /* @__PURE__ */ new Set());
4015
+ const [sourceQuery, setSourceQuery] = useState("");
4016
+ const [targetQuery, setTargetQuery] = useState("");
4017
+ const target = new Set(value);
4018
+ function panelItems(values, inTarget, query) {
4019
+ return values.filter((item) => item.label.toLowerCase().includes(query.toLowerCase()) && target.has(item.value) === inTarget);
4020
+ }
4021
+ function toggle(side, option) {
4022
+ (side === "source" ? setCheckedSource : setCheckedTarget)((prev) => {
4023
+ const next = new Set(prev);
4024
+ if (next.has(option)) next.delete(option);
4025
+ else next.add(option);
4026
+ return next;
4027
+ });
4028
+ }
4029
+ function move(toTarget) {
4030
+ const moving = toTarget ? checkedSource : checkedTarget;
4031
+ if (moving.size === 0) return;
4032
+ const next = toTarget ? [...value, ...moving].filter((entry, index, all) => all.indexOf(entry) === index) : value.filter((entry) => !moving.has(entry));
4033
+ if (toTarget) setCheckedSource(/* @__PURE__ */ new Set());
4034
+ else setCheckedTarget(/* @__PURE__ */ new Set());
4035
+ onValueChange?.(next);
4036
+ }
4037
+ function panel(side, title, query, onQuery, checked, items) {
4038
+ return /* @__PURE__ */ jsxs("div", {
4039
+ "data-scope": "transfer",
4040
+ "data-part": "panel",
4041
+ "data-side": side,
4042
+ children: [
4043
+ /* @__PURE__ */ jsxs("div", {
4044
+ "data-scope": "transfer",
4045
+ "data-part": "head",
4046
+ children: [/* @__PURE__ */ jsx("span", {
4047
+ "data-scope": "transfer",
4048
+ "data-part": "title",
4049
+ children: title
4050
+ }), /* @__PURE__ */ jsx("span", {
4051
+ "data-scope": "transfer",
4052
+ "data-part": "count",
4053
+ children: items.length
4054
+ })]
4055
+ }),
4056
+ searchable ? /* @__PURE__ */ jsx("div", {
4057
+ "data-scope": "transfer",
4058
+ "data-part": "search",
4059
+ children: /* @__PURE__ */ jsx(Input, {
4060
+ size: "sm",
4061
+ value: query,
4062
+ onValueChange: onQuery,
4063
+ placeholder: "Filter…",
4064
+ "aria-label": `Filter ${title}`
4065
+ })
4066
+ }) : null,
4067
+ /* @__PURE__ */ jsx("div", {
4068
+ "data-scope": "transfer",
4069
+ "data-part": "list",
4070
+ children: items.length === 0 ? /* @__PURE__ */ jsx("p", {
4071
+ "data-scope": "transfer",
4072
+ "data-part": "empty",
4073
+ children: "Nothing here"
4074
+ }) : items.map((item) => {
4075
+ const locked = disabled || item.disabled === true;
4076
+ return /* @__PURE__ */ jsxs(Checkbox$1.Root, {
4077
+ checked: checked.has(item.value),
4078
+ disabled: locked,
4079
+ onCheckedChange: () => toggle(side, item.value),
4080
+ children: [
4081
+ /* @__PURE__ */ jsx(Checkbox$1.Control, { children: /* @__PURE__ */ jsx(Checkbox$1.Indicator, { children: checkGlyph }) }),
4082
+ /* @__PURE__ */ jsx(Checkbox$1.Label, {
4083
+ "data-part": "label",
4084
+ children: item.label
4085
+ }),
4086
+ /* @__PURE__ */ jsx(Checkbox$1.HiddenInput, {})
4087
+ ]
4088
+ }, item.value);
4089
+ })
4090
+ })
4091
+ ]
4092
+ });
4093
+ }
4094
+ const items = panelItems(data, false, sourceQuery);
4095
+ const targetItems = panelItems(data, true, targetQuery);
4096
+ return /* @__PURE__ */ jsxs("div", {
4097
+ ...rest,
4098
+ "data-scope": "transfer",
4099
+ "data-part": "root",
4100
+ children: [
4101
+ panel("source", titles[0], sourceQuery, setSourceQuery, checkedSource, items),
4102
+ /* @__PURE__ */ jsxs("div", {
4103
+ "data-scope": "transfer",
4104
+ "data-part": "operations",
4105
+ children: [/* @__PURE__ */ jsx(Button, {
4106
+ variant: "outline",
4107
+ size: "sm",
4108
+ square: true,
4109
+ disabled: checkedSource.size === 0 || disabled,
4110
+ "aria-label": "Move right",
4111
+ onClick: () => move(true),
4112
+ children: arrowGlyph("right")
4113
+ }), /* @__PURE__ */ jsx(Button, {
4114
+ variant: "outline",
4115
+ size: "sm",
4116
+ square: true,
4117
+ disabled: checkedTarget.size === 0 || disabled,
4118
+ "aria-label": "Move left",
4119
+ onClick: () => move(false),
4120
+ children: arrowGlyph("left")
4121
+ })]
4122
+ }),
4123
+ panel("target", titles[1], targetQuery, setTargetQuery, checkedTarget, targetItems)
4124
+ ]
4125
+ });
4126
+ }
4127
+ injectComponentStyle("transfer");
4128
+ injectComponentStyle("checkbox");
4129
+ //#endregion
4130
+ //#region src/components/tree-select/index.tsx
4131
+ const chevron = /* @__PURE__ */ jsx("svg", {
4132
+ viewBox: "0 0 24 24",
4133
+ fill: "none",
4134
+ stroke: "currentColor",
4135
+ strokeWidth: 2,
4136
+ strokeLinecap: "round",
4137
+ strokeLinejoin: "round",
4138
+ "aria-hidden": "true",
4139
+ children: /* @__PURE__ */ jsx("path", { d: "m9 18 6-6-6-6" })
4140
+ });
4141
+ const chevronDown = /* @__PURE__ */ jsx("span", {
4142
+ "data-part": "chevron",
4143
+ "aria-hidden": "true",
4144
+ children: chevron
4145
+ });
4146
+ function TreeSelectRow({ node, indexPath }) {
4147
+ return /* @__PURE__ */ jsx(TreeView$1.NodeProvider, {
4148
+ node,
4149
+ indexPath,
4150
+ children: node.children ? /* @__PURE__ */ jsxs(TreeView$1.Branch, { children: [/* @__PURE__ */ jsxs(TreeView$1.BranchControl, { children: [/* @__PURE__ */ jsx(TreeView$1.BranchIndicator, { children: chevron }), /* @__PURE__ */ jsx(TreeView$1.BranchText, { children: node.label })] }), /* @__PURE__ */ jsxs(TreeView$1.BranchContent, { children: [/* @__PURE__ */ jsx(TreeView$1.BranchIndentGuide, {}), node.children.map((child, index) => /* @__PURE__ */ jsx(TreeSelectRow, {
4151
+ node: child,
4152
+ indexPath: [...indexPath, index]
4153
+ }, child.value))] })] }) : /* @__PURE__ */ jsx(TreeView$1.Item, {
4154
+ asChild: true,
4155
+ children: /* @__PURE__ */ jsx("span", {
4156
+ style: {
4157
+ display: "flex",
4158
+ inlineSize: "100%"
4159
+ },
4160
+ children: /* @__PURE__ */ jsx(TreeView$1.ItemText, { children: node.label })
4161
+ })
4162
+ })
4163
+ });
4164
+ }
4165
+ function TreeSelect({ value, data, placeholder = "Select…", disabled = false, onValueChange, ...rest }) {
4166
+ const [open, setOpen] = useState(false);
4167
+ const collection = createTreeCollection$1({
4168
+ nodeToValue: (node) => node.value,
4169
+ nodeToString: (node) => node.label,
4170
+ rootNode: {
4171
+ value: "ROOT",
4172
+ label: "",
4173
+ children: data
4174
+ }
4175
+ });
4176
+ const firstLevel = data.map((node) => node.value);
4177
+ let found;
4178
+ const walk = (nodes) => {
4179
+ for (const node of nodes ?? []) {
4180
+ if (node.value === value) found = node.label;
4181
+ walk(node.children);
4182
+ }
4183
+ };
4184
+ walk(data);
4185
+ const label = found;
4186
+ function pick(details) {
4187
+ const [selected] = details.selectedValue;
4188
+ if (selected == null) return;
4189
+ onValueChange?.(selected);
4190
+ setOpen(false);
4191
+ }
4192
+ return /* @__PURE__ */ jsxs(Popover$1.Root, {
4193
+ ...rest,
4194
+ open,
4195
+ onOpenChange: (details) => setOpen(details.open),
4196
+ positioning: {
4197
+ sameWidth: true,
4198
+ placement: "bottom-start"
4199
+ },
4200
+ children: [/* @__PURE__ */ jsx(Popover$1.Trigger, {
4201
+ asChild: true,
4202
+ disabled,
4203
+ children: /* @__PURE__ */ jsxs("button", {
4204
+ type: "button",
4205
+ "data-scope": "tree-select",
4206
+ "data-part": "control",
4207
+ "data-open": open ? "" : void 0,
4208
+ "data-placeholder": label == null ? "" : void 0,
4209
+ disabled,
4210
+ children: [label ?? placeholder, chevronDown]
4211
+ })
4212
+ }), /* @__PURE__ */ jsx(Portal, { children: /* @__PURE__ */ jsx(Popover$1.Positioner, { children: /* @__PURE__ */ jsx(Popover$1.Content, {
4213
+ "data-scope": "tree-select",
4214
+ "data-part": "content",
4215
+ children: /* @__PURE__ */ jsx(TreeView$1.Root, {
4216
+ collection,
4217
+ selectionMode: "single",
4218
+ selectedValue: value ? [value] : [],
4219
+ defaultExpandedValue: firstLevel,
4220
+ onSelectionChange: pick,
4221
+ children: /* @__PURE__ */ jsx(TreeView$1.Tree, { children: collection.rootNode.children?.map((node, index) => /* @__PURE__ */ jsx(TreeSelectRow, {
4222
+ node,
4223
+ indexPath: [index]
4224
+ }, node.value)) })
4225
+ })
4226
+ }) }) })]
4227
+ });
4228
+ }
4229
+ injectComponentStyle("tree-select");
4230
+ injectComponentStyle("tree-view");
4231
+ //#endregion
2019
4232
  //#region src/components/tree-view/index.tsx
2020
4233
  /** Ark's TreeView, dressed in the paper-and-ink system: quiet rows where
2021
4234
  * selection is pure light on the paper, one hairline plumb line per depth,
@@ -2027,4 +4240,80 @@ injectComponentStyle("tour");
2027
4240
  const TreeView = TreeView$1;
2028
4241
  injectComponentStyle("tree-view");
2029
4242
  //#endregion
2030
- export { Accordion, Action, Ai, Alert, AngleSlider, Avatar, AvatarGroup, Badge, Banner, Breadcrumb, Button, Calendar, Card, Carousel, Checkbox, Chip, Clipboard, Collapsible, ColorPicker, Combobox, DataTable, DateInput, DatePicker, Dialog, Drawer, Editable, Empty, Field, Fieldset, FileUpload, FlexRender, FloatingPanel, Format, Frame, Highlight, HoverCard, ImageCropper, JsonTreeView, Kbd, Link, Listbox, Marquee, Menu, Message, Meter, NavigationMenu, NumberInput, PageHeader, Pagination, PasswordInput, PinInput, Popover, Progress, PromptInput, QrCode, RadioGroup, RatingGroup, Reasoning, Response, ScrollArea, SegmentGroup, Select, Separator, SignaturePad, Skeleton, Slider, Source, Spinner, Splitter, Stat, Steps, Suggestion, Swap, Switch, Tabs, TagsInput, Timeline, Timer, Toast, Toaster, Toc, Toggle, ToggleGroup, Tool, Tooltip, Tour, TreeView, Typography, createColumnHelper, createListCollection, createToaster, useTour };
4243
+ //#region src/components/watermark/index.tsx
4244
+ /** Font-relative measures ride the root's own measure; absolute units
4245
+ * pass through untouched — the canvas needs a number, the prop may
4246
+ * speak in CSS. */
4247
+ function toPx(size) {
4248
+ const root = Number.parseFloat(getComputedStyle(document.documentElement).fontSize) || 16;
4249
+ const value = Number.parseFloat(size) || 0;
4250
+ if (size.includes("em")) return value * root;
4251
+ return value;
4252
+ }
4253
+ /**
4254
+ * The paper bears its seal beneath the content: a canvas draws the
4255
+ * text once into a tile (rotated, faint, crisp at the screen's pixel
4256
+ * density) and the marks layer repeats it over the children. The seal
4257
+ * redraws itself when a prop turns — and it never takes a pointer.
4258
+ */
4259
+ function Watermark({ content, opacity = .06, rotate = -20, fontSize = "0.875rem", children, ...rest }) {
4260
+ const [root, setRoot] = useState(null);
4261
+ const [tile, setTile] = useState("");
4262
+ useEffect(() => {
4263
+ if (!root) return;
4264
+ const canvas = document.createElement("canvas");
4265
+ const paint = canvas.getContext("2d");
4266
+ if (!paint) return;
4267
+ const styles = getComputedStyle(root);
4268
+ const fontSizePx = toPx(fontSize);
4269
+ const font = `${styles.fontWeight} ${fontSizePx}px ${styles.fontFamily}`;
4270
+ paint.font = font;
4271
+ const textWidth = paint.measureText(content).width;
4272
+ const margin = fontSizePx;
4273
+ const boxWidth = Math.ceil(textWidth + margin * 2);
4274
+ const boxHeight = Math.ceil(fontSizePx + margin * 2);
4275
+ const radian = rotate * Math.PI / 180;
4276
+ const cos = Math.cos(radian);
4277
+ const sin = Math.sin(radian);
4278
+ const width = Math.ceil(Math.abs(boxWidth * cos) + Math.abs(boxHeight * sin));
4279
+ const height = Math.ceil(Math.abs(boxWidth * sin) + Math.abs(boxHeight * cos));
4280
+ const dpr = window.devicePixelRatio || 1;
4281
+ canvas.width = width * dpr;
4282
+ canvas.height = height * dpr;
4283
+ paint.scale(dpr, dpr);
4284
+ paint.translate(width / 2, height / 2);
4285
+ paint.rotate(radian);
4286
+ paint.globalAlpha = opacity;
4287
+ paint.font = font;
4288
+ paint.textAlign = "center";
4289
+ paint.textBaseline = "middle";
4290
+ paint.fillStyle = styles.getPropertyValue("--bs-color-text-tertiary").trim() || styles.color;
4291
+ paint.fillText(content, 0, 0);
4292
+ setTile(`url(${canvas.toDataURL()})`);
4293
+ }, [
4294
+ root,
4295
+ content,
4296
+ opacity,
4297
+ rotate,
4298
+ fontSize
4299
+ ]);
4300
+ return /* @__PURE__ */ jsxs("div", {
4301
+ ...rest,
4302
+ ref: setRoot,
4303
+ "data-scope": "watermark",
4304
+ "data-part": "root",
4305
+ children: [/* @__PURE__ */ jsx("div", {
4306
+ "data-scope": "watermark",
4307
+ "data-part": "content",
4308
+ children
4309
+ }), /* @__PURE__ */ jsx("div", {
4310
+ "data-scope": "watermark",
4311
+ "data-part": "marks",
4312
+ "aria-hidden": "true",
4313
+ style: { backgroundImage: tile }
4314
+ })]
4315
+ });
4316
+ }
4317
+ injectComponentStyle("watermark");
4318
+ //#endregion
4319
+ export { Accordion, Action, Action as AiAction, Affix, Ai, Attachment as AiAttachment, Attachment, Attachments as AiAttachments, Attachments, Message as AiMessage, Message, PromptInput as AiPromptInput, PromptInput, Reasoning as AiReasoning, Reasoning, Response as AiResponse, Response, Source as AiSource, Source, Sources as AiSources, Sources, Suggestion as AiSuggestion, Suggestion, Tool as AiTool, Tool, Alert, AngleSlider, AspectRatio, AutoComplete, Avatar, AvatarGroup, BackTop, Badge, Banner, Breadcrumb, Button, ButtonGroup, Calendar, Card, Carousel, CascadeSelect, Checkbox, CheckboxGroup, Chip, ClientOnly, Clipboard, Collapsible, ColorPicker, Combobox, Command, Comment, ConfigProvider, Container, DataTable, DateInput, DatePicker, Descriptions, DescriptionsRoot, Dialog, DownloadTrigger, Drawer, DynamicInput, Editable, Ellipsis, Empty, FLOAT_BUTTON_CONTEXT, Field, Fieldset, FileUpload, FlexRender, FloatButton, FloatingPanel, FocusTrap, Form, FormField, Format, Frame, Grid, Highlight, HoverCard, Icon, Image, ImageCropper, ImageViewer, Input, InputGroup, JsonTreeView, Kbd, Layout, Link, List, Listbox, Marquee, Masonry, Mentions, MentionsVessel, Menu, Menubar, Meter, NavigationMenu, NumberInput, PageHeader, Pagination, PasswordInput, PinInput, Popconfirm, Popover, Presence, PresenceProvider, Progress, ProgressGroup, QrCode, RadioGroup, RatingGroup, ScrollArea, SegmentGroup, Select, Separator, SignaturePad, Skeleton, Slider, Spinner, SplitButton, Splitter, Stack, Stat, Steps, Swap, Switch, Tabs, TagsInput, Textarea, Timeline, Timer, Toast, Toaster, Toc, Toggle, ToggleGroup, Tooltip, Tour, Transfer, TreeSelect, TreeView, Typography, Watermark, createColumnHelper, createFileTreeCollection, createGridCollection, createToaster, createTreeCollection, useAsyncList, useConfig, useDownload, useListCollection, useListSelection, useMentions, usePresence, usePresenceContext, useTour };