@apliteni/apliteni-ui 0.116.0 → 0.118.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -271,11 +271,9 @@ function Callout({ variant, icon: icon7 = calloutIcons[variant ?? "neutral"], ch
271
271
  // src/primitives/StatBand.tsx
272
272
  import { useId as useId2 } from "react";
273
273
 
274
- // src/Tooltip.tsx
275
- import { useEffect, useId, useLayoutEffect as useLayoutEffect2, useRef as useRef2, useState } from "react";
276
-
277
274
  // src/tip.ts
278
- function placeTip(host, mark, tip, bound) {
275
+ var TIP_GAP = 8;
276
+ function placeTip(host, mark, tip, bound, placement = "top") {
279
277
  const mrect = mark.getBoundingClientRect();
280
278
  const rect = host.getBoundingClientRect();
281
279
  const view = host.ownerDocument.documentElement;
@@ -296,10 +294,13 @@ function placeTip(host, mark, tip, bound) {
296
294
  clip.right = Math.min(clip.right, edge.right);
297
295
  clip.bottom = Math.min(clip.bottom, edge.bottom);
298
296
  }
299
- const gap = parseFloat(getComputedStyle(tip).getPropertyValue("--ui-tip-gap")) || 8;
297
+ const declared = parseFloat(getComputedStyle(tip).getPropertyValue("--ui-tip-gap"));
298
+ const gap = Number.isFinite(declared) ? declared : TIP_GAP;
300
299
  const above = mrect.top - clip.top;
301
300
  const below = clip.bottom - mrect.bottom;
302
- const isBelow = above < tip.offsetHeight + gap && below > above;
301
+ const prefersBelow = placement === "bottom";
302
+ const flip = prefersBelow ? below < tip.offsetHeight + gap && above > below : above < tip.offsetHeight + gap && below > above;
303
+ const isBelow = prefersBelow !== flip;
303
304
  tip.classList.toggle("is-below", isBelow);
304
305
  const centre = mrect.left + mrect.width / 2;
305
306
  const ideal = centre - tip.offsetWidth / 2;
@@ -310,79 +311,196 @@ function placeTip(host, mark, tip, bound) {
310
311
  }
311
312
 
312
313
  // src/Tooltip.tsx
313
- import { jsx as jsx10, jsxs as jsxs6 } from "react/jsx-runtime";
314
- function Tooltip({ text: text2, children }) {
314
+ import { useEffect, useId, useLayoutEffect as useLayoutEffect2, useRef as useRef2, useState } from "react";
315
+ import { Fragment, jsx as jsx10, jsxs as jsxs6 } from "react/jsx-runtime";
316
+ var DOC_EVENTS = ["pointerdown", "pointercancel", "click", "keydown", "touchend"];
317
+ var CAPTURED = /* @__PURE__ */ new Set(["pointerdown", "pointercancel"]);
318
+ var wirings = /* @__PURE__ */ new WeakMap();
319
+ function wireDocument(doc, handlers) {
320
+ let wiring2 = wirings.get(doc);
321
+ if (!wiring2) {
322
+ const members2 = /* @__PURE__ */ new Set();
323
+ const offs = DOC_EVENTS.map((type) => {
324
+ const relay = (event) => {
325
+ for (const member of [...members2]) member[type](event);
326
+ };
327
+ doc.addEventListener(type, relay, CAPTURED.has(type));
328
+ return () => doc.removeEventListener(type, relay, CAPTURED.has(type));
329
+ });
330
+ wiring2 = { members: members2, off: () => offs.forEach((off2) => off2()) };
331
+ wirings.set(doc, wiring2);
332
+ }
333
+ const { members, off } = wiring2;
334
+ members.add(handlers);
335
+ return () => {
336
+ members.delete(handlers);
337
+ if (members.size) return;
338
+ off();
339
+ wirings.delete(doc);
340
+ };
341
+ }
342
+ var Text = ({ label = "", value = "", detail: detail2 = "" }) => /* @__PURE__ */ jsxs6(Fragment, { children: [
343
+ /* @__PURE__ */ jsx10("span", { className: "ui-tip__label", hidden: !label, children: label }),
344
+ /* @__PURE__ */ jsx10("span", { className: "ui-tip__value", hidden: !value, children: value }),
345
+ /* @__PURE__ */ jsx10("span", { className: "ui-tip__detail", hidden: !detail2, children: detail2 })
346
+ ] });
347
+ function Tooltip({ text: text2, label = text2, value, detail: detail2, placement = "top", children }) {
315
348
  const id = useId();
316
349
  const host = useRef2(null);
317
350
  const trigger = useRef2(null);
318
351
  const tip = useRef2(null);
319
352
  const ignoreMouseUntil = useRef2(0);
320
353
  const touchMoved = useRef2(false);
321
- const [open, setOpen] = useState(false);
322
- const place = () => placeTip(host.current, trigger.current, tip.current);
354
+ const pointerKind = useRef2("");
355
+ const pendingClick = useRef2(null);
356
+ const dismissed = useRef2(null);
357
+ const [mark, setMark] = useState(null);
358
+ const active = useRef2(null);
359
+ active.current = mark;
360
+ const open = mark !== null;
361
+ function close(reset = false) {
362
+ dismissed.current = reset ? null : active.current;
363
+ setMark(null);
364
+ }
365
+ function show(target) {
366
+ if (target && target !== dismissed.current) {
367
+ dismissed.current = null;
368
+ setMark(target);
369
+ }
370
+ }
371
+ function markOf(target) {
372
+ if (!(target instanceof Element)) return null;
373
+ return trigger.current?.contains(target) ? trigger.current : null;
374
+ }
375
+ function place() {
376
+ const h = host.current;
377
+ const t = tip.current;
378
+ const target = active.current;
379
+ if (!h || !t || !target) return;
380
+ const anchor = target.querySelector("[data-tip-anchor]") || target;
381
+ placeTip(h, anchor, t, void 0, placement);
382
+ }
323
383
  useLayoutEffect2(() => {
324
- if (open) place();
325
- }, [open, text2]);
384
+ if (!mark) return;
385
+ if (!host.current?.contains(mark)) {
386
+ close(true);
387
+ return;
388
+ }
389
+ place();
390
+ });
391
+ const shared = useRef2({});
392
+ shared.current.keydown = (event) => {
393
+ ignoreMouseUntil.current = 0;
394
+ pointerKind.current = "";
395
+ pendingClick.current = null;
396
+ if (event.key === "Escape") close();
397
+ };
398
+ shared.current.touchend = (event) => {
399
+ if (!host.current?.contains(event.target)) close(true);
400
+ };
401
+ shared.current.pointerdown = (event) => {
402
+ pointerKind.current = event.pointerType;
403
+ if (event.pointerType === "touch" || event.pointerType === "pen") ignoreMouseUntil.current = Date.now() + 800;
404
+ };
405
+ shared.current.pointercancel = () => {
406
+ pendingClick.current = null;
407
+ };
408
+ shared.current.click = (event) => {
409
+ if ((pointerKind.current === "touch" || pointerKind.current === "pen") && !host.current?.contains(event.target)) close(true);
410
+ };
411
+ useEffect(() => wireDocument(host.current.ownerDocument, shared.current), []);
326
412
  useEffect(() => {
327
413
  if (!open) return;
328
- const doc = host.current.ownerDocument;
329
- const view = doc.defaultView;
330
- const escape = (event) => {
331
- if (event.key === "Escape") setOpen(false);
332
- };
333
- doc.addEventListener("keydown", escape);
334
- view.addEventListener("scroll", place, true);
335
- view.addEventListener("resize", place);
414
+ const view = host.current.ownerDocument.defaultView;
415
+ const reposition = () => place();
416
+ view.addEventListener("scroll", reposition, true);
417
+ view.addEventListener("resize", reposition);
336
418
  return () => {
337
- doc.removeEventListener("keydown", escape);
338
- view.removeEventListener("scroll", place, true);
339
- view.removeEventListener("resize", place);
419
+ view.removeEventListener("scroll", reposition, true);
420
+ view.removeEventListener("resize", reposition);
340
421
  };
341
- }, [open]);
342
- return /* @__PURE__ */ jsxs6("span", { ref: host, className: "ui-tip-host", style: { display: "inline-block" }, children: [
343
- /* @__PURE__ */ jsx10(
344
- "span",
345
- {
346
- ref: trigger,
347
- className: "ui-focusable",
348
- tabIndex: 0,
349
- "aria-describedby": id,
350
- onMouseEnter: () => {
351
- if (Date.now() > ignoreMouseUntil.current) setOpen(true);
352
- },
353
- onMouseLeave: () => {
354
- if (Date.now() > ignoreMouseUntil.current) setOpen(false);
355
- },
356
- onFocus: () => {
357
- if (Date.now() > ignoreMouseUntil.current) setOpen(true);
358
- },
359
- onBlur: () => setOpen(false),
360
- onKeyDown: (event) => {
361
- if (event.key === "Escape") setOpen(false);
362
- },
363
- onTouchStart: () => {
364
- ignoreMouseUntil.current = Date.now() + 800;
365
- touchMoved.current = false;
366
- },
367
- onTouchMove: () => {
368
- touchMoved.current = true;
369
- },
370
- onTouchCancel: () => {
371
- touchMoved.current = true;
372
- },
373
- onTouchEnd: () => {
374
- ignoreMouseUntil.current = Date.now() + 800;
375
- if (!touchMoved.current) setOpen((value) => !value);
376
- },
377
- children
378
- }
379
- ),
380
- /* @__PURE__ */ jsx10("span", { ref: tip, id, role: "tooltip", className: `ui-tip${open ? " is-open" : ""}`, children: /* @__PURE__ */ jsx10("span", { className: "ui-tip__label", children: text2 }) })
381
- ] });
422
+ }, [open, placement]);
423
+ return /* @__PURE__ */ jsxs6(
424
+ "span",
425
+ {
426
+ ref: host,
427
+ className: "ui-tip-host",
428
+ style: { display: "inline-block" },
429
+ onMouseOver: (event) => {
430
+ if (Date.now() <= ignoreMouseUntil.current) return;
431
+ const target = markOf(event.target);
432
+ if (target) show(target);
433
+ else setMark(null);
434
+ },
435
+ onMouseLeave: () => {
436
+ if (Date.now() > ignoreMouseUntil.current) close(true);
437
+ },
438
+ onFocus: (event) => {
439
+ if (Date.now() > ignoreMouseUntil.current) show(markOf(event.target));
440
+ },
441
+ onBlur: (event) => {
442
+ if (!markOf(event.relatedTarget)) close(true);
443
+ },
444
+ onPointerOver: (event) => {
445
+ if (event.pointerType === "touch" || event.pointerType === "pen") ignoreMouseUntil.current = Date.now() + 800;
446
+ else if (event.pointerType === "mouse") {
447
+ ignoreMouseUntil.current = 0;
448
+ show(markOf(event.target));
449
+ }
450
+ },
451
+ onClickCapture: (event) => {
452
+ const touched = pendingClick.current;
453
+ pendingClick.current = null;
454
+ if (pointerKind.current !== "pen") return;
455
+ const target = markOf(event.target);
456
+ const opening = touched ? touched === "open" : !!target && target !== mark;
457
+ if (!opening) {
458
+ if (!touched) close();
459
+ return;
460
+ }
461
+ event.preventDefault();
462
+ event.stopPropagation();
463
+ const doc = host.current.ownerDocument;
464
+ pointerKind.current = "";
465
+ doc.documentElement.dispatchEvent(new MouseEvent("click", { bubbles: true }));
466
+ pointerKind.current = "touch";
467
+ dismissed.current = null;
468
+ show(target);
469
+ },
470
+ onTouchStart: () => {
471
+ ignoreMouseUntil.current = Date.now() + 800;
472
+ touchMoved.current = false;
473
+ pendingClick.current = null;
474
+ },
475
+ onTouchMove: () => {
476
+ touchMoved.current = true;
477
+ },
478
+ onTouchCancel: () => {
479
+ touchMoved.current = true;
480
+ },
481
+ onTouchEnd: (event) => {
482
+ ignoreMouseUntil.current = Date.now() + 800;
483
+ if (touchMoved.current) return;
484
+ const target = markOf(event.target);
485
+ if (!target || target === mark) {
486
+ pendingClick.current = "close";
487
+ close();
488
+ } else {
489
+ pendingClick.current = "open";
490
+ dismissed.current = null;
491
+ show(target);
492
+ }
493
+ },
494
+ children: [
495
+ /* @__PURE__ */ jsx10("span", { ref: trigger, className: "ui-focusable", tabIndex: 0, "aria-describedby": id, children }),
496
+ /* @__PURE__ */ jsx10("span", { ref: tip, id, "data-tip": "", role: "tooltip", className: `ui-tip${open ? " is-open" : ""}`, children: /* @__PURE__ */ jsx10(Text, { label, value, detail: detail2 }) })
497
+ ]
498
+ }
499
+ );
382
500
  }
383
501
 
384
502
  // src/primitives/StatBand.tsx
385
- import { Fragment, jsx as jsx11, jsxs as jsxs7 } from "react/jsx-runtime";
503
+ import { Fragment as Fragment2, jsx as jsx11, jsxs as jsxs7 } from "react/jsx-runtime";
386
504
  var GLYPH = { up: "arrowUp", down: "arrowDown", flat: "minus" };
387
505
  var directionOf = (text2) => {
388
506
  const t = text2.trim();
@@ -391,7 +509,7 @@ var directionOf = (text2) => {
391
509
  var hasChange = (d) => !!d && d.value != null && d.value !== "";
392
510
  function ContextRow({ caption, delta, basisId }) {
393
511
  if (!hasChange(delta)) return caption ? /* @__PURE__ */ jsx11("dd", { className: "ui-stat__caption", children: caption }) : null;
394
- const lead = caption ? /* @__PURE__ */ jsxs7(Fragment, { children: [
512
+ const lead = caption ? /* @__PURE__ */ jsxs7(Fragment2, { children: [
395
513
  /* @__PURE__ */ jsx11("span", { className: "ui-stat__caption", children: caption }),
396
514
  " "
397
515
  ] }) : null;
@@ -401,7 +519,7 @@ function ContextRow({ caption, delta, basisId }) {
401
519
  lead,
402
520
  /* @__PURE__ */ jsx11(Icon, { name: GLYPH[dir] }),
403
521
  delta.tooltip ? /* @__PURE__ */ jsx11(Tooltip, { text: delta.tooltip, children: /* @__PURE__ */ jsx11("span", { className: "ui-stat__change", children: delta.value }) }) : /* @__PURE__ */ jsx11("span", { className: "ui-stat__change", children: delta.value }),
404
- own ? /* @__PURE__ */ jsxs7(Fragment, { children: [
522
+ own ? /* @__PURE__ */ jsxs7(Fragment2, { children: [
405
523
  " ",
406
524
  /* @__PURE__ */ jsx11("span", { className: "ui-stat__basis", children: own })
407
525
  ] }) : null
@@ -672,7 +790,7 @@ function Modal({ open, title, onClose, footer, children, initialFocusRef, role =
672
790
  }
673
791
 
674
792
  // src/Confirm.tsx
675
- import { Fragment as Fragment2, jsx as jsx13, jsxs as jsxs9 } from "react/jsx-runtime";
793
+ import { Fragment as Fragment3, jsx as jsx13, jsxs as jsxs9 } from "react/jsx-runtime";
676
794
  function Confirm({
677
795
  open,
678
796
  title,
@@ -693,7 +811,7 @@ function Confirm({
693
811
  onClose: onCancel,
694
812
  role: "alertdialog",
695
813
  initialFocusRef: safeAction,
696
- footer: /* @__PURE__ */ jsxs9(Fragment2, { children: [
814
+ footer: /* @__PURE__ */ jsxs9(Fragment3, { children: [
697
815
  /* @__PURE__ */ jsx13(Button, { ref: safeAction, variant: "ghost", onClick: onCancel, children: cancelLabel }),
698
816
  /* @__PURE__ */ jsx13(Button, { variant: danger ? "danger" : "primary", busy, onClick: onConfirm, children: confirmLabel })
699
817
  ] }),
@@ -945,7 +1063,7 @@ function rowId(uid, groups, item) {
945
1063
  }
946
1064
 
947
1065
  // src/DataTable.tsx
948
- import { useMemo as useMemo2, useState as useState5 } from "react";
1066
+ import { useCallback as useCallback2, useEffect as useEffect5, useMemo as useMemo2, useRef as useRef9, useState as useState5 } from "react";
949
1067
  import { DEFAULT_PAGE_SIZE as DEFAULT_PAGE_SIZE2 } from "@apliteni/apliteni-ui";
950
1068
 
951
1069
  // src/Pagination.tsx
@@ -1173,7 +1291,7 @@ function Pagination({
1173
1291
  }
1174
1292
 
1175
1293
  // src/DataTable.tsx
1176
- import { Fragment as Fragment3, jsx as jsx17, jsxs as jsxs13 } from "react/jsx-runtime";
1294
+ import { Fragment as Fragment4, jsx as jsx17, jsxs as jsxs13 } from "react/jsx-runtime";
1177
1295
  var NO_SORT = { key: void 0, dir: -1 };
1178
1296
  function sortTableRows(rows, sort) {
1179
1297
  if (sort.key === void 0) return [...rows];
@@ -1209,6 +1327,33 @@ function DataTable({
1209
1327
  hasMore = false
1210
1328
  }) {
1211
1329
  const scrollable = stickyHeader || pinnedIdentity;
1330
+ const table = useRef9(null);
1331
+ const [pagerHost, setPagerHost] = useState5(null);
1332
+ const holdPagerBox = useCallback2(
1333
+ (box) => setPagerHost(box?.parentElement ?? null),
1334
+ []
1335
+ );
1336
+ const [strip2, setStrip] = useState5();
1337
+ useEffect5(() => {
1338
+ const el = table.current;
1339
+ const host = pagerHost;
1340
+ if (!el || !host || typeof ResizeObserver === "undefined") {
1341
+ setStrip(void 0);
1342
+ return;
1343
+ }
1344
+ const measure = () => {
1345
+ const rect = el.getBoundingClientRect();
1346
+ const box = host.getBoundingClientRect();
1347
+ const left = box.left + host.clientLeft + (Number.parseFloat(getComputedStyle(host).paddingLeft) || 0);
1348
+ const inset = Math.max(0, rect.left - left);
1349
+ const width = rect.right - left - inset;
1350
+ setStrip(width > 0 ? { width, inset } : void 0);
1351
+ };
1352
+ const observer = new ResizeObserver(measure);
1353
+ observer.observe(el);
1354
+ measure();
1355
+ return () => observer.disconnect();
1356
+ }, [pagerHost, columns, rows]);
1212
1357
  const [localSort, setLocalSort] = useState5(
1213
1358
  { key: columns.find((c) => c.sortable)?.key, dir: -1 }
1214
1359
  );
@@ -1253,14 +1398,14 @@ function DataTable({
1253
1398
  strokeLinejoin: "round",
1254
1399
  "aria-hidden": "true",
1255
1400
  focusable: "false",
1256
- children: sort.key === k ? /* @__PURE__ */ jsx17("path", { d: "m8 10 4 4 4-4" }) : /* @__PURE__ */ jsxs13(Fragment3, { children: [
1401
+ children: sort.key === k ? /* @__PURE__ */ jsx17("path", { d: "m8 10 4 4 4-4" }) : /* @__PURE__ */ jsxs13(Fragment4, { children: [
1257
1402
  /* @__PURE__ */ jsx17("path", { d: "m8 9 4-4 4 4" }),
1258
1403
  /* @__PURE__ */ jsx17("path", { d: "m8 15 4 4 4-4" })
1259
1404
  ] })
1260
1405
  }
1261
1406
  );
1262
1407
  const pageAllOn = selectable && slice.length > 0 && slice.every((r) => selected.has(r.name));
1263
- return /* @__PURE__ */ jsxs13(Fragment3, { children: [
1408
+ return /* @__PURE__ */ jsxs13(Fragment4, { children: [
1264
1409
  /* @__PURE__ */ jsx17(
1265
1410
  "div",
1266
1411
  {
@@ -1271,6 +1416,7 @@ function DataTable({
1271
1416
  children: /* @__PURE__ */ jsxs13(
1272
1417
  "table",
1273
1418
  {
1419
+ ref: table,
1274
1420
  className: ["ui-table ui-table--hover", (density === "dense" || !density && dense) && "ui-table--dense", density === "compact" && "ui-table--compact", stickyHeader && "ui-table--sticky", pinnedIdentity && "ui-table--pinned"].filter(Boolean).join(" "),
1275
1421
  "aria-busy": loading || void 0,
1276
1422
  children: [
@@ -1328,23 +1474,37 @@ function DataTable({
1328
1474
  )
1329
1475
  }
1330
1476
  ),
1331
- pager ? /* @__PURE__ */ jsx17(
1332
- Pagination,
1333
- {
1334
- page,
1335
- pageSize: size,
1336
- total: owned ? ordered.length : total ?? null,
1337
- hasMore,
1338
- pageSizes,
1339
- loading,
1340
- ...pagerLabel === void 0 ? {} : { label: pagerLabel },
1341
- onPageChange: goTo,
1342
- onPageSizeChange: (s) => {
1343
- if (pageSize === void 0) setLocalSize(s);
1344
- onPageSizeChange?.(s);
1345
- if (owned) setLocalPage(1);
1477
+ pager ? (
1478
+ // The strip that pages a table may not be wider than the rows it pages (#504).
1479
+ // The two are siblings, and no selector sizes one to the other, so the width is
1480
+ // measured: a cap rather than a width, so a pager wider than the table wraps
1481
+ // inside it and a table wider than the room still leaves the strip in the room.
1482
+ /* @__PURE__ */ jsx17(
1483
+ "div",
1484
+ {
1485
+ className: "rx-table-pager",
1486
+ ref: holdPagerBox,
1487
+ style: strip2 ? { maxWidth: strip2.width, marginInlineStart: strip2.inset || void 0 } : void 0,
1488
+ children: /* @__PURE__ */ jsx17(
1489
+ Pagination,
1490
+ {
1491
+ page,
1492
+ pageSize: size,
1493
+ total: owned ? ordered.length : total ?? null,
1494
+ hasMore,
1495
+ pageSizes,
1496
+ loading,
1497
+ ...pagerLabel === void 0 ? {} : { label: pagerLabel },
1498
+ onPageChange: goTo,
1499
+ onPageSizeChange: (s) => {
1500
+ if (pageSize === void 0) setLocalSize(s);
1501
+ onPageSizeChange?.(s);
1502
+ if (owned) setLocalPage(1);
1503
+ }
1504
+ }
1505
+ )
1346
1506
  }
1347
- }
1507
+ )
1348
1508
  ) : null
1349
1509
  ] });
1350
1510
  }
@@ -1424,10 +1584,10 @@ function Denied({
1424
1584
 
1425
1585
  // src/DatePicker.tsx
1426
1586
  import {
1427
- useCallback as useCallback2,
1428
- useEffect as useEffect5,
1587
+ useCallback as useCallback3,
1588
+ useEffect as useEffect6,
1429
1589
  useMemo as useMemo3,
1430
- useRef as useRef9,
1590
+ useRef as useRef10,
1431
1591
  useState as useState6
1432
1592
  } from "react";
1433
1593
  import { jsx as jsx19, jsxs as jsxs15 } from "react/jsx-runtime";
@@ -1440,7 +1600,7 @@ var DAY_RE = /^(\d{4})-(\d{2})-(\d{2})$/;
1440
1600
  var PHONE_MAX = 560;
1441
1601
  function usePhone() {
1442
1602
  const [phone, setPhone] = useState6(false);
1443
- useEffect5(() => {
1603
+ useEffect6(() => {
1444
1604
  const query = typeof window === "undefined" ? null : window.matchMedia?.(`(max-width: ${PHONE_MAX}px)`);
1445
1605
  if (!query) return;
1446
1606
  const read = () => setPhone(query.matches);
@@ -1535,9 +1695,9 @@ function DatePicker({
1535
1695
  const picksRange = mode === "range" || mode === "day-range";
1536
1696
  const phone = usePhone();
1537
1697
  const asSheet = sheet ?? phone;
1538
- const root = useRef9(null);
1539
- const trigger = useRef9(null);
1540
- const grid = useRef9(null);
1698
+ const root = useRef10(null);
1699
+ const trigger = useRef10(null);
1700
+ const grid = useRef10(null);
1541
1701
  const [selfOpen, setSelfOpen] = useState6(defaultOpen);
1542
1702
  const open = openProp ?? selfOpen;
1543
1703
  const [selfValue, setSelfValue] = useState6(defaultValue);
@@ -1555,7 +1715,7 @@ function DatePicker({
1555
1715
  weekdayShort: new Intl.DateTimeFormat(locale, { weekday: "short", timeZone: "UTC" })
1556
1716
  }), [locale]);
1557
1717
  const monthLabels = useMemo3(() => evenMonthLabels(names.monthShort), [names]);
1558
- const at = useCallback2((index) => new Date(
1718
+ const at = useCallback3((index) => new Date(
1559
1719
  grain === "month" ? Date.UTC(Math.floor(index / 12), index % 12, 1) : index * DAY_MS
1560
1720
  ), [grain]);
1561
1721
  const lo = toIndex(min, grain, "start");
@@ -1574,19 +1734,19 @@ function DatePicker({
1574
1734
  }, [today, grain]);
1575
1735
  const anchor = toIndex(picked, grain) ?? toIndex(picksRange ? span.start ?? span.end : null, grain) ?? todayIndex;
1576
1736
  const [cursor, setCursor] = useState6(() => clamp(anchor, lo, hi));
1577
- const land = useRef9(false);
1578
- const setOpen = useCallback2((next) => {
1737
+ const land = useRef10(false);
1738
+ const setOpen = useCallback3((next) => {
1579
1739
  if (openProp === void 0) setSelfOpen(next);
1580
1740
  onOpenChange?.(next);
1581
1741
  }, [openProp, onOpenChange]);
1582
- const close = useRef9(setOpen);
1742
+ const close = useRef10(setOpen);
1583
1743
  useIsoLayoutEffect(() => {
1584
1744
  close.current = setOpen;
1585
1745
  });
1586
- useEffect5(() => {
1746
+ useEffect6(() => {
1587
1747
  if (open) setCursor(clamp(anchor, lo, hi));
1588
1748
  }, [open]);
1589
- useEffect5(() => {
1749
+ useEffect6(() => {
1590
1750
  if (!open || asSheet) return;
1591
1751
  const doc = root.current?.ownerDocument ?? document;
1592
1752
  const onClick = (e) => {
@@ -1612,7 +1772,7 @@ function DatePicker({
1612
1772
  const columns = grain === "month" ? 3 : 7;
1613
1773
  const page = grain === "month" ? Math.floor(cursor / 12) : monthOf(cursor);
1614
1774
  const caption = grain === "month" ? String(page) : names.monthYear.format(at(firstDayOf(page)));
1615
- const periodName = useCallback2((index) => grain === "month" ? names.monthYear.format(at(index)) : `${names.weekday.format(at(index))} ${names.day.format(at(index))}`, [grain, names, at]);
1775
+ const periodName = useCallback3((index) => grain === "month" ? names.monthYear.format(at(index)) : `${names.weekday.format(at(index))} ${names.day.format(at(index))}`, [grain, names, at]);
1616
1776
  const count = grain === "month" ? 12 : daysInMonth(page);
1617
1777
  const first = grain === "month" ? page * 12 : firstDayOf(page);
1618
1778
  const last = first + count - 1;
@@ -1894,11 +2054,11 @@ function DatePicker({
1894
2054
 
1895
2055
  // src/Dropdown.tsx
1896
2056
  import {
1897
- Fragment as Fragment4,
1898
- useCallback as useCallback3,
1899
- useEffect as useEffect6,
2057
+ Fragment as Fragment5,
2058
+ useCallback as useCallback4,
2059
+ useEffect as useEffect7,
1900
2060
  useId as useId7,
1901
- useRef as useRef10,
2061
+ useRef as useRef11,
1902
2062
  useState as useState7
1903
2063
  } from "react";
1904
2064
  import {
@@ -1911,7 +2071,7 @@ import {
1911
2071
  dropdownHeightFit,
1912
2072
  filterPanelRow
1913
2073
  } from "@apliteni/apliteni-ui";
1914
- import { Fragment as Fragment5, jsx as jsx20, jsxs as jsxs16 } from "react/jsx-runtime";
2074
+ import { Fragment as Fragment6, jsx as jsx20, jsxs as jsxs16 } from "react/jsx-runtime";
1915
2075
  var EXIT_SLACK_MS2 = 50;
1916
2076
  var SETTLE_MS = 450;
1917
2077
  var inPanel = (node) => {
@@ -1975,19 +2135,19 @@ function Dropdown({
1975
2135
  const [pick, setPick] = useState7(null);
1976
2136
  const [query, setQuery] = useState7(() => search && search !== true ? search.query || "" : "");
1977
2137
  const [activeKey, setActiveKey] = useState7(null);
1978
- const root = useRef10(null);
1979
- const panel = useRef10(null);
1980
- const trigger = useRef10(null);
1981
- const field = useRef10(null);
1982
- const landOn = useRef10(null);
1983
- const at = useRef10("");
2138
+ const root = useRef11(null);
2139
+ const panel = useRef11(null);
2140
+ const trigger = useRef11(null);
2141
+ const field = useRef11(null);
2142
+ const landOn = useRef11(null);
2143
+ const at = useRef11("");
1984
2144
  const auto = useId7().replace(/:/g, "");
1985
2145
  const uid = id ?? auto;
1986
- const setOpen = useCallback3((next) => {
2146
+ const setOpen = useCallback4((next) => {
1987
2147
  if (openProp === void 0) setSelfOpen(next);
1988
2148
  onOpenChange?.(next);
1989
2149
  }, [openProp, onOpenChange]);
1990
- const close = useRef10(setOpen);
2150
+ const close = useRef11(setOpen);
1991
2151
  useIsoLayoutEffect(() => {
1992
2152
  close.current = setOpen;
1993
2153
  });
@@ -2040,7 +2200,7 @@ function Dropdown({
2040
2200
  stop.forEach((off) => off());
2041
2201
  };
2042
2202
  }, [open]);
2043
- const opened = useRef10(false);
2203
+ const opened = useRef11(false);
2044
2204
  useIsoLayoutEffect(() => {
2045
2205
  const el = panel.current;
2046
2206
  if (open) {
@@ -2079,7 +2239,7 @@ function Dropdown({
2079
2239
  const given = rows.find((it) => it.selected);
2080
2240
  const givenKey = given ? keyOf(given) : null;
2081
2241
  const pickedKey = pick && pick.against === givenKey ? pick.key : null;
2082
- useEffect6(() => {
2242
+ useEffect7(() => {
2083
2243
  if (pick && pick.against !== givenKey) setPick(null);
2084
2244
  }, [givenKey, pick]);
2085
2245
  const picked = pickedKey != null ? rows.find((it) => keyOf(it) === pickedKey) : void 0;
@@ -2093,7 +2253,7 @@ function Dropdown({
2093
2253
  const rowIds = /* @__PURE__ */ new Map();
2094
2254
  rows.forEach((it, i) => rowIds.set(it, `${uid}-opt-${i}`));
2095
2255
  const listId = `${uid}-list`;
2096
- useEffect6(() => {
2256
+ useEffect7(() => {
2097
2257
  if (!open) return;
2098
2258
  const mine = () => close.current(false);
2099
2259
  for (const other of [...openNow]) other();
@@ -2102,7 +2262,7 @@ function Dropdown({
2102
2262
  openNow.delete(mine);
2103
2263
  };
2104
2264
  }, [open]);
2105
- useEffect6(() => {
2265
+ useEffect7(() => {
2106
2266
  if (!open) return;
2107
2267
  const doc = root.current?.ownerDocument ?? document;
2108
2268
  const onClick = (e) => {
@@ -2337,7 +2497,7 @@ function Dropdown({
2337
2497
  ...asLink ? { href: entry.href, ...entry.target ? { target: entry.target } : null } : null,
2338
2498
  ...sx ? { id: rowIds.get(entry), hidden: hiddenBy(entry) || void 0 } : null,
2339
2499
  onClick: (e) => choose(entry, e),
2340
- children: /* @__PURE__ */ jsxs16(Fragment5, { children: [
2500
+ children: /* @__PURE__ */ jsxs16(Fragment6, { children: [
2341
2501
  entry.icon && /* @__PURE__ */ jsx20(Glyph2, { name: entry.icon, className: "ui-dropdown__ic" }),
2342
2502
  /* @__PURE__ */ jsxs16("span", { className: "ui-dropdown__main", children: [
2343
2503
  /* @__PURE__ */ jsx20("span", { className: "ui-dropdown__label", children: entry.label }),
@@ -2347,7 +2507,7 @@ function Dropdown({
2347
2507
  asOption && /* @__PURE__ */ jsx20(Glyph2, { name: "check", className: "ui-dropdown__tick", hidden: true })
2348
2508
  ] })
2349
2509
  };
2350
- if (row) return /* @__PURE__ */ jsx20(Fragment4, { children: row(entry, props) }, key);
2510
+ if (row) return /* @__PURE__ */ jsx20(Fragment5, { children: row(entry, props) }, key);
2351
2511
  const Tag = asLink ? "a" : "div";
2352
2512
  return /* @__PURE__ */ jsx20(Tag, { ...props }, key);
2353
2513
  }
@@ -2369,7 +2529,7 @@ function Dropdown({
2369
2529
  );
2370
2530
  }) : (items || []).map((entry, i) => renderRow(entry, `i${i}`));
2371
2531
  const cap = scroll && scroll !== true ? { "--ui-dropdown-cap": typeof scroll === "number" ? `${scroll}px` : scroll } : void 0;
2372
- const none = sx && filtering && !visible.length ? /* @__PURE__ */ jsxs16(Fragment5, { children: [
2532
+ const none = sx && filtering && !visible.length ? /* @__PURE__ */ jsxs16(Fragment6, { children: [
2373
2533
  /* @__PURE__ */ jsx20("span", { className: "ui-dropdown__none-title", children: sx.empty.replace("{q}", () => query.trim()) }),
2374
2534
  /* @__PURE__ */ jsx20("span", { className: "ui-dropdown__none-hint", children: sx.hint })
2375
2535
  ] }) : null;
@@ -2390,7 +2550,7 @@ function Dropdown({
2390
2550
  setOpen(!open);
2391
2551
  },
2392
2552
  children: [
2393
- triggerContent != null ? triggerContent : /* @__PURE__ */ jsxs16(Fragment5, { children: [
2553
+ triggerContent != null ? triggerContent : /* @__PURE__ */ jsxs16(Fragment6, { children: [
2394
2554
  label && /* @__PURE__ */ jsx20("span", { className: "ui-dropdown__pre", children: label }),
2395
2555
  /* @__PURE__ */ jsx20("span", { className: "ui-dropdown__value", children: shown != null ? shown : placeholder })
2396
2556
  ] }),
@@ -2418,7 +2578,7 @@ function Dropdown({
2418
2578
  onMouseMove,
2419
2579
  children: [
2420
2580
  header,
2421
- sx ? /* @__PURE__ */ jsxs16(Fragment5, { children: [
2581
+ sx ? /* @__PURE__ */ jsxs16(Fragment6, { children: [
2422
2582
  /* @__PURE__ */ jsxs16("div", { className: "ui-dropdown__search", children: [
2423
2583
  /* @__PURE__ */ jsx20(Glyph2, { name: "search", className: "ui-dropdown__search-ic", hidden: true }),
2424
2584
  /* @__PURE__ */ jsx20(
@@ -2567,15 +2727,15 @@ function Segmented({ options, value, onChange, label, appearance = "pill", size,
2567
2727
  }
2568
2728
 
2569
2729
  // src/FilterBar.tsx
2570
- import { useRef as useRef11, useState as useState8 } from "react";
2730
+ import { useRef as useRef12, useState as useState8 } from "react";
2571
2731
  import { filterChipText, filterChipName, filterChipUnset, filterChipItems, focusNextStop } from "@apliteni/apliteni-ui";
2572
- import { Fragment as Fragment6, jsx as jsx24, jsxs as jsxs19 } from "react/jsx-runtime";
2732
+ import { Fragment as Fragment7, jsx as jsx24, jsxs as jsxs19 } from "react/jsx-runtime";
2573
2733
  var SEARCH_AT = 10;
2574
2734
  var isRow2 = (entry) => entry !== "---" && !entry.separator;
2575
- function FilterBar({ filters, label = "Filters", clearLabel = "Clear all", add, addLabel = "Filter", disabled = false, busy = false, onRemove, onClear, onChange, onAdd }) {
2576
- const bar = useRef11(null);
2577
- const focused = useRef11(null);
2578
- const landing = useRef11(null);
2735
+ function FilterBar({ filters, label = "Filters", clearLabel = "Clear all", clearVariant = "ghost", add, addLabel = "Filter", disabled = false, busy = false, onRemove, onClear, onChange, onAdd }) {
2736
+ const bar = useRef12(null);
2737
+ const focused = useRef12(null);
2738
+ const landing = useRef12(null);
2579
2739
  const [opened, setOpened] = useState8({});
2580
2740
  const [adding, setAdding] = useState8(false);
2581
2741
  const blocked = disabled || busy;
@@ -2676,7 +2836,7 @@ function FilterBar({ filters, label = "Filters", clearLabel = "Clear all", add,
2676
2836
  variant: "menu",
2677
2837
  sections,
2678
2838
  ariaLabel: addLabel,
2679
- triggerContent: /* @__PURE__ */ jsxs19(Fragment6, { children: [
2839
+ triggerContent: /* @__PURE__ */ jsxs19(Fragment7, { children: [
2680
2840
  /* @__PURE__ */ jsx24(Icon, { name: "plus" }),
2681
2841
  addLabel
2682
2842
  ] }),
@@ -2693,7 +2853,7 @@ function FilterBar({ filters, label = "Filters", clearLabel = "Clear all", add,
2693
2853
  ) }),
2694
2854
  filters.length > 0 && /* @__PURE__ */ jsx24("span", { "data-filter-clear": "", onFocus: () => {
2695
2855
  focused.current = { id: null, index: 0 };
2696
- }, children: /* @__PURE__ */ jsx24(Button, { size: "sm", variant: "ghost", onClick: () => {
2856
+ }, children: /* @__PURE__ */ jsx24(Button, { size: "sm", variant: clearVariant, onClick: () => {
2697
2857
  if (!blocked) onClear();
2698
2858
  }, children: clearLabel }) })
2699
2859
  ]
@@ -2726,13 +2886,13 @@ function DrawerSection({ title, headingLevel = 3, className, children, ...rest }
2726
2886
  }
2727
2887
 
2728
2888
  // src/Snippet.tsx
2729
- import { useEffect as useEffect7, useRef as useRef12, useState as useState9 } from "react";
2730
- import { Fragment as Fragment7, jsx as jsx26, jsxs as jsxs21 } from "react/jsx-runtime";
2889
+ import { useEffect as useEffect8, useRef as useRef13, useState as useState9 } from "react";
2890
+ import { Fragment as Fragment8, jsx as jsx26, jsxs as jsxs21 } from "react/jsx-runtime";
2731
2891
  function Snippet({ label = "shell", code = "", children, copy = true, reveal = false, copyLabel = "Copy code" }) {
2732
2892
  const [status, setStatus] = useState9("idle");
2733
- const request = useRef12(0);
2734
- const timer = useRef12(void 0);
2735
- useEffect7(() => {
2893
+ const request = useRef13(0);
2894
+ const timer = useRef13(void 0);
2895
+ useEffect8(() => {
2736
2896
  setStatus("idle");
2737
2897
  return () => {
2738
2898
  request.current++;
@@ -2755,7 +2915,7 @@ function Snippet({ label = "shell", code = "", children, copy = true, reveal = f
2755
2915
  return /* @__PURE__ */ jsxs21("div", { className: reveal ? "ui-snippet ui-snippet--reveal" : "ui-snippet", children: [
2756
2916
  /* @__PURE__ */ jsxs21("div", { className: "ui-snippet__bar", children: [
2757
2917
  /* @__PURE__ */ jsx26("span", { children: label }),
2758
- copy && /* @__PURE__ */ jsxs21(Fragment7, { children: [
2918
+ copy && /* @__PURE__ */ jsxs21(Fragment8, { children: [
2759
2919
  /* @__PURE__ */ jsx26(
2760
2920
  "button",
2761
2921
  {
@@ -2775,15 +2935,15 @@ function Snippet({ label = "shell", code = "", children, copy = true, reveal = f
2775
2935
  }
2776
2936
 
2777
2937
  // src/Tabs.tsx
2778
- import { useEffect as useEffect8, useId as useId8, useRef as useRef13 } from "react";
2938
+ import { useEffect as useEffect9, useId as useId8, useRef as useRef14 } from "react";
2779
2939
  import { playEntrance } from "@apliteni/apliteni-ui/motion";
2780
- import { Fragment as Fragment8, jsx as jsx27, jsxs as jsxs22 } from "react/jsx-runtime";
2940
+ import { Fragment as Fragment9, jsx as jsx27, jsxs as jsxs22 } from "react/jsx-runtime";
2781
2941
  function Tabs({ items, value, onChange, label }) {
2782
2942
  const id = useId8();
2783
- const previous = useRef13(value);
2784
- const activePanel = useRef13(null);
2785
- const buttons = useRef13([]);
2786
- useEffect8(() => {
2943
+ const previous = useRef14(value);
2944
+ const activePanel = useRef14(null);
2945
+ const buttons = useRef14([]);
2946
+ useEffect9(() => {
2787
2947
  if (previous.current !== value) playEntrance(activePanel.current);
2788
2948
  previous.current = value;
2789
2949
  }, [value]);
@@ -2826,7 +2986,7 @@ function Tabs({ items, value, onChange, label }) {
2826
2986
  },
2827
2987
  children: [
2828
2988
  item.label,
2829
- item.count != null && /* @__PURE__ */ jsxs22(Fragment8, { children: [
2989
+ item.count != null && /* @__PURE__ */ jsxs22(Fragment9, { children: [
2830
2990
  " ",
2831
2991
  item.count
2832
2992
  ] })
@@ -2852,14 +3012,14 @@ function Tabs({ items, value, onChange, label }) {
2852
3012
  }
2853
3013
 
2854
3014
  // src/Timeline.tsx
2855
- import { useEffect as useEffect9, useRef as useRef14 } from "react";
3015
+ import { useEffect as useEffect10, useRef as useRef15 } from "react";
2856
3016
  import { playEntrance as playEntrance2, prefersReducedMotion } from "@apliteni/apliteni-ui/motion";
2857
3017
  import { jsx as jsx28, jsxs as jsxs23 } from "react/jsx-runtime";
2858
3018
  var kindIcons = { person: "user", rule: "bolt", reversal: "refresh" };
2859
3019
  function Timeline({ events, className, ...rest }) {
2860
- const previousIds = useRef14(new Set(events.map((event) => event.id)));
2861
- const rows = useRef14(/* @__PURE__ */ new Map());
2862
- useEffect9(() => {
3020
+ const previousIds = useRef15(new Set(events.map((event) => event.id)));
3021
+ const rows = useRef15(/* @__PURE__ */ new Map());
3022
+ useEffect10(() => {
2863
3023
  if (previousIds.current.size > 0 && !prefersReducedMotion()) {
2864
3024
  for (const event of events) {
2865
3025
  if (previousIds.current.has(event.id)) continue;
@@ -2902,7 +3062,7 @@ function Timeline({ events, className, ...rest }) {
2902
3062
  }
2903
3063
 
2904
3064
  // src/Field.tsx
2905
- import { forwardRef as forwardRef6, useEffect as useEffect10, useId as useId9, useRef as useRef15, useState as useState10 } from "react";
3065
+ import { forwardRef as forwardRef6, useEffect as useEffect11, useId as useId9, useRef as useRef16, useState as useState10 } from "react";
2906
3066
  import { esc, icon as icon4 } from "@apliteni/apliteni-ui";
2907
3067
  import { jsx as jsx29, jsxs as jsxs24 } from "react/jsx-runtime";
2908
3068
  function messages(id, hint, error) {
@@ -2990,10 +3150,10 @@ function SelectField({ label, hint, error, required, className = "", children, .
2990
3150
  }
2991
3151
  function FileField({ label, hint, error, required, disabled, onFileChange, className = "", ...props }) {
2992
3152
  const id = useId9();
2993
- const input = useRef15(null);
3153
+ const input = useRef16(null);
2994
3154
  const [file, setFile] = useState10(null);
2995
3155
  const [dragging, setDragging] = useState10(false);
2996
- useEffect10(() => {
3156
+ useEffect11(() => {
2997
3157
  const form = input.current?.form;
2998
3158
  const reset = () => {
2999
3159
  setFile(null);
@@ -3052,8 +3212,8 @@ function FileField({ label, hint, error, required, disabled, onFileChange, class
3052
3212
  }
3053
3213
 
3054
3214
  // src/FileDrop.tsx
3055
- import { useRef as useRef16, useState as useState11 } from "react";
3056
- import { Fragment as Fragment9, jsx as jsx30, jsxs as jsxs25 } from "react/jsx-runtime";
3215
+ import { useRef as useRef17, useState as useState11 } from "react";
3216
+ import { Fragment as Fragment10, jsx as jsx30, jsxs as jsxs25 } from "react/jsx-runtime";
3057
3217
  var MARKS = {
3058
3218
  uploading: "clock",
3059
3219
  done: "circleCheck",
@@ -3086,7 +3246,7 @@ function FileDrop({
3086
3246
  children,
3087
3247
  className
3088
3248
  }) {
3089
- const input = useRef16(null);
3249
+ const input = useRef17(null);
3090
3250
  const [over, setOver] = useState11(false);
3091
3251
  const status = file?.status ?? "uploading";
3092
3252
  const word = status === "error" ? file?.error ?? WORDS.error : file?.state ?? WORDS[status];
@@ -3165,7 +3325,7 @@ function FileDrop({
3165
3325
  children: /* @__PURE__ */ jsx30("span", { style: { width: `${file.progress}%` } })
3166
3326
  }
3167
3327
  )
3168
- ] }) : /* @__PURE__ */ jsxs25(Fragment9, { children: [
3328
+ ] }) : /* @__PURE__ */ jsxs25(Fragment10, { children: [
3169
3329
  /* @__PURE__ */ jsx30(
3170
3330
  Button,
3171
3331
  {
@@ -3221,7 +3381,7 @@ var SearchField = forwardRef7(function SearchField2({ ariaLabel, className, ...p
3221
3381
  });
3222
3382
 
3223
3383
  // src/Toast.tsx
3224
- import { createContext as createContext2, useCallback as useCallback4, useContext as useContext2, useEffect as useEffect11, useLayoutEffect as useLayoutEffect4, useRef as useRef17, useState as useState12 } from "react";
3384
+ import { createContext as createContext2, useCallback as useCallback5, useContext as useContext2, useEffect as useEffect12, useLayoutEffect as useLayoutEffect4, useRef as useRef18, useState as useState12 } from "react";
3225
3385
  import { createPortal as createPortal4 } from "react-dom";
3226
3386
  import { jsx as jsx32, jsxs as jsxs27 } from "react/jsx-runtime";
3227
3387
  var Context = createContext2(null);
@@ -3232,21 +3392,21 @@ function useToast() {
3232
3392
  return push;
3233
3393
  }
3234
3394
  function Notice({ notice, remove }) {
3235
- const root = useRef17(null);
3395
+ const root = useRef18(null);
3236
3396
  const [leaving2, setLeaving] = useState12(false);
3237
- const dismissed = useRef17(false);
3238
- const remaining = useRef17(5e3);
3397
+ const dismissed = useRef18(false);
3398
+ const remaining = useRef18(5e3);
3239
3399
  const [hovered, setHovered] = useState12(false);
3240
3400
  const [focused, setFocused] = useState12(false);
3241
3401
  const paused = hovered || focused;
3242
3402
  const tone = notice.tone ?? "success";
3243
- const dismiss = useCallback4(() => {
3403
+ const dismiss = useCallback5(() => {
3244
3404
  if (dismissed.current) return;
3245
3405
  dismissed.current = true;
3246
3406
  if (typeof matchMedia === "function" && matchMedia("(prefers-reduced-motion: reduce)").matches) remove();
3247
3407
  else setLeaving(true);
3248
3408
  }, [remove]);
3249
- useEffect11(() => {
3409
+ useEffect12(() => {
3250
3410
  if (leaving2) {
3251
3411
  const element = root.current;
3252
3412
  const finish = (event) => {
@@ -3260,7 +3420,7 @@ function Notice({ notice, remove }) {
3260
3420
  };
3261
3421
  }
3262
3422
  }, [leaving2, remove]);
3263
- useEffect11(() => {
3423
+ useEffect12(() => {
3264
3424
  if (leaving2 || notice.action || paused) return;
3265
3425
  const started = Date.now();
3266
3426
  const timer = setTimeout(dismiss, remaining.current);
@@ -3338,9 +3498,9 @@ function usePublishedReach(stack2, count) {
3338
3498
  }
3339
3499
  function Toast({ children }) {
3340
3500
  const [entries, setEntries] = useState12([]);
3341
- const nextId = useRef17(0);
3342
- const stack2 = useRef17(null);
3343
- const push = useCallback4((notice) => {
3501
+ const nextId = useRef18(0);
3502
+ const stack2 = useRef18(null);
3503
+ const push = useCallback5((notice) => {
3344
3504
  const id = nextId.current++;
3345
3505
  const remove = () => setEntries((current) => current.filter((entry) => entry.id !== id));
3346
3506
  setEntries((current) => [...current, { id, notice, remove }]);
@@ -3356,13 +3516,13 @@ function Toast({ children }) {
3356
3516
  }
3357
3517
 
3358
3518
  // src/AppShell.tsx
3359
- import { useEffect as useEffect13, useId as useId11, useState as useState14 } from "react";
3519
+ import { useEffect as useEffect14, useId as useId11, useState as useState14 } from "react";
3360
3520
  import { applyTheme, paletteHotkey, prism, railCollapsed, themeIcon, themeName } from "@apliteni/apliteni-ui";
3361
3521
 
3362
3522
  // src/SidebarNav.tsx
3363
- import { forwardRef as forwardRef8, useEffect as useEffect12, useId as useId10, useState as useState13 } from "react";
3523
+ import { forwardRef as forwardRef8, useEffect as useEffect13, useId as useId10, useState as useState13 } from "react";
3364
3524
  import { ENTRANCE_FALLBACK_MS } from "@apliteni/apliteni-ui/motion";
3365
- import { Fragment as Fragment10, jsx as jsx33, jsxs as jsxs28 } from "react/jsx-runtime";
3525
+ import { Fragment as Fragment11, jsx as jsx33, jsxs as jsxs28 } from "react/jsx-runtime";
3366
3526
  var badgeText = (badge) => typeof badge === "object" ? badge.text : badge;
3367
3527
  function Row({ item, active, activeIs, collapsed, renderLink, sub }) {
3368
3528
  const uid = useId10();
@@ -3371,7 +3531,7 @@ function Row({ item, active, activeIs, collapsed, renderLink, sub }) {
3371
3531
  const [expanded, setExpanded] = useState13();
3372
3532
  const open = expanded ?? item.defaultOpen ?? childActive;
3373
3533
  const [entering, setEntering] = useState13(false);
3374
- useEffect12(() => {
3534
+ useEffect13(() => {
3375
3535
  if (!entering) return;
3376
3536
  const timer = setTimeout(() => setEntering(false), ENTRANCE_FALLBACK_MS);
3377
3537
  return () => clearTimeout(timer);
@@ -3388,7 +3548,7 @@ function Row({ item, active, activeIs, collapsed, renderLink, sub }) {
3388
3548
  item.disabled && "is-disabled",
3389
3549
  item.danger && "is-danger"
3390
3550
  ].filter(Boolean).join(" ");
3391
- const children = /* @__PURE__ */ jsxs28(Fragment10, { children: [
3551
+ const children = /* @__PURE__ */ jsxs28(Fragment11, { children: [
3392
3552
  (item.leading ?? item.icon) && /* @__PURE__ */ jsx33("span", { className: "ui-nav__ic", children: item.leading ?? /* @__PURE__ */ jsx33(Icon, { name: item.icon }) }),
3393
3553
  /* @__PURE__ */ jsx33("span", { className: "ui-nav__label", children: item.label }),
3394
3554
  count != null && count !== "" && /* @__PURE__ */ jsx33("span", { className: `ui-nav__badge is-${typeof item.badge === "object" ? item.badge.tone ?? "neutral" : "neutral"}`, children: count }),
@@ -3457,7 +3617,7 @@ var SidebarNav = forwardRef8(function SidebarNav2({
3457
3617
  });
3458
3618
 
3459
3619
  // src/AppShell.tsx
3460
- import { Fragment as Fragment11, jsx as jsx34, jsxs as jsxs29 } from "react/jsx-runtime";
3620
+ import { Fragment as Fragment12, jsx as jsx34, jsxs as jsxs29 } from "react/jsx-runtime";
3461
3621
  var path = (value) => value.split(/[?#]/)[0].replace(/\/+$/, "") || "/";
3462
3622
  function AppShell({
3463
3623
  sections,
@@ -3487,14 +3647,14 @@ function AppShell({
3487
3647
  const [theme, setTheme] = useState14("dark");
3488
3648
  const current = path(pathname);
3489
3649
  const active = sections.filter((section) => current === path(section.href) || path(section.href) !== "/" && current.startsWith(`${path(section.href)}/`)).sort((a, b) => path(b.href).length - path(a.href).length)[0];
3490
- useEffect13(() => {
3650
+ useEffect14(() => {
3491
3651
  setCollapsed(railCollapsed() ?? defaultCollapsed);
3492
3652
  }, [defaultCollapsed]);
3493
- useEffect13(() => {
3653
+ useEffect14(() => {
3494
3654
  setMore(false);
3495
3655
  setSearch(false);
3496
3656
  }, [pathname]);
3497
- useEffect13(() => {
3657
+ useEffect14(() => {
3498
3658
  const root = document.documentElement;
3499
3659
  const sync2 = () => setTheme(root.getAttribute("data-theme") === "light" ? "light" : "dark");
3500
3660
  sync2();
@@ -3502,7 +3662,7 @@ function AppShell({
3502
3662
  observer.observe(root, { attributes: true, attributeFilter: ["data-theme"] });
3503
3663
  return () => observer.disconnect();
3504
3664
  }, []);
3505
- useEffect13(() => {
3665
+ useEffect14(() => {
3506
3666
  const hotkey = (event) => {
3507
3667
  if (!(event.metaKey || event.ctrlKey) || event.altKey || event.shiftKey || event.key.toLowerCase() !== "k") return;
3508
3668
  const target = event.target;
@@ -3532,7 +3692,7 @@ function AppShell({
3532
3692
  onClick: (event) => {
3533
3693
  if (!event.metaKey && !event.ctrlKey && !event.shiftKey && !event.altKey) setMore(false);
3534
3694
  },
3535
- children: /* @__PURE__ */ jsxs29(Fragment11, { children: [
3695
+ children: /* @__PURE__ */ jsxs29(Fragment12, { children: [
3536
3696
  /* @__PURE__ */ jsx34("span", { className: "ui-nav__ic", children: /* @__PURE__ */ jsx34(Icon, { name: section.icon }) }),
3537
3697
  /* @__PURE__ */ jsx34("span", { className: "ui-nav__label", children: section.label }),
3538
3698
  section.count != null && /* @__PURE__ */ jsx34("span", { className: "ui-nav__badge is-neutral", children: section.count })
@@ -3733,7 +3893,7 @@ function ThemeToggle({ labelled = false }) {
3733
3893
  }
3734
3894
 
3735
3895
  // src/Success.tsx
3736
- import { forwardRef as forwardRef9, useEffect as useEffect14, useRef as useRef18, useState as useState15 } from "react";
3896
+ import { forwardRef as forwardRef9, useEffect as useEffect15, useRef as useRef19, useState as useState15 } from "react";
3737
3897
  import { jsx as jsx37, jsxs as jsxs32 } from "react/jsx-runtime";
3738
3898
  var SuccessCheck = forwardRef9(function SuccessCheck2({ variant = "line", className, ...rest }, ref) {
3739
3899
  const circled = variant === "circled";
@@ -3781,11 +3941,11 @@ var pieces = [
3781
3941
  ];
3782
3942
  function Countdown({ seconds, label = "Redirecting", onDone }) {
3783
3943
  const [remaining, setRemaining] = useState15(seconds);
3784
- const callback = useRef18(onDone);
3785
- useEffect14(() => {
3944
+ const callback = useRef19(onDone);
3945
+ useEffect15(() => {
3786
3946
  callback.current = onDone;
3787
3947
  }, [onDone]);
3788
- useEffect14(() => {
3948
+ useEffect15(() => {
3789
3949
  let count = seconds;
3790
3950
  const timer = setInterval(() => {
3791
3951
  count -= 1;
@@ -3857,16 +4017,16 @@ var Success = forwardRef9(function Success2({
3857
4017
 
3858
4018
  // src/Chart.tsx
3859
4019
  import {
3860
- useCallback as useCallback5,
3861
- useEffect as useEffect15,
4020
+ useCallback as useCallback6,
4021
+ useEffect as useEffect16,
3862
4022
  useId as useId12,
3863
4023
  useLayoutEffect as useLayoutEffect5,
3864
4024
  useMemo as useMemo4,
3865
- useRef as useRef19,
4025
+ useRef as useRef20,
3866
4026
  useState as useState16
3867
4027
  } from "react";
3868
4028
  import { CHART_FLOOR, bridgeWalk, chartScale, pointTarget } from "@apliteni/apliteni-ui";
3869
- import { Fragment as Fragment12, jsx as jsx38, jsxs as jsxs33 } from "react/jsx-runtime";
4029
+ import { Fragment as Fragment13, jsx as jsx38, jsxs as jsxs33 } from "react/jsx-runtime";
3870
4030
  var HEIGHT = { months: 216, bridge: 216, spark: 32 };
3871
4031
  var PAD = 2;
3872
4032
  var ZERO_INSET = 1.5;
@@ -3905,7 +4065,7 @@ function barPath(m) {
3905
4065
  }
3906
4066
  function useTapFloor() {
3907
4067
  const [floor, setFloor] = useState16(TARGET);
3908
- useEffect15(() => {
4068
+ useEffect16(() => {
3909
4069
  const query = typeof window === "undefined" ? null : window.matchMedia?.(`(max-width: ${PHONE_MAX2}px) and (pointer: coarse)`);
3910
4070
  if (!query) return;
3911
4071
  const read = () => setFloor(query.matches ? TAP_FLOOR : TARGET);
@@ -4028,16 +4188,16 @@ function Chart(props) {
4028
4188
  const plotHeight = height ?? HEIGHT[variant];
4029
4189
  const showTable = table ?? !spark;
4030
4190
  const uid = useId12().replace(/[^\w-]/g, "");
4031
- const frameEl = useRef19(null);
4032
- const scroller = useRef19(null);
4033
- const plot = useRef19(null);
4034
- const tipEl = useRef19(null);
4035
- const svgEl = useRef19(null);
4036
- const ignoreMouseUntil = useRef19(0);
4037
- const touchMoved = useRef19(false);
4038
- const dismissed = useRef19(null);
4039
- const opening = useRef19(false);
4040
- const pointerFocus = useRef19(false);
4191
+ const frameEl = useRef20(null);
4192
+ const scroller = useRef20(null);
4193
+ const plot = useRef20(null);
4194
+ const tipEl = useRef20(null);
4195
+ const svgEl = useRef20(null);
4196
+ const ignoreMouseUntil = useRef20(0);
4197
+ const touchMoved = useRef20(false);
4198
+ const dismissed = useRef20(null);
4199
+ const opening = useRef20(false);
4200
+ const pointerFocus = useRef20(false);
4041
4201
  const floor = useTapFloor();
4042
4202
  const [width, setWidth] = useState16(0);
4043
4203
  const [openId, setOpenId] = useState16(null);
@@ -4058,7 +4218,7 @@ function Chart(props) {
4058
4218
  const boxHeight = Math.max(plotHeight, floor);
4059
4219
  const boxTop = -(boxHeight - plotHeight) / 2;
4060
4220
  const span = scale.max - scale.min || 1;
4061
- const y = useCallback5(
4221
+ const y = useCallback6(
4062
4222
  (value) => PAD + (scale.max - value) / span * (plotHeight - PAD * 2),
4063
4223
  [scale.max, span, plotHeight]
4064
4224
  );
@@ -4071,7 +4231,7 @@ function Chart(props) {
4071
4231
  cap * lanes + LANE_GAP * (lanes - 1)
4072
4232
  ));
4073
4233
  const barWidth = (groupWidth - LANE_GAP * (lanes - 1)) / lanes;
4074
- const centre = useCallback5((column) => column * colWidth + colWidth / 2, [colWidth]);
4234
+ const centre = useCallback6((column) => column * colWidth + colWidth / 2, [colWidth]);
4075
4235
  const marks = useMemo4(() => {
4076
4236
  const out = frame.bars.map((bar) => {
4077
4237
  let top = Math.min(y(bar.from), y(bar.to));
@@ -4145,9 +4305,9 @@ function Chart(props) {
4145
4305
  return [...out, ...dots];
4146
4306
  }, [frame, lines, keys, columns, centre, barWidth, groupWidth, y, floor, colWidth, plotWidth, boxTop, boxHeight]);
4147
4307
  const byId = useMemo4(() => new Map(marks.map((m) => [m.id, m])), [marks]);
4148
- const lead = useCallback5((column) => marks.find((m) => m.column === column), [marks]);
4308
+ const lead = useCallback6((column) => marks.find((m) => m.column === column), [marks]);
4149
4309
  const open = openId ? byId.get(openId) : void 0;
4150
- useEffect15(() => {
4310
+ useEffect16(() => {
4151
4311
  const el = plot.current;
4152
4312
  if (!el) return;
4153
4313
  const read = () => setWidth(el.clientWidth);
@@ -4157,20 +4317,20 @@ function Chart(props) {
4157
4317
  observer.observe(el);
4158
4318
  return () => observer.disconnect();
4159
4319
  }, []);
4160
- const syncEdges = useCallback5(() => {
4320
+ const syncEdges = useCallback6(() => {
4161
4321
  const el = scroller.current;
4162
4322
  if (!el) return;
4163
4323
  const last = el.scrollWidth - el.clientWidth;
4164
4324
  el.classList.toggle("is-more-before", el.scrollLeft > 1);
4165
4325
  el.classList.toggle("is-more-after", el.scrollLeft < last - 1);
4166
4326
  }, []);
4167
- useEffect15(syncEdges, [syncEdges, plotWidth, count]);
4327
+ useEffect16(syncEdges, [syncEdges, plotWidth, count]);
4168
4328
  useLayoutEffect5(() => {
4169
4329
  if (!openId || !frameEl.current || !tipEl.current || !svgEl.current) return;
4170
4330
  const anchor = [...svgEl.current.querySelectorAll("[data-anchor]")].find((el) => el.getAttribute("data-anchor") === openId);
4171
4331
  if (anchor) placeTip(frameEl.current, anchor, tipEl.current, frameEl.current);
4172
4332
  }, [openId, plotWidth, plotHeight]);
4173
- useEffect15(() => {
4333
+ useEffect16(() => {
4174
4334
  if (!openId) return;
4175
4335
  const doc = frameEl.current?.ownerDocument;
4176
4336
  const view = doc?.defaultView;
@@ -4198,7 +4358,7 @@ function Chart(props) {
4198
4358
  setOpenId(id);
4199
4359
  };
4200
4360
  const markAt = (target) => target.closest?.("[data-mark]")?.getAttribute("data-mark") ?? null;
4201
- const announce = useCallback5((column, picked = pick) => {
4361
+ const announce = useCallback6((column, picked = pick) => {
4202
4362
  const where = columns[column];
4203
4363
  if (!where) return;
4204
4364
  const values = marks.filter((m) => m.column === column).map((m) => `${m.name} ${format(m.value)}`).join(". ") || "No value";
@@ -4496,7 +4656,7 @@ function Chart(props) {
4496
4656
  `${column.label}-${i}`
4497
4657
  )) })
4498
4658
  ] }) }),
4499
- /* @__PURE__ */ jsx38("span", { ref: tipEl, className: cx8("ui-tip", openId && "is-open"), role: open ? "tooltip" : void 0, children: open && /* @__PURE__ */ jsxs33(Fragment12, { children: [
4659
+ /* @__PURE__ */ jsx38("span", { ref: tipEl, className: cx8("ui-tip", openId && "is-open"), role: open ? "tooltip" : void 0, children: open && /* @__PURE__ */ jsxs33(Fragment13, { children: [
4500
4660
  /* @__PURE__ */ jsx38("span", { className: "ui-tip__label", children: spark ? columns[open.column]?.label : `${open.name}, ${columns[open.column]?.label}` }),
4501
4661
  /* @__PURE__ */ jsx38("span", { className: "ui-tip__value", children: format(open.value) }),
4502
4662
  (stateOf(columns[open.column]) || open.detail) && /* @__PURE__ */ jsx38("span", { className: "ui-tip__detail", children: stateOf(columns[open.column]) || open.detail })
@@ -4519,7 +4679,7 @@ function Chart(props) {
4519
4679
  /* @__PURE__ */ jsx38("tbody", { children: tableRows.map((row, i) => /* @__PURE__ */ jsxs33("tr", { "aria-current": pick === i ? true : void 0, children: [
4520
4680
  /* @__PURE__ */ jsxs33("th", { scope: "row", children: [
4521
4681
  row.column.label,
4522
- row.column.estimated && /* @__PURE__ */ jsxs33(Fragment12, { children: [
4682
+ row.column.estimated && /* @__PURE__ */ jsxs33(Fragment13, { children: [
4523
4683
  " ",
4524
4684
  /* @__PURE__ */ jsx38("span", { className: "ui-chart__state", children: stateOf(row.column) })
4525
4685
  ] })