gridsmith-ui 0.10.0 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { useAppShell, ControlSizeContext, Button, Spinner, DrawerFooterCtx, useCompact, useElementWidth, Sheet, useCloseSettle, Drawer, useRememberedWidth, pxOf, ResizeEdge, useDirtyGuard, DiscardConfirm, defaultMaxWidth } from './chunk-YMUCTZXS.js';
2
- export { AppShell, Button, ButtonSizeContext, ControlSizeContext, Drawer, Sheet, SkipLink, Spinner, useAppShell } from './chunk-YMUCTZXS.js';
1
+ import { useAppShell, ControlSizeContext, Button, Spinner, OverlayCloseCtx, DrawerFooterCtx, useCompact, useElementWidth, Sheet, useCloseSettle, Drawer, useRememberedWidth, pxOf, ResizeEdge, useDirtyGuard, DiscardConfirm, defaultMaxWidth } from './chunk-HL3KYWOK.js';
2
+ export { AppShell, Button, ButtonSizeContext, ControlSizeContext, Drawer, Sheet, SkipLink, Spinner, useAppShell } from './chunk-HL3KYWOK.js';
3
3
  import { Skeleton } from './chunk-M3AARGLI.js';
4
4
  export { Skeleton } from './chunk-M3AARGLI.js';
5
5
  import { useOverlayLayer, useCloseOnFocusOut, focusInitial, rovingTabStop, OVERLAY_CLOSE_ATTR, useNonModalDialog, useFocusTrap } from './chunk-NHQCMOAN.js';
@@ -8,8 +8,8 @@ export { CodeBlock, Divider, Link } from './chunk-QJBCZ7BR.js';
8
8
  import { Badge } from './chunk-U2JT37GJ.js';
9
9
  export { Badge } from './chunk-U2JT37GJ.js';
10
10
  import { inferColumnKinds, CardValue } from './chunk-CR2KF73R.js';
11
- import { SplitPaneCtx, usePreferences, TableCardCtx, preferenceActionKey } from './chunk-QNVSMY4R.js';
12
- export { PreferencesContext, preferenceActionKey, usePreferences } from './chunk-QNVSMY4R.js';
11
+ import { SplitPaneCtx, useShellPreferences, TableCardCtx, PREFERENCE_HOUSE_DEFAULTS, preferenceActionKey } from './chunk-YO7JVPXK.js';
12
+ export { PreferencesContext, preferenceActionKey, usePreferences } from './chunk-YO7JVPXK.js';
13
13
  import { useBreakpoint } from './chunk-CRQ6KCRD.js';
14
14
  export { BreakpointWidthProvider, useBreakpoint } from './chunk-CRQ6KCRD.js';
15
15
  import { useTextOverflow, Tooltip, usePosition } from './chunk-IYD6ZDM2.js';
@@ -1220,7 +1220,7 @@ function parseTypedDate(text, dayFirst = localeDayFirst()) {
1220
1220
  const mi = monthIndex(m[2]);
1221
1221
  return mi < 0 ? null : validDate(Number(m[3]), mi, Number(m[1]));
1222
1222
  }
1223
- m = /^(\d{1,2})[/.\-](\d{1,2})[/.\-](\d{2,4})$/.exec(t);
1223
+ m = /^(\d{1,2})[/.-](\d{1,2})[/.-](\d{2,4})$/.exec(t);
1224
1224
  if (m) {
1225
1225
  const a = Number(m[1]), b = Number(m[2]);
1226
1226
  const year = m[3].length === 2 ? 2e3 + Number(m[3]) : Number(m[3]);
@@ -1246,26 +1246,6 @@ function DatePicker({ value, onChange, placeholder = "Pick a date", disabled, cl
1246
1246
  const firstDay = getFirstDayOfWeek(year, month);
1247
1247
  const today = useMemo(() => /* @__PURE__ */ new Date(), []);
1248
1248
  const isTopLayer = useOverlayLayer(open);
1249
- useEffect(() => {
1250
- if (!open) return;
1251
- const handler = (e) => {
1252
- const t = e.target;
1253
- if (triggerRef.current?.contains(t) || panelRef.current?.contains(t)) return;
1254
- setOpen(false);
1255
- };
1256
- const keyHandler = (e) => {
1257
- if (e.key === "Escape" && isTopLayer()) {
1258
- setOpen(false);
1259
- focusSegment(0);
1260
- }
1261
- };
1262
- document.addEventListener("mousedown", handler);
1263
- document.addEventListener("keydown", keyHandler);
1264
- return () => {
1265
- document.removeEventListener("mousedown", handler);
1266
- document.removeEventListener("keydown", keyHandler);
1267
- };
1268
- }, [open, isTopLayer]);
1269
1249
  const prevMonth = () => setViewDate(new Date(year, month - 1, 1));
1270
1250
  const nextMonth = () => setViewDate(new Date(year, month + 1, 1));
1271
1251
  const startOf = (d) => new Date(d.getFullYear(), d.getMonth(), d.getDate());
@@ -1280,18 +1260,39 @@ function DatePicker({ value, onChange, placeholder = "Pick a date", disabled, cl
1280
1260
  };
1281
1261
  const dayFirst = useMemo(() => localeDayFirst(), []);
1282
1262
  const [segs, setSegs] = useState(() => value ? { day: value.getDate(), month: value.getMonth() + 1, year: value.getFullYear() } : { day: null, month: null, year: null });
1283
- const buffers = useRef({});
1263
+ const [buffers, setBuffers] = useState({});
1284
1264
  const lastCommitted = useRef(null);
1285
1265
  useEffect(() => {
1286
1266
  if (value && value.getTime() === lastCommitted.current) return;
1287
1267
  setSegs(value ? { day: value.getDate(), month: value.getMonth() + 1, year: value.getFullYear() } : { day: null, month: null, year: null });
1288
- buffers.current = {};
1268
+ setBuffers({});
1289
1269
  }, [value]);
1290
1270
  const specs = dateSegments(dayFirst, segs.month && segs.year ? getDaysInMonth(segs.year, segs.month - 1) : 31);
1291
1271
  const segmentRefs = useRef([]);
1292
1272
  const focusSegment = (i) => {
1293
1273
  segmentRefs.current[Math.max(0, Math.min(specs.length - 1, i))]?.focus();
1294
1274
  };
1275
+ const focusSegmentRef = useLatest(focusSegment);
1276
+ useEffect(() => {
1277
+ if (!open) return;
1278
+ const handler = (e) => {
1279
+ const t = e.target;
1280
+ if (triggerRef.current?.contains(t) || panelRef.current?.contains(t)) return;
1281
+ setOpen(false);
1282
+ };
1283
+ const keyHandler = (e) => {
1284
+ if (e.key === "Escape" && isTopLayer()) {
1285
+ setOpen(false);
1286
+ focusSegmentRef.current(0);
1287
+ }
1288
+ };
1289
+ document.addEventListener("mousedown", handler);
1290
+ document.addEventListener("keydown", keyHandler);
1291
+ return () => {
1292
+ document.removeEventListener("mousedown", handler);
1293
+ document.removeEventListener("keydown", keyHandler);
1294
+ };
1295
+ }, [open, isTopLayer, focusSegmentRef]);
1295
1296
  const [typedInvalid, setTypedInvalid] = useState(false);
1296
1297
  const commitIfComplete = (next) => {
1297
1298
  if (next.day === null || next.month === null || next.year === null) {
@@ -1319,7 +1320,7 @@ function DatePicker({ value, onChange, placeholder = "Pick a date", disabled, cl
1319
1320
  if (!d) return;
1320
1321
  const next = { day: d.getDate(), month: d.getMonth() + 1, year: d.getFullYear() };
1321
1322
  setSegs(next);
1322
- buffers.current = {};
1323
+ setBuffers({});
1323
1324
  commitIfComplete(next);
1324
1325
  };
1325
1326
  const onSegmentKeyDown = (e, index, spec) => {
@@ -1327,6 +1328,7 @@ function DatePicker({ value, onChange, placeholder = "Pick a date", disabled, cl
1327
1328
  if (key === "Tab" || key === "Shift" || key === "Escape" || key.startsWith("F")) return;
1328
1329
  e.preventDefault();
1329
1330
  const k = spec.key;
1331
+ const clearBuffer = () => setBuffers((b) => ({ ...b, [k]: "" }));
1330
1332
  if (key === "ArrowLeft") {
1331
1333
  focusSegment(index - 1);
1332
1334
  return;
@@ -1336,39 +1338,39 @@ function DatePicker({ value, onChange, placeholder = "Pick a date", disabled, cl
1336
1338
  return;
1337
1339
  }
1338
1340
  if (key === "ArrowUp" || key === "ArrowDown") {
1339
- buffers.current[k] = "";
1341
+ clearBuffer();
1340
1342
  setSegment(k, stepValue(spec, segs[k], key === "ArrowUp" ? 1 : -1));
1341
1343
  return;
1342
1344
  }
1343
1345
  if (key === "Home") {
1344
- buffers.current[k] = "";
1346
+ clearBuffer();
1345
1347
  setSegment(k, spec.min);
1346
1348
  return;
1347
1349
  }
1348
1350
  if (key === "End") {
1349
- buffers.current[k] = "";
1351
+ clearBuffer();
1350
1352
  setSegment(k, spec.max);
1351
1353
  return;
1352
1354
  }
1353
1355
  if (key === "Backspace" || key === "Delete") {
1354
- if (segs[k] === null && !buffers.current[k]) {
1356
+ if (segs[k] === null && !buffers[k]) {
1355
1357
  focusSegment(index - 1);
1356
1358
  return;
1357
1359
  }
1358
- buffers.current[k] = "";
1360
+ clearBuffer();
1359
1361
  setSegment(k, null, false);
1360
1362
  return;
1361
1363
  }
1362
1364
  if (/^\d$/.test(key)) {
1363
- const r = typeDigit(spec, buffers.current[k] ?? "", key);
1364
- buffers.current[k] = r.advance ? "" : r.buffer;
1365
+ const r = typeDigit(spec, buffers[k] ?? "", key);
1366
+ setBuffers((b) => ({ ...b, [k]: r.advance ? "" : r.buffer }));
1365
1367
  setSegment(k, r.value);
1366
1368
  if (r.advance) focusSegment(index + 1);
1367
1369
  }
1368
1370
  };
1369
1371
  const shown = (spec) => {
1370
1372
  const k = spec.key;
1371
- const b = buffers.current[k];
1373
+ const b = buffers[k];
1372
1374
  if (b && segs[k] === null) return b;
1373
1375
  if (segs[k] === null) return spec.placeholder;
1374
1376
  return k === "year" ? String(segs[k]) : pad2(segs[k]);
@@ -1444,7 +1446,7 @@ function DatePicker({ value, onChange, placeholder = "Pick a date", disabled, cl
1444
1446
  "aria-valuetext": segs[k] === null ? "empty" : String(segs[k]),
1445
1447
  onKeyDown: (e) => onSegmentKeyDown(e, i, spec),
1446
1448
  onClick: (e) => e.stopPropagation(),
1447
- className: cn("rounded-[var(--ds-radius-sm)] px-[2px] outline-none focus:bg-[var(--ds-accent-subtle)] focus:text-[var(--ds-accent-primary)] cursor-text", segs[k] === null && !buffers.current[k] && "text-[var(--ds-text-muted)]"),
1449
+ className: cn("rounded-[var(--ds-radius-sm)] px-[2px] outline-none focus:bg-[var(--ds-accent-subtle)] focus:text-[var(--ds-accent-primary)] cursor-text", segs[k] === null && !buffers[k] && "text-[var(--ds-text-muted)]"),
1448
1450
  children: shown(spec)
1449
1451
  }
1450
1452
  )
@@ -2288,6 +2290,12 @@ function SliderRange({
2288
2290
  )
2289
2291
  ] });
2290
2292
  }
2293
+ function fromValue(v, use24Hour) {
2294
+ const m = /^(\d{1,2}):(\d{2})$/.exec(v);
2295
+ if (!m) return { hour: null, minute: null, period: null };
2296
+ const h24 = Number(m[1]);
2297
+ return use24Hour ? { hour: h24, minute: Number(m[2]), period: null } : { hour: h24 % 12 === 0 ? 12 : h24 % 12, minute: Number(m[2]), period: h24 >= 12 ? "PM" : "AM" };
2298
+ }
2291
2299
  var CONTROL_HEIGHT4 = {
2292
2300
  sm: "h-[var(--ds-control-height-sm)]",
2293
2301
  md: "h-[var(--ds-control-height-md)]",
@@ -2365,25 +2373,6 @@ function TimePicker({
2365
2373
  const minutes = generateMinutes(minuteStep);
2366
2374
  const isTopLayer = useOverlayLayer(open);
2367
2375
  useCloseOnFocusOut(open, triggerRef, panelRef, () => setOpen(false), isTopLayer);
2368
- useEffect(() => {
2369
- if (!open) return;
2370
- const handler = (e) => {
2371
- if (triggerRef.current?.contains(e.target) || panelRef.current?.contains(e.target)) return;
2372
- setOpen(false);
2373
- };
2374
- const keyHandler = (e) => {
2375
- if (e.key === "Escape" && isTopLayer()) {
2376
- setOpen(false);
2377
- focusSegment(0);
2378
- }
2379
- };
2380
- document.addEventListener("mousedown", handler);
2381
- document.addEventListener("keydown", keyHandler);
2382
- return () => {
2383
- document.removeEventListener("mousedown", handler);
2384
- document.removeEventListener("keydown", keyHandler);
2385
- };
2386
- }, [open, isTopLayer]);
2387
2376
  useEffect(() => {
2388
2377
  if (!open) return;
2389
2378
  const id2 = requestAnimationFrame(() => {
@@ -2421,19 +2410,13 @@ function TimePicker({
2421
2410
  onChange(`${pad(h24)}:${pad(minute)}`);
2422
2411
  }
2423
2412
  const specs = timeSegments(use24Hour);
2424
- const fromValue = (v) => {
2425
- const m = /^(\d{1,2}):(\d{2})$/.exec(v);
2426
- if (!m) return { hour: null, minute: null, period: null };
2427
- const h24 = Number(m[1]);
2428
- return use24Hour ? { hour: h24, minute: Number(m[2]), period: null } : { hour: h24 % 12 === 0 ? 12 : h24 % 12, minute: Number(m[2]), period: h24 >= 12 ? "PM" : "AM" };
2429
- };
2430
- const [segs, setSegs] = useState(() => fromValue(value));
2431
- const buffers = useRef({});
2413
+ const [segs, setSegs] = useState(() => fromValue(value, use24Hour));
2414
+ const [buffers, setBuffers] = useState({});
2432
2415
  const lastCommitted = useRef(null);
2433
2416
  useEffect(() => {
2434
2417
  if (value === lastCommitted.current) return;
2435
- setSegs(fromValue(value));
2436
- buffers.current = {};
2418
+ setSegs(fromValue(value, use24Hour));
2419
+ setBuffers({});
2437
2420
  }, [value, use24Hour]);
2438
2421
  const segmentRefs = useRef([]);
2439
2422
  const segmentCount = specs.length + (use24Hour ? 0 : 1);
@@ -2441,6 +2424,26 @@ function TimePicker({
2441
2424
  const el = segmentRefs.current[Math.max(0, Math.min(segmentCount - 1, i))];
2442
2425
  el?.focus();
2443
2426
  };
2427
+ const focusSegmentRef = useLatest(focusSegment);
2428
+ useEffect(() => {
2429
+ if (!open) return;
2430
+ const handler = (e) => {
2431
+ if (triggerRef.current?.contains(e.target) || panelRef.current?.contains(e.target)) return;
2432
+ setOpen(false);
2433
+ };
2434
+ const keyHandler = (e) => {
2435
+ if (e.key === "Escape" && isTopLayer()) {
2436
+ setOpen(false);
2437
+ focusSegmentRef.current(0);
2438
+ }
2439
+ };
2440
+ document.addEventListener("mousedown", handler);
2441
+ document.addEventListener("keydown", keyHandler);
2442
+ return () => {
2443
+ document.removeEventListener("mousedown", handler);
2444
+ document.removeEventListener("keydown", keyHandler);
2445
+ };
2446
+ }, [open, isTopLayer, focusSegmentRef]);
2444
2447
  const commitIfComplete = (next) => {
2445
2448
  if (next.hour === null || next.minute === null) return;
2446
2449
  let h24 = next.hour;
@@ -2462,9 +2465,9 @@ function TimePicker({
2462
2465
  const applyTyped = (text) => {
2463
2466
  const parsed2 = parseTypedTime(text, use24Hour);
2464
2467
  if (!parsed2) return;
2465
- const next = fromValue(parsed2);
2468
+ const next = fromValue(parsed2, use24Hour);
2466
2469
  setSegs(next);
2467
- buffers.current = {};
2470
+ setBuffers({});
2468
2471
  commitIfComplete(next);
2469
2472
  };
2470
2473
  const onSegmentKeyDown = (e, index, spec) => {
@@ -2489,33 +2492,34 @@ function TimePicker({
2489
2492
  return;
2490
2493
  }
2491
2494
  const k = spec.key;
2495
+ const clearBuffer = () => setBuffers((b) => ({ ...b, [k]: "" }));
2492
2496
  if (key === "ArrowUp" || key === "ArrowDown") {
2493
- buffers.current[k] = "";
2497
+ clearBuffer();
2494
2498
  setSegment(k, stepValue(spec, segs[k], key === "ArrowUp" ? 1 : -1));
2495
2499
  return;
2496
2500
  }
2497
2501
  if (key === "Home") {
2498
- buffers.current[k] = "";
2502
+ clearBuffer();
2499
2503
  setSegment(k, spec.min);
2500
2504
  return;
2501
2505
  }
2502
2506
  if (key === "End") {
2503
- buffers.current[k] = "";
2507
+ clearBuffer();
2504
2508
  setSegment(k, spec.max);
2505
2509
  return;
2506
2510
  }
2507
2511
  if (key === "Backspace" || key === "Delete") {
2508
- if (segs[k] === null && !buffers.current[k]) {
2512
+ if (segs[k] === null && !buffers[k]) {
2509
2513
  focusSegment(index - 1);
2510
2514
  return;
2511
2515
  }
2512
- buffers.current[k] = "";
2516
+ clearBuffer();
2513
2517
  setSegment(k, null, false);
2514
2518
  return;
2515
2519
  }
2516
2520
  if (/^\d$/.test(key)) {
2517
- const r = typeDigit(spec, buffers.current[k] ?? "", key);
2518
- buffers.current[k] = r.advance ? "" : r.buffer;
2521
+ const r = typeDigit(spec, buffers[k] ?? "", key);
2522
+ setBuffers((b) => ({ ...b, [k]: r.advance ? "" : r.buffer }));
2519
2523
  setSegment(k, r.value);
2520
2524
  if (r.advance) focusSegment(index + 1);
2521
2525
  return;
@@ -2526,7 +2530,7 @@ function TimePicker({
2526
2530
  }
2527
2531
  };
2528
2532
  const shown = (k, spec) => {
2529
- const b = buffers.current[k];
2533
+ const b = buffers[k];
2530
2534
  if (b && segs[k] === null) return b;
2531
2535
  return segs[k] === null ? spec.placeholder : pad2(segs[k]);
2532
2536
  };
@@ -2585,7 +2589,7 @@ function TimePicker({
2585
2589
  "aria-valuetext": segs[k] === null ? "empty" : pad2(segs[k]),
2586
2590
  onKeyDown: (e) => onSegmentKeyDown(e, i, spec),
2587
2591
  onClick: (e) => e.stopPropagation(),
2588
- className: cn("rounded-[var(--ds-radius-sm)] px-[2px] outline-none focus:bg-[var(--ds-accent-subtle)] focus:text-[var(--ds-accent-primary)] cursor-text", segs[k] === null && !buffers.current[k] && "text-[var(--ds-text-muted)]"),
2592
+ className: cn("rounded-[var(--ds-radius-sm)] px-[2px] outline-none focus:bg-[var(--ds-accent-subtle)] focus:text-[var(--ds-accent-primary)] cursor-text", segs[k] === null && !buffers[k] && "text-[var(--ds-text-muted)]"),
2589
2593
  children: shown(k, spec)
2590
2594
  }
2591
2595
  )
@@ -3855,10 +3859,19 @@ function collectInvalidFields(form) {
3855
3859
  }
3856
3860
  return out;
3857
3861
  }
3858
- function FormWrapper({ onSubmit, validationMode: validationModeProp, children, actions, actionsAlign: actionsAlignProp, focusFirstError = true, errorSummary = true, className, ref }) {
3859
- const preferences = usePreferences();
3862
+ function FormWrapper({ onSubmit, validationMode: validationModeProp, children, actions: actionsProp, actionsAlign: actionsAlignProp, onCancel, cancelLabel = "Cancel", focusFirstError = true, errorSummary = true, className, ref }) {
3863
+ const preferences = useShellPreferences();
3860
3864
  const validationMode = validationModeProp ?? preferences.validationTiming ?? "onSubmit";
3861
3865
  const actionsAlign = actionsAlignProp ?? preferences.formActions?.align ?? "end";
3866
+ const overlayClose = useContext(OverlayCloseCtx);
3867
+ const actions = useMemo(() => {
3868
+ if (!onCancel) return actionsProp;
3869
+ const cancel = /* @__PURE__ */ jsx(Button, { type: "button", variant: "secondary", onClick: () => (overlayClose ?? onCancel)(), children: cancelLabel }, "gs-form-cancel");
3870
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
3871
+ cancel,
3872
+ actionsProp
3873
+ ] });
3874
+ }, [actionsProp, onCancel, overlayClose, cancelLabel]);
3862
3875
  const [errors, setErrors] = useState({});
3863
3876
  const [submitted, setSubmitted] = useState(false);
3864
3877
  const [submitCount, setSubmitCount] = useState(0);
@@ -4197,6 +4210,17 @@ function PanelCheckbox({ checked, indeterminate, onClick, label }) {
4197
4210
  }
4198
4211
  );
4199
4212
  }
4213
+
4214
+ // ../../showcase/src/lib/initials.ts
4215
+ function initialsOf(name) {
4216
+ return name.trim().split(/\s+/).filter(Boolean).slice(0, 2).map((word) => Array.from(word)[0] ?? "").join("").toUpperCase();
4217
+ }
4218
+ function toInitials(value) {
4219
+ const s = value.trim();
4220
+ if (!s) return "";
4221
+ if (!/\s/.test(s) && Array.from(s).length <= 3) return s;
4222
+ return initialsOf(s);
4223
+ }
4200
4224
  var variantColors = {
4201
4225
  success: "bg-[var(--ds-status-success)]",
4202
4226
  warning: "bg-[var(--ds-status-warning)]",
@@ -4305,7 +4329,7 @@ function Avatar({ initials, src, alt, size = "md", status, color = "auto", class
4305
4329
  colorStyles(color, alt ?? initials ?? ""),
4306
4330
  "border-[length:var(--ds-border-width)] border-transparent"
4307
4331
  ),
4308
- children: initials
4332
+ children: initials != null ? toInitials(initials) : null
4309
4333
  }
4310
4334
  );
4311
4335
  if (!status) return avatarElement;
@@ -5239,7 +5263,7 @@ function Table({
5239
5263
  (col) => col.kind ?? inferredKinds.get(col.key),
5240
5264
  [inferredKinds]
5241
5265
  );
5242
- const preferences = usePreferences();
5266
+ const preferences = useShellPreferences();
5243
5267
  const mobileBreakpoint = mobileBreakpointProp ?? preferences.tableToCardsBreakpoint ?? "md";
5244
5268
  const isMobile = useBreakpoint(mobileBreakpoint);
5245
5269
  if (isMobile) {
@@ -7204,7 +7228,7 @@ function renderIcon(icon) {
7204
7228
  return icon;
7205
7229
  }
7206
7230
  function EmptyState({ icon, iconFrame = "circle", title, description, action, variant = "empty", bordered = false, style: styleProp, className }) {
7207
- const preferences = usePreferences();
7231
+ const preferences = useShellPreferences();
7208
7232
  const style = styleProp ?? (preferences.emptyStyle === "text-cta" ? "text" : "illustration");
7209
7233
  const iconNode = style === "text" ? void 0 : icon === void 0 || icon === null ? void 0 : renderIcon(icon);
7210
7234
  return /* @__PURE__ */ jsxs(
@@ -7227,9 +7251,6 @@ function EmptyState({ icon, iconFrame = "circle", title, description, action, va
7227
7251
  }
7228
7252
  );
7229
7253
  }
7230
- function initialsOf(name) {
7231
- return name.trim().split(/\s+/).slice(0, 2).map((w) => w[0] ?? "").join("").toUpperCase();
7232
- }
7233
7254
  function looksLikeUrl(s) {
7234
7255
  return /^(?:https?:|data:|blob:|\/|\.{1,2}\/)/.test(s) || /\.[a-z]{2,5}(?:$|[?#])/i.test(s);
7235
7256
  }
@@ -7285,6 +7306,7 @@ function TableToolbar({
7285
7306
  onClearAll,
7286
7307
  resultCount,
7287
7308
  resultNoun = ["result", "results"],
7309
+ pagination,
7288
7310
  actions,
7289
7311
  size = "sm",
7290
7312
  compactBreakpoint = 680,
@@ -7304,8 +7326,14 @@ function TableToolbar({
7304
7326
  const hasChips = !!activeFilters?.length;
7305
7327
  const inPane = useContext(SplitPaneCtx);
7306
7328
  const searchFills = inPane || !primaryFilter && !filters && !actions;
7307
- return /* @__PURE__ */ jsx(ControlSizeContext.Provider, { value: size, children: /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-ds-3 min-w-0", className), "data-table-toolbar": "", children: [
7308
- /* @__PURE__ */ jsxs("div", { ref: rowRef, className: "flex items-center gap-ds-2 flex-wrap", children: [
7329
+ const hasControls = !!(search || primaryFilter || filters || actions);
7330
+ const noun = (n) => n === 1 ? resultNoun[0] : resultNoun[1];
7331
+ const total = resultCount ?? pagination?.totalItems;
7332
+ const paged = total !== void 0 && !!pagination && pagination.pageSize > 0 && total > pagination.pageSize;
7333
+ const countText = total === void 0 ? null : paged ? `Showing ${Math.min((pagination.page - 1) * pagination.pageSize + 1, total)}\u2013${Math.min(pagination.page * pagination.pageSize, total)} of ${total} ${noun(total)}` : resultCount !== void 0 ? `${resultCount} ${noun(resultCount)}` : null;
7334
+ if (!hasControls && countText === null && !hasChips) return null;
7335
+ return /* @__PURE__ */ jsx(ControlSizeContext.Provider, { value: size, children: /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-ds-3 min-w-0 mb-ds-3 last:mb-0", className), "data-table-toolbar": "", children: [
7336
+ hasControls && /* @__PURE__ */ jsxs("div", { ref: rowRef, className: "flex items-center gap-ds-2 flex-wrap", children: [
7309
7337
  search && /* @__PURE__ */ jsx(
7310
7338
  Input,
7311
7339
  {
@@ -7358,12 +7386,8 @@ function TableToolbar({
7358
7386
  ] })
7359
7387
  ] }),
7360
7388
  filters && open && /* @__PURE__ */ jsx("div", { id: filterRowId, className: "flex items-center gap-ds-3 flex-wrap", children: filters }),
7361
- (resultCount !== void 0 || hasChips) && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-ds-2 flex-wrap", children: [
7362
- resultCount !== void 0 && /* @__PURE__ */ jsxs("span", { className: "text-xs text-[var(--ds-text-muted)]", "aria-live": "polite", children: [
7363
- resultCount,
7364
- " ",
7365
- resultCount === 1 ? resultNoun[0] : resultNoun[1]
7366
- ] }),
7389
+ (countText !== null || hasChips) && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-ds-2 flex-wrap", children: [
7390
+ countText !== null && /* @__PURE__ */ jsx("span", { className: "text-xs text-[var(--ds-text-muted)]", "aria-live": "polite", "data-result-count": "", children: countText }),
7367
7391
  activeFilters?.map((f) => /* @__PURE__ */ jsx(Tag, { size: "sm", variant: "subtle", onRemove: f.onRemove, children: f.label }, f.id)),
7368
7392
  hasChips && onClearAll && /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", onClick: onClearAll, children: "Clear all" })
7369
7393
  ] })
@@ -8393,16 +8417,18 @@ var TOAST_INSET_VARS = {
8393
8417
  "bottom-right": "--ds-toast-inset-bottom-right",
8394
8418
  "bottom-left": "--ds-toast-inset-bottom-left",
8395
8419
  right: "--ds-toast-inset-right",
8396
- left: "--ds-toast-inset-left"
8420
+ left: "--ds-toast-inset-left",
8421
+ top: "--ds-toast-inset-top"
8397
8422
  };
8398
8423
  var LAUNCHER_INSET_PRIORITY = 1;
8399
8424
  var PANEL_INSET_PRIORITY = 2;
8425
+ var NAVBAR_INSET_PRIORITY = 1;
8400
8426
  var registry = /* @__PURE__ */ new WeakMap();
8401
8427
  var seq = 0;
8402
8428
  function claimsFor(target) {
8403
8429
  let entry = registry.get(target);
8404
8430
  if (!entry) {
8405
- entry = { "bottom-right": [], "bottom-left": [], right: [], left: [] };
8431
+ entry = { "bottom-right": [], "bottom-left": [], right: [], left: [], top: [] };
8406
8432
  registry.set(target, entry);
8407
8433
  }
8408
8434
  return entry;
@@ -9823,7 +9849,7 @@ function Popover({ open, onOpenChange, trigger, children, side = "bottom", align
9823
9849
  }
9824
9850
  function Pagination({ currentPage, totalPages, onPageChange, pageSize: pageSizeProp, pageSizeOptions, onPageSizeChange, className }) {
9825
9851
  const pages = buildPageRange(currentPage, totalPages);
9826
- const preferences = usePreferences();
9852
+ const preferences = useShellPreferences();
9827
9853
  const pageSize = pageSizeProp ?? preferences.itemsPerPage;
9828
9854
  return /* @__PURE__ */ jsxs("nav", { "aria-label": "Pagination", className: cn("flex flex-wrap items-center gap-ds-3", className), children: [
9829
9855
  pageSizeOptions && pageSize != null && onPageSizeChange && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-ds-2", children: [
@@ -12608,6 +12634,31 @@ var Navbar = forwardRef(function Navbar2({
12608
12634
  ro.observe(header);
12609
12635
  return () => ro.disconnect();
12610
12636
  }, [mobileHidesLinks, links]);
12637
+ const [topInset, setTopInset] = useState(null);
12638
+ const shellEl = appShell?.container ?? null;
12639
+ useLayoutEffect(() => {
12640
+ const header = headerRef.current;
12641
+ if (!shellEl || !header) {
12642
+ setTopInset(null);
12643
+ return;
12644
+ }
12645
+ const measure = () => {
12646
+ const shell = shellEl.getBoundingClientRect();
12647
+ const fillsWindow = shell.top <= 1 && shell.height >= window.innerHeight - 1;
12648
+ const bottom = Math.round(header.getBoundingClientRect().bottom);
12649
+ setTopInset(fillsWindow && bottom > 0 ? `calc(${bottom}px + var(--ds-space-3))` : null);
12650
+ };
12651
+ measure();
12652
+ window.addEventListener("resize", measure);
12653
+ const ro = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(measure);
12654
+ ro?.observe(header);
12655
+ ro?.observe(shellEl);
12656
+ return () => {
12657
+ window.removeEventListener("resize", measure);
12658
+ ro?.disconnect();
12659
+ };
12660
+ }, [shellEl]);
12661
+ useCornerInset(topInset ? "top" : null, topInset, NAVBAR_INSET_PRIORITY);
12611
12662
  const hidden = useMemo(() => {
12612
12663
  if (visibleCount === null || links.length === 0) return /* @__PURE__ */ new Set();
12613
12664
  return new Set(links.map((_, i) => i).filter((i) => i >= visibleCount));
@@ -12957,7 +13008,7 @@ function Dialog({ open, onClose: onCloseProp, title, description, children, foot
12957
13008
  }
12958
13009
  ),
12959
13010
  description && /* @__PURE__ */ jsx("p", { id: descriptionId, className: "mt-ds-2 text-sm text-[var(--ds-text-muted)]", children: description }),
12960
- children && /* @__PURE__ */ jsx("div", { className: "mt-ds-4", children })
13011
+ children && /* @__PURE__ */ jsx("div", { className: "mt-ds-4", children: /* @__PURE__ */ jsx(OverlayCloseCtx, { value: onClose, children }) })
12961
13012
  ] })
12962
13013
  ] }) }),
12963
13014
  /* @__PURE__ */ jsx(DiscardConfirm, { open: guard.confirming, onKeep: guard.keep, onDiscard: guard.discard }),
@@ -13834,11 +13885,11 @@ var variantIcons = {
13834
13885
  error: { name: "error", className: "text-[var(--ds-status-error)]" }
13835
13886
  };
13836
13887
  var TOAST_POSITION_CLASSES = {
13837
- "top-right": "top-ds-4 right-[var(--ds-toast-inset-right)]",
13838
- "top-left": "top-ds-4 left-[var(--ds-toast-inset-left)]",
13888
+ "top-right": "top-[var(--ds-toast-inset-top)] right-[var(--ds-toast-inset-right)]",
13889
+ "top-left": "top-[var(--ds-toast-inset-top)] left-[var(--ds-toast-inset-left)]",
13839
13890
  "bottom-right": "bottom-[var(--ds-toast-inset-bottom-right)] right-[var(--ds-toast-inset-right)]",
13840
13891
  "bottom-left": "bottom-[var(--ds-toast-inset-bottom-left)] left-[var(--ds-toast-inset-left)]",
13841
- "top-center": "top-ds-4 left-1/2 -translate-x-1/2",
13892
+ "top-center": "top-[var(--ds-toast-inset-top)] left-1/2 -translate-x-1/2",
13842
13893
  "bottom-center": "bottom-ds-4 left-1/2 -translate-x-1/2"
13843
13894
  };
13844
13895
  function Toast({ variant = "default", message, visible, onDismiss, duration = 5e3, pauseOnHover = false, action, position = "bottom-right", mode, container, inline = false }) {
@@ -14036,9 +14087,62 @@ function ToastProvider({ children, maxVisible = 1, position = "bottom-right", du
14036
14087
  )
14037
14088
  ] });
14038
14089
  }
14090
+ function firstKey(item) {
14091
+ if (item !== null && typeof item === "object") return "id" in item ? item.id : void 0;
14092
+ return item;
14093
+ }
14094
+ function signature(list, resetOn) {
14095
+ let reset = "";
14096
+ try {
14097
+ reset = JSON.stringify(resetOn ?? null);
14098
+ } catch {
14099
+ reset = String(resetOn);
14100
+ }
14101
+ let first = "";
14102
+ try {
14103
+ first = JSON.stringify(firstKey(list[0]) ?? null);
14104
+ } catch {
14105
+ first = "";
14106
+ }
14107
+ return `${list.length}|${first}|${reset}`;
14108
+ }
14109
+ function usePagination(list, options = {}) {
14110
+ const shell = useShellPreferences();
14111
+ const [chosenSize, setChosenSize] = useState(null);
14112
+ const pageSize = Math.max(1, Math.floor(chosenSize ?? options.pageSize ?? shell.itemsPerPage ?? PREFERENCE_HOUSE_DEFAULTS.itemsPerPage));
14113
+ const [page, setPageState] = useState(1);
14114
+ const sig = signature(list, options.resetOn);
14115
+ const [seen, setSeen] = useState(sig);
14116
+ if (seen !== sig) {
14117
+ setSeen(sig);
14118
+ if (page !== 1) setPageState(1);
14119
+ }
14120
+ const totalItems = list.length;
14121
+ const totalPages = Math.max(1, Math.ceil(totalItems / pageSize));
14122
+ const current = Math.min(Math.max(1, seen !== sig ? 1 : page), totalPages);
14123
+ const start = (current - 1) * pageSize;
14124
+ const items = list.slice(start, start + pageSize);
14125
+ const range = totalItems === 0 ? [0, 0] : [start + 1, start + items.length];
14126
+ const setPage = (next) => setPageState(Math.min(Math.max(1, Math.floor(next)), totalPages));
14127
+ const setPageSize = (size) => {
14128
+ setChosenSize(Math.max(1, Math.floor(size)));
14129
+ setPageState(1);
14130
+ };
14131
+ return {
14132
+ items,
14133
+ page: current,
14134
+ pageSize,
14135
+ totalItems,
14136
+ totalPages,
14137
+ range,
14138
+ setPage,
14139
+ setPageSize,
14140
+ props: { currentPage: current, totalPages, onPageChange: setPage, pageSize, onPageSizeChange: setPageSize }
14141
+ };
14142
+ }
14039
14143
  function useDestructiveAction(options) {
14040
14144
  const { action, title, description, confirmLabel, typeToConfirm, onConfirm, onUndo, undoMessage, severity } = options;
14041
- const preferences = usePreferences();
14145
+ const preferences = useShellPreferences();
14042
14146
  const toast = useToastOptional();
14043
14147
  const [open, setOpen] = useState(false);
14044
14148
  const [typed, setTyped] = useState("");
@@ -14244,6 +14348,6 @@ var TextOverflow = forwardRef(function TextOverflow2({
14244
14348
  return /* @__PURE__ */ jsx(Tooltip, { content: resolvedTooltipContent, children: content });
14245
14349
  });
14246
14350
 
14247
- export { Accordion, ActionPanel, ActionPanelGroup, Alert, AsidePanel, Avatar, AvatarGroup, BottomNav, Breadcrumbs, BulkActionBar, Calendar, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Carousel, ChatMessageList, ChatPanel, Checkbox, CheckboxGroup, CheckboxGroupItem, Collapsible, ColorPicker, Combobox, CommandPalette, ContextMenu, CornerPanel, DEFAULT_DATE_RANGE_PRESETS, DataList, DatePicker, DateRangePicker, DescriptionList, Dialog, Dock, Dropdown, DropdownMenu, EmptyState, EntityCell, Field, FileUpload, FormWrapper, HoverCard, InlineFieldError, Input, Kbd, Label, Launcher, MentionInput, MobileHeaderMenu, NavItem, NavMenu, Navbar, NotificationCenter, NumberInput, PageContainer, PageHeader, Pagination, PinInput, Popover, Progress, RadioGroup, Rating, ScrollArea, SectionHeading, SegmentedControl, SettingsLayout, Sidebar, SidebarNav, SliderRange, StackedList, StatsCard, StatusDot, Stepper, Table, TableToolbar, Tabs, Tag, TagInput, TextOverflow, Textarea, TimePicker, Timeline, Toast, ToastProvider, Toggle, Tour, TransferList, TreeView, useContentWidth, useDestructiveAction, useFormContext, useSidebar, useToast, useToastOptional };
14351
+ export { Accordion, ActionPanel, ActionPanelGroup, Alert, AsidePanel, Avatar, AvatarGroup, BottomNav, Breadcrumbs, BulkActionBar, Calendar, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Carousel, ChatMessageList, ChatPanel, Checkbox, CheckboxGroup, CheckboxGroupItem, Collapsible, ColorPicker, Combobox, CommandPalette, ContextMenu, CornerPanel, DEFAULT_DATE_RANGE_PRESETS, DataList, DatePicker, DateRangePicker, DescriptionList, Dialog, Dock, Dropdown, DropdownMenu, EmptyState, EntityCell, Field, FileUpload, FormWrapper, HoverCard, InlineFieldError, Input, Kbd, Label, Launcher, MentionInput, MobileHeaderMenu, NavItem, NavMenu, Navbar, NotificationCenter, NumberInput, PageContainer, PageHeader, Pagination, PinInput, Popover, Progress, RadioGroup, Rating, ScrollArea, SectionHeading, SegmentedControl, SettingsLayout, Sidebar, SidebarNav, SliderRange, StackedList, StatsCard, StatusDot, Stepper, Table, TableToolbar, Tabs, Tag, TagInput, TextOverflow, Textarea, TimePicker, Timeline, Toast, ToastProvider, Toggle, Tour, TransferList, TreeView, useContentWidth, useDestructiveAction, useFormContext, usePagination, useSidebar, useToast, useToastOptional };
14248
14352
  //# sourceMappingURL=index.js.map
14249
14353
  //# sourceMappingURL=index.js.map