gridsmith-ui 0.30.0 → 0.30.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.
Files changed (64) hide show
  1. package/CHANGELOG.md +41 -1
  2. package/dist/charts.js +21 -8
  3. package/dist/charts.js.map +1 -1
  4. package/dist/chat.js +7 -7
  5. package/dist/{chunk-INGF2CPW.js → chunk-6C2IUMY7.js} +3 -3
  6. package/dist/{chunk-INGF2CPW.js.map → chunk-6C2IUMY7.js.map} +1 -1
  7. package/dist/{chunk-RHWTMTU5.js → chunk-DBHVJ7Z3.js} +5 -49
  8. package/dist/chunk-DBHVJ7Z3.js.map +1 -0
  9. package/dist/chunk-IELIF4PJ.js +110 -0
  10. package/dist/chunk-IELIF4PJ.js.map +1 -0
  11. package/dist/{chunk-Z4MCD73B.js → chunk-ISONVOA7.js} +7 -7
  12. package/dist/{chunk-Z4MCD73B.js.map → chunk-ISONVOA7.js.map} +1 -1
  13. package/dist/{chunk-UNS4TGGK.js → chunk-KMKBOTFR.js} +78 -26
  14. package/dist/chunk-KMKBOTFR.js.map +1 -0
  15. package/dist/{chunk-6A5RHW2W.js → chunk-NEUWZUK6.js} +4 -5
  16. package/dist/chunk-NEUWZUK6.js.map +1 -0
  17. package/dist/{chunk-NLXQ323J.js → chunk-OVHBQT3Z.js} +5 -4
  18. package/dist/chunk-OVHBQT3Z.js.map +1 -0
  19. package/dist/{chunk-KTPGMJUK.js → chunk-OX3NNMWG.js} +4 -4
  20. package/dist/{chunk-KTPGMJUK.js.map → chunk-OX3NNMWG.js.map} +1 -1
  21. package/dist/{chunk-OIOII5L6.js → chunk-R5QXMNW7.js} +210 -17
  22. package/dist/chunk-R5QXMNW7.js.map +1 -0
  23. package/dist/chunk-SJZWEBHL.js +58 -0
  24. package/dist/chunk-SJZWEBHL.js.map +1 -0
  25. package/dist/{chunk-NI5542ZM.js → chunk-SLRTSBCJ.js} +58 -22
  26. package/dist/chunk-SLRTSBCJ.js.map +1 -0
  27. package/dist/{chunk-F2BNJSON.js → chunk-T52LAFKG.js} +71 -69
  28. package/dist/chunk-T52LAFKG.js.map +1 -0
  29. package/dist/{chunk-GQVBZ4GW.js → chunk-UDJOIVKQ.js} +5 -108
  30. package/dist/chunk-UDJOIVKQ.js.map +1 -0
  31. package/dist/{chunk-Q36JVJX4.js → chunk-ULCACQSA.js} +4 -4
  32. package/dist/{chunk-Q36JVJX4.js.map → chunk-ULCACQSA.js.map} +1 -1
  33. package/dist/{chunk-HP7WUZPK.js → chunk-WIUGPZOH.js} +10 -3
  34. package/dist/chunk-WIUGPZOH.js.map +1 -0
  35. package/dist/{chunk-JTU7OBYJ.js → chunk-YL5KD5RC.js} +4 -3
  36. package/dist/chunk-YL5KD5RC.js.map +1 -0
  37. package/dist/data-grid.js +9 -9
  38. package/dist/editor-mentions.js +4 -5
  39. package/dist/editor-mentions.js.map +1 -1
  40. package/dist/editor.js +9 -6
  41. package/dist/editor.js.map +1 -1
  42. package/dist/index.js +178 -91
  43. package/dist/index.js.map +1 -1
  44. package/dist/kanban.js +12 -11
  45. package/dist/kanban.js.map +1 -1
  46. package/dist/resizable.js +43 -13
  47. package/dist/resizable.js.map +1 -1
  48. package/dist/utils.js.map +1 -1
  49. package/dist/virtualized.d.ts +6 -1
  50. package/dist/virtualized.js +14 -11
  51. package/dist/virtualized.js.map +1 -1
  52. package/package.json +1 -1
  53. package/dist/chunk-6A5RHW2W.js.map +0 -1
  54. package/dist/chunk-F2BNJSON.js.map +0 -1
  55. package/dist/chunk-GQVBZ4GW.js.map +0 -1
  56. package/dist/chunk-HP7WUZPK.js.map +0 -1
  57. package/dist/chunk-JTU7OBYJ.js.map +0 -1
  58. package/dist/chunk-NI5542ZM.js.map +0 -1
  59. package/dist/chunk-NLXQ323J.js.map +0 -1
  60. package/dist/chunk-OIOII5L6.js.map +0 -1
  61. package/dist/chunk-RHWTMTU5.js.map +0 -1
  62. package/dist/chunk-UNS4TGGK.js.map +0 -1
  63. package/dist/chunk-WH2FUFAC.js +0 -15
  64. package/dist/chunk-WH2FUFAC.js.map +0 -1
@@ -1,16 +1,17 @@
1
1
  "use client";
2
+ import { useKeyboardScroll } from './chunk-SJZWEBHL.js';
2
3
  import { PreferencesContext } from './chunk-TYNDXMBV.js';
3
4
  import { FormChangeCtx } from './chunk-72SDAX54.js';
4
- import { SurfaceBoundary, Button } from './chunk-Q36JVJX4.js';
5
+ import { SurfaceBoundary, Button } from './chunk-ULCACQSA.js';
5
6
  import { useBreakpoint, readBreakpointPx } from './chunk-ZHUVLBCC.js';
6
7
  import { useRevealFocus } from './chunk-HTXP5BMM.js';
7
- import { usePopupFocus, useOverlayLayer, useReturnFocus, useFocusTrap, focusInitial, useNonModalDialog, OVERLAY_CLOSE_ATTR } from './chunk-OIOII5L6.js';
8
- import { useTextOverflow, AutoTooltip } from './chunk-GQVBZ4GW.js';
8
+ import { usePopupFocus, useOverlayLayer, useReturnFocus, useFocusTrap, inertOutside, focusInitial, useNonModalDialog, OVERLAY_CLOSE_ATTR } from './chunk-R5QXMNW7.js';
9
+ import { useTextOverflow } from './chunk-IELIF4PJ.js';
10
+ import { AutoTooltip } from './chunk-UDJOIVKQ.js';
9
11
  import { Icon } from './chunk-L6HWACK7.js';
10
- import { usePosition } from './chunk-HP7WUZPK.js';
11
- import { useLatest } from './chunk-WH2FUFAC.js';
12
- import { cn, FOCUS_RING, FOCUS_INSET, lockBodyScroll, unlockBodyScroll, OVERLAY_SURFACE, GLASS_OVERLAY, GROUP_FOCUS_RING } from './chunk-JTU7OBYJ.js';
13
- import { createContext, version, forwardRef, useState, useCallback, useRef, useEffect, useContext, useMemo, useId, useLayoutEffect } from 'react';
12
+ import { usePosition, useLatest } from './chunk-WIUGPZOH.js';
13
+ import { cn, FOCUS_INSET_WHILE_STOP, FOCUS_RING, FOCUS_INSET, lockBodyScroll, unlockBodyScroll, OVERLAY_SURFACE, GLASS_OVERLAY, GROUP_FOCUS_RING } from './chunk-YL5KD5RC.js';
14
+ import { createContext, version, forwardRef, useState, useCallback, useRef, useId, useEffect, useContext, useMemo, useLayoutEffect } from 'react';
14
15
  import { createPortal } from 'react-dom';
15
16
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
16
17
 
@@ -268,6 +269,7 @@ function useOverlayMark(open) {
268
269
  const round = useRef(0);
269
270
  const [changed, setChanged] = useState(false);
270
271
  const [holds, setHolds] = useState(0);
272
+ const [pends, setPends] = useState(0);
271
273
  const [answers, setAnswers] = useState([]);
272
274
  const [wasOpen, setWasOpen] = useState(open);
273
275
  if (open !== wasOpen) {
@@ -325,6 +327,15 @@ function useOverlayMark(open) {
325
327
  setHolds((n) => n - 1);
326
328
  };
327
329
  },
330
+ pend: () => {
331
+ setPends((n) => n + 1);
332
+ let released = false;
333
+ return () => {
334
+ if (released) return;
335
+ released = true;
336
+ setPends((n) => n - 1);
337
+ };
338
+ },
328
339
  open
329
340
  }), [open]);
330
341
  useEffect(() => {
@@ -345,7 +356,7 @@ function useOverlayMark(open) {
345
356
  setAnswers([]);
346
357
  setChanged([...forms.current.values()].some((f) => f.stamp > 0));
347
358
  }, [answers]);
348
- return { marked: changed || holds > 0, mark };
359
+ return { marked: changed || holds > 0, pending: pends > 0, mark };
349
360
  }
350
361
  var OverlayCloseCtx = createContext(null);
351
362
  function useDirtyGuard(dirty, onClose, onDiscard) {
@@ -439,6 +450,7 @@ function useScrollbarInset() {
439
450
  }
440
451
  var insetLessScrollbar = (gutter) => `max(0px, calc(${gutter} - var(--gs-scrollbar, 0px)))`;
441
452
  var DrawerFooterCtx = createContext(null);
453
+ var DrawerScopeCtx = createContext(null);
442
454
  var slideClasses = {
443
455
  right: {
444
456
  panel: "top-0 right-0 h-full",
@@ -466,8 +478,8 @@ function Drawer(props) {
466
478
  const shellWidth = useContext(DrawerWidthCtx) ?? void 0;
467
479
  const isPhone = useBreakpoint("sm");
468
480
  const mobileMode = mobile ?? (position === "left" && props.modal !== false ? "panel" : "sheet");
469
- const { marked, mark } = useOverlayMark(open);
470
- const guard = useDirtyGuard(dirty ?? marked, onClose, onDiscard);
481
+ const { marked, pending, mark } = useOverlayMark(open);
482
+ const guard = useDirtyGuard((dirty ?? marked) || pending, onClose, onDiscard);
471
483
  const confirm = /* @__PURE__ */ jsx(DiscardConfirm, { open: guard.confirming, onKeep: guard.keep, onDiscard: guard.discard });
472
484
  const [actionsMap, setActionsMap] = useState(/* @__PURE__ */ new Map());
473
485
  const registerActions = useCallback((formId, acts) => {
@@ -503,6 +515,9 @@ function DrawerPanel({ form, open, onClose, position = "right", width = "400px",
503
515
  const { ref: titleOverflowRef, isTruncated: titleTruncated } = useTextOverflow({ lines: 1 });
504
516
  const isMobile = useBreakpoint("sm");
505
517
  const panelRef = useRef(null);
518
+ const wrapperRef = useRef(null);
519
+ const scope = useContext(DrawerScopeCtx);
520
+ const scoped = !!scope && blocking && !sheet;
506
521
  const [mounted, setMounted] = useState(open);
507
522
  const [hidden, setHidden] = useState(!open);
508
523
  const [snapIdx, setSnapIdx] = useState(0);
@@ -538,7 +553,13 @@ function DrawerPanel({ form, open, onClose, position = "right", width = "400px",
538
553
  return () => unlockBodyScroll();
539
554
  }, [open, blocking, container]);
540
555
  useReturnFocus(open && !nonModal, panelRef);
541
- useFocusTrap(panelRef, open && blocking && (sheet || !topOffset), isTopLayer);
556
+ useFocusTrap(panelRef, open && blocking && (sheet || !topOffset || scoped), isTopLayer, scoped ? scope : null);
557
+ useEffect(() => {
558
+ const keep = scope?.current;
559
+ const own = wrapperRef.current;
560
+ if (!open || !mounted || !scoped || !keep || !own) return;
561
+ return inertOutside([keep, own], container instanceof Element ? container : document.body);
562
+ }, [open, mounted, scoped, scope, container]);
542
563
  useEffect(() => {
543
564
  if (!open || !mounted || nonModal) return;
544
565
  const raf = requestAnimationFrame(() => focusInitial(panelRef.current));
@@ -573,7 +594,13 @@ function DrawerPanel({ form, open, onClose, position = "right", width = "400px",
573
594
  const panel = panelRef.current;
574
595
  if (panel && !panel.contains(document.activeElement)) focusInitial(panel);
575
596
  }, [open, mounted, blocking]);
576
- const bodyRef = useScrollbarInset();
597
+ const bodyInset = useScrollbarInset();
598
+ const [bodyEl, setBodyEl] = useState(null);
599
+ const bodyRef = useCallback((el) => {
600
+ bodyInset(el);
601
+ setBodyEl(el);
602
+ }, [bodyInset]);
603
+ useKeyboardScroll(bodyEl, typeof title === "string" ? title : "Content", open);
577
604
  useCloseSettle(open, panelRef, () => {
578
605
  if (keepMounted) setHidden(true);
579
606
  else setMounted(false);
@@ -627,6 +654,7 @@ function DrawerPanel({ form, open, onClose, position = "right", width = "400px",
627
654
  /* @__PURE__ */ jsxs(
628
655
  "div",
629
656
  {
657
+ ref: wrapperRef,
630
658
  hidden: keepMounted && hidden ? true : void 0,
631
659
  className: cn(
632
660
  `${positionClass} transition-opacity duration-[var(--ds-transition-speed)]`,
@@ -657,7 +685,7 @@ function DrawerPanel({ form, open, onClose, position = "right", width = "400px",
657
685
  "data-gs": sheet ? "sheet" : "drawer",
658
686
  "data-ds-sheet": sheet ? "" : void 0,
659
687
  ...{ [OVERLAY_ROOT_ATTR]: "" },
660
- "aria-modal": blocking ? "true" : void 0,
688
+ "aria-modal": blocking && !scoped ? "true" : void 0,
661
689
  "aria-labelledby": title ? titleId : labelledBy,
662
690
  style: sheet ? {
663
691
  containerType: "inline-size",
@@ -731,7 +759,7 @@ function DrawerPanel({ form, open, onClose, position = "right", width = "400px",
731
759
  },
732
760
  children: [
733
761
  !sheet && titleTruncated ? /* @__PURE__ */ jsx(AutoTooltip, { content: title, children: /* @__PURE__ */ jsx("h2", { ref: titleOverflowRef, id: titleId, className: heading, children: title }) }) : /* @__PURE__ */ jsx("h2", { ref: titleOverflowRef, id: titleId, className: heading, children: title }),
734
- /* @__PURE__ */ jsx(
762
+ /* @__PURE__ */ jsx(AutoTooltip, { content: "Close", children: /* @__PURE__ */ jsx(
735
763
  "button",
736
764
  {
737
765
  type: "button",
@@ -741,7 +769,7 @@ function DrawerPanel({ form, open, onClose, position = "right", width = "400px",
741
769
  "aria-label": "Close",
742
770
  children: /* @__PURE__ */ jsx(Icon, { name: "close", size: 18 })
743
771
  }
744
- )
772
+ ) })
745
773
  ]
746
774
  }
747
775
  ),
@@ -749,7 +777,7 @@ function DrawerPanel({ form, open, onClose, position = "right", width = "400px",
749
777
  "div",
750
778
  {
751
779
  ref: bodyRef,
752
- className: "flex-1 overflow-y-auto",
780
+ className: cn("flex-1 overflow-y-auto", FOCUS_INSET),
753
781
  style: flush ? void 0 : { padding: `var(--ds-space-5) ${insetLessScrollbar(INSET)} var(--ds-space-5) ${INSET}` },
754
782
  children: /* @__PURE__ */ jsx(SurfaceBoundary, { children })
755
783
  }
@@ -882,6 +910,15 @@ var AppShell = forwardRef(function AppShell2({
882
910
  const isHome = currentPath != null && currentPath === homePath;
883
911
  const hasFooter = footer != null && scrollable;
884
912
  const mainRef = useRef(null);
913
+ const [mainEl, setMainEl] = useState(null);
914
+ const setMain = useCallback((el) => {
915
+ mainRef.current = el;
916
+ setMainEl(el);
917
+ }, []);
918
+ useKeyboardScroll(mainEl, "Main content");
919
+ const navbarRef = useRef(null);
920
+ const navbarSlot = navbar != null && navbar !== false ? /* @__PURE__ */ jsx("div", { ref: navbarRef, "data-ds-navbar-slot": "", className: "contents", children: navbar }) : navbar;
921
+ const menuNameId = useId();
885
922
  useEffect(() => {
886
923
  const main = mainRef.current;
887
924
  if (!hasFooter || !shellEl || !main || typeof ResizeObserver === "undefined") {
@@ -925,18 +962,18 @@ var AppShell = forwardRef(function AppShell2({
925
962
  className
926
963
  ), children: [
927
964
  skipLink && /* @__PURE__ */ jsx(SkipLink, { href: `#${mainId}` }),
928
- layout === "sidebar-header" && navbar,
929
- layout === "multi-column" && navbar,
965
+ layout === "sidebar-header" && navbarSlot,
966
+ layout === "multi-column" && navbarSlot,
930
967
  /* @__PURE__ */ jsxs("div", { className: "flex flex-1 min-h-0", children: [
931
968
  hasSidebar && !isMobile && /* @__PURE__ */ jsx("div", { className: "shrink-0 h-full", children: sidebar }),
932
969
  aside && asideSide === "left" && aside,
933
970
  /* @__PURE__ */ jsxs("div", { className: "flex-1 flex flex-col min-w-0 min-h-0", children: [
934
- layout === "sidebar" && navbar,
935
- layout === "stacked" && navbar,
971
+ layout === "sidebar" && navbarSlot,
972
+ layout === "stacked" && navbarSlot,
936
973
  /* @__PURE__ */ jsx(
937
974
  "main",
938
975
  {
939
- ref: mainRef,
976
+ ref: setMain,
940
977
  id: mainId,
941
978
  "data-shell-main": "",
942
979
  tabIndex: -1,
@@ -946,6 +983,14 @@ var AppShell = forwardRef(function AppShell2({
946
983
  // <main> to it. Placed against the shell instead, it stayed where the unscrolled page had put it, out of
947
984
  // <main>'s reach, and focus scrolled the shell's outer box to show it
948
985
  "relative flex-1 min-h-0 focus:outline-none",
986
+ // the skip link's target draws no ring (GOV.UK's); a Tab stop while it scrolls with nothing in it to Tab
987
+ // to, it draws the inset ring (Sprint 25.29 item 10)
988
+ FOCUS_INSET_WHILE_STOP,
989
+ // the outline's reach at the foot as scroll padding, which a control Tab reaches across the bottom edge
990
+ // stops short of (Sprint 25.29 item 19; a pinned PageHeader claims the top inline). The page's last control
991
+ // has its room from the page's own foot (PageContainer's bottom padding): padding here would sit under a
992
+ // view that fills the page, past the gutter its sides keep (Sprint 25.16 A42)
993
+ "scroll-pb-[4px]",
949
994
  scrollable && "overflow-y-auto",
950
995
  layout === "multi-column" && "flex"
951
996
  ),
@@ -959,7 +1004,10 @@ var AppShell = forwardRef(function AppShell2({
959
1004
  ] }),
960
1005
  aside && asideSide === "right" && aside
961
1006
  ] }),
962
- showMobileDrawer && isMobile && /* @__PURE__ */ jsx(
1007
+ showMobileDrawer && isMobile && // Under the navbar, the menu is modal over the page with the navbar in its scope: the rest inert, Tab cycling the
1008
+ // two, Escape closing it (the Authoring Practices; Sprint 25.29 item 9). The stacked shell, with no offset, traps
1009
+ // in the menu alone.
1010
+ /* @__PURE__ */ jsx(DrawerScopeCtx, { value: layout !== "stacked" && navbar != null ? navbarRef : null, children: /* @__PURE__ */ jsxs(
963
1011
  Drawer,
964
1012
  {
965
1013
  open: sidebarOpen,
@@ -970,9 +1018,13 @@ var AppShell = forwardRef(function AppShell2({
970
1018
  flush: mobileMenuFlush,
971
1019
  lightBackdrop: mobileMenuLightBackdrop,
972
1020
  topOffset: layout !== "stacked" && navbar != null ? "var(--ds-navbar-height)" : void 0,
973
- children: mobileMenu
1021
+ labelledBy: menuNameId,
1022
+ children: [
1023
+ /* @__PURE__ */ jsx("span", { id: menuNameId, hidden: true, children: "Menu" }),
1024
+ mobileMenu
1025
+ ]
974
1026
  }
975
- ),
1027
+ ) }),
976
1028
  isSmallMobile && hasMobileNav && /* @__PURE__ */ jsx("div", { className: "sticky bottom-0 z-[var(--ds-z-sticky)]", children: mobileNav }),
977
1029
  !isSmallMobile && launcher
978
1030
  ] })
@@ -1306,5 +1358,5 @@ function useElementWidth(ref) {
1306
1358
  }
1307
1359
 
1308
1360
  export { AppShell, Breadcrumbs, DiscardConfirm, Drawer, DrawerFooterCtx, DrawerPanel, LAUNCHER_INSET_PRIORITY, NAVBAR_INSET_PRIORITY, OVERLAY_ROOT_ATTR, OverlayCloseCtx, OverlayMarkCtx, OverlayMarkScope, PANEL_INSET_PRIORITY, REACT_VERSION_PROBLEM, ResizeEdge, SkipLink, besideRoom, crumbGoes, defaultMaxWidth, insetLessScrollbar, pxOf, useAppShell, useBelow, useCloseSettle, useCompact, useCornerInset, useCrumbFollow, useDirtyGuard, useElementWidth, useOverlayMark, useRememberedWidth, useScrollbarInset, useUnsavedChanges };
1309
- //# sourceMappingURL=chunk-UNS4TGGK.js.map
1310
- //# sourceMappingURL=chunk-UNS4TGGK.js.map
1361
+ //# sourceMappingURL=chunk-KMKBOTFR.js.map
1362
+ //# sourceMappingURL=chunk-KMKBOTFR.js.map