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 +1 @@
1
- {"version":3,"sources":["../../../showcase/src/components/CodeBlock.tsx","../../../showcase/src/components/Link.tsx","../../../showcase/src/components/Divider.tsx"],"names":["Link","jsxs","jsx"],"mappings":"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","file":"chunk-KTPGMJUK.js","sourcesContent":["import { useState, useCallback } from \"react\";\nimport { cn, FOCUS_RING } from \"../lib/utils\";\nimport { Icon } from \"../lib/icons\";\nimport { Badge } from \"./Badge\";\n\ninterface CodeBlockProps {\n code: string;\n language?: string;\n showLineNumbers?: boolean;\n /** Wrap long lines instead of scrolling sideways. Default: on for a single-line snippet (a tracking tag, a command), off for multi-line code. */\n wrap?: boolean;\n className?: string;\n}\n\nexport function CodeBlock({\n code,\n language,\n showLineNumbers = false,\n wrap,\n className,\n}: CodeBlockProps) {\n const [copied, setCopied] = useState(false);\n\n const handleCopy = useCallback(async () => {\n try {\n await navigator.clipboard.writeText(code);\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n } catch {\n /* clipboard not available */\n }\n }, [code]);\n\n const lines = code.split(\"\\n\");\n const wraps = wrap ?? lines.length === 1;\n const gutterWidth = showLineNumbers ? `${String(lines.length).length + 1}ch` : undefined;\n\n return (\n <div\n className={cn(\n \"relative group\",\n \"bg-[var(--ds-bg-surface)] text-[var(--ds-text-primary)]\",\n \"border-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]\",\n \"rounded-[var(--ds-radius-md)]\",\n \"shadow-[var(--ds-shadow-sm)]\",\n \"overflow-hidden\",\n className,\n )}\n >\n <div className=\"flex items-center justify-between px-ds-4 py-ds-2 border-b-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)] bg-[var(--ds-bg-muted)]\">\n <div className=\"flex items-center gap-ds-2\">\n {language && <Badge variant=\"outline\" size=\"sm\">{language}</Badge>}\n </div>\n <button\n type=\"button\"\n onClick={handleCopy}\n className={cn(\n \"inline-flex items-center gap-ds-1.5 px-ds-2 py-ds-1 text-xs font-medium cursor-pointer\",\n \"text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)]\",\n \"rounded-[var(--ds-radius-sm)]\",\n \"hover:bg-[var(--ds-bg-surface)]\",\n \"transition-colors\",\n FOCUS_RING,\n )}\n aria-label={copied ? \"Copied\" : \"Copy code\"}\n >\n {/* Sprint 25.8.7 item 12: the copy icon, where a folder stood */}\n <Icon name={copied ? \"check\" : \"copy\"} size={14} />\n {copied ? \"Copied\" : \"Copy\"}\n </button>\n </div>\n\n <div className={wraps ? undefined : \"overflow-x-auto\"} data-wrap={wraps ? \"true\" : undefined}>\n <pre className={cn(\"p-ds-4 text-sm leading-relaxed font-[family-name:var(--ds-font-mono)]\", wraps && \"whitespace-pre-wrap break-words\")}>\n <code>\n {lines.map((line, i) => (\n // with line numbers each line is a two-column row, so a wrapped line continues under its text, not under the gutter\n <span key={i} className={showLineNumbers ? \"grid grid-cols-[max-content_1fr]\" : \"block\"}>\n {showLineNumbers && (\n <span\n className=\"text-right text-[var(--ds-text-muted)] select-none mr-ds-4 opacity-50\"\n style={{ width: gutterWidth }}\n >\n {i + 1}\n </span>\n )}\n <span className=\"min-w-0\">{line || \" \"}</span>\n </span>\n ))}\n </code>\n </pre>\n </div>\n </div>\n );\n}\n","import { forwardRef, type AnchorHTMLAttributes, type ElementType, type ReactNode } from \"react\";\nimport { cn, FOCUS_RING } from \"../lib/utils\";\nimport { slotIcon, type IconSlot } from \"../lib/icons\";\n\ntype LinkUnderline = \"hover\" | \"always\" | \"none\";\ntype LinkTone = \"accent\" | \"muted\" | \"inherit\";\n\nexport interface LinkProps extends AnchorHTMLAttributes<HTMLAnchorElement> {\n href: string;\n children: ReactNode;\n /** When to show the underline. Default \"hover\". */\n underline?: LinkUnderline;\n /** Colour: accent (default), muted for secondary links, inherit to match surrounding text. */\n tone?: LinkTone;\n /** Opens in a new tab with rel=\"noopener noreferrer\". Default false. */\n external?: boolean;\n /**\n * Render through a router link component instead of a plain anchor\n * (e.g. `component={RouterLink}` from react-router or next/link). The\n * component receives the same props; `href` is also passed as `to` for\n * react-router compatibility. Any element type: a router's Link requires\n * its own props (react-router's `to`), which a narrower type refused under\n * strict TypeScript (Sprint 25.16 A19).\n */\n component?: ElementType;\n /** An icon name (\"info\"), drawn as the theme's icon at 14 px, or an element. Not text: use children. */\n iconLeft?: IconSlot;\n /** As iconLeft, after the label. */\n iconRight?: IconSlot;\n}\n\nconst toneStyles: Record<LinkTone, string> = {\n accent: \"text-[var(--ds-accent-ink)] hover:text-[var(--ds-accent-primary-hover)] active:text-[var(--ds-accent-primary-active)]\",\n muted: \"text-[var(--ds-text-secondary)] hover:text-[var(--ds-text-primary)]\",\n inherit: \"text-inherit hover:text-[var(--ds-accent-ink)]\",\n};\n\nconst underlineStyles: Record<LinkUnderline, string> = {\n hover: \"no-underline hover:underline\",\n always: \"underline underline-offset-2\",\n none: \"no-underline\",\n};\n\n/**\n * Navigation link. Renders a real <a> (or a router link via `component`) so\n * middle-click, open-in-new-tab, right-click \"copy link\" and screen readers\n * all behave correctly. Visually identical to Button variant=\"link\".\n *\n * Use Link for NAVIGATION (to a page or URL). Use Button variant=\"link\" for an\n * ACTION that should look like a link (show more, resend code). Never use a\n * ghost Button for inline text — its padding breaks the line.\n */\nexport const Link = forwardRef<HTMLAnchorElement, LinkProps>(function Link(\n { href, children, underline = \"hover\", tone = \"accent\", external = false, component: Component, iconLeft, iconRight, className, target, rel, ...props },\n ref,\n) {\n const classes = cn(\n \"inline-flex items-center gap-ds-1 font-medium cursor-pointer\",\n \"transition-colors duration-[var(--ds-transition-speed)]\",\n FOCUS_RING,\n \"rounded-[var(--ds-radius-sm)]\",\n toneStyles[tone],\n underlineStyles[underline],\n className,\n );\n const resolvedTarget = external ? \"_blank\" : target;\n const resolvedRel = external ? cn(\"noopener noreferrer\", rel) : rel;\n const content = (\n <>\n {slotIcon(iconLeft, 14, \"Link's iconLeft\")}\n {children}\n {slotIcon(iconRight, 14, \"Link's iconRight\")}\n </>\n );\n\n if (Component) {\n return (\n <Component ref={ref} href={href} to={href} className={classes} target={resolvedTarget} rel={resolvedRel} {...props}>\n {content}\n </Component>\n );\n }\n\n return (\n <a ref={ref} href={href} className={classes} target={resolvedTarget} rel={resolvedRel} {...props}>\n {content}\n </a>\n );\n});\n","import { cn } from \"../lib/utils\";\nimport type { ReactNode } from \"react\";\n\ntype Orientation = \"horizontal\" | \"vertical\";\n\ninterface DividerProps {\n orientation?: Orientation;\n label?: ReactNode;\n className?: string;\n}\n\nexport function Divider({\n orientation = \"horizontal\",\n label,\n className,\n}: DividerProps) {\n if (orientation === \"vertical\") {\n return (\n <div\n role=\"separator\"\n aria-orientation=\"vertical\"\n className={cn(\n \"inline-block self-stretch min-h-[1em]\",\n \"w-[var(--ds-divider-width)]\",\n \"bg-[var(--ds-border-default)]\",\n className,\n )}\n />\n );\n }\n\n if (label) {\n return (\n <div\n role=\"separator\"\n className={cn(\"flex items-center gap-ds-3\", className)}\n >\n <span className=\"flex-1 h-[var(--ds-divider-width)] bg-[var(--ds-border-default)]\" />\n <span className=\"text-xs font-medium text-[var(--ds-text-muted)] shrink-0\">\n {label}\n </span>\n <span className=\"flex-1 h-[var(--ds-divider-width)] bg-[var(--ds-border-default)]\" />\n </div>\n );\n }\n\n return (\n <hr\n role=\"separator\"\n className={cn(\n \"border-none w-full\",\n \"h-[var(--ds-divider-width)]\",\n \"bg-[var(--ds-border-default)]\",\n className,\n )}\n />\n );\n}\n"]}
1
+ {"version":3,"sources":["../../../showcase/src/components/CodeBlock.tsx","../../../showcase/src/components/Link.tsx","../../../showcase/src/components/Divider.tsx"],"names":["Link","jsxs","jsx"],"mappings":"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","file":"chunk-OX3NNMWG.js","sourcesContent":["import { useState, useCallback } from \"react\";\nimport { cn, FOCUS_RING } from \"../lib/utils\";\nimport { Icon } from \"../lib/icons\";\nimport { Badge } from \"./Badge\";\n\ninterface CodeBlockProps {\n code: string;\n language?: string;\n showLineNumbers?: boolean;\n /** Wrap long lines instead of scrolling sideways. Default: on for a single-line snippet (a tracking tag, a command), off for multi-line code. */\n wrap?: boolean;\n className?: string;\n}\n\nexport function CodeBlock({\n code,\n language,\n showLineNumbers = false,\n wrap,\n className,\n}: CodeBlockProps) {\n const [copied, setCopied] = useState(false);\n\n const handleCopy = useCallback(async () => {\n try {\n await navigator.clipboard.writeText(code);\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n } catch {\n /* clipboard not available */\n }\n }, [code]);\n\n const lines = code.split(\"\\n\");\n const wraps = wrap ?? lines.length === 1;\n const gutterWidth = showLineNumbers ? `${String(lines.length).length + 1}ch` : undefined;\n\n return (\n <div\n className={cn(\n \"relative group\",\n \"bg-[var(--ds-bg-surface)] text-[var(--ds-text-primary)]\",\n \"border-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]\",\n \"rounded-[var(--ds-radius-md)]\",\n \"shadow-[var(--ds-shadow-sm)]\",\n \"overflow-hidden\",\n className,\n )}\n >\n <div className=\"flex items-center justify-between px-ds-4 py-ds-2 border-b-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)] bg-[var(--ds-bg-muted)]\">\n <div className=\"flex items-center gap-ds-2\">\n {language && <Badge variant=\"outline\" size=\"sm\">{language}</Badge>}\n </div>\n <button\n type=\"button\"\n onClick={handleCopy}\n className={cn(\n \"inline-flex items-center gap-ds-1.5 px-ds-2 py-ds-1 text-xs font-medium cursor-pointer\",\n \"text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)]\",\n \"rounded-[var(--ds-radius-sm)]\",\n \"hover:bg-[var(--ds-bg-surface)]\",\n \"transition-colors\",\n FOCUS_RING,\n )}\n aria-label={copied ? \"Copied\" : \"Copy code\"}\n >\n {/* Sprint 25.8.7 item 12: the copy icon, where a folder stood */}\n <Icon name={copied ? \"check\" : \"copy\"} size={14} />\n {copied ? \"Copied\" : \"Copy\"}\n </button>\n </div>\n\n <div className={wraps ? undefined : \"overflow-x-auto\"} data-wrap={wraps ? \"true\" : undefined}>\n <pre className={cn(\"p-ds-4 text-sm leading-relaxed font-[family-name:var(--ds-font-mono)]\", wraps && \"whitespace-pre-wrap break-words\")}>\n <code>\n {lines.map((line, i) => (\n // with line numbers each line is a two-column row, so a wrapped line continues under its text, not under the gutter\n <span key={i} className={showLineNumbers ? \"grid grid-cols-[max-content_1fr]\" : \"block\"}>\n {showLineNumbers && (\n <span\n className=\"text-right text-[var(--ds-text-muted)] select-none mr-ds-4 opacity-50\"\n style={{ width: gutterWidth }}\n >\n {i + 1}\n </span>\n )}\n <span className=\"min-w-0\">{line || \" \"}</span>\n </span>\n ))}\n </code>\n </pre>\n </div>\n </div>\n );\n}\n","import { forwardRef, type AnchorHTMLAttributes, type ElementType, type ReactNode } from \"react\";\nimport { cn, FOCUS_RING } from \"../lib/utils\";\nimport { slotIcon, type IconSlot } from \"../lib/icons\";\n\ntype LinkUnderline = \"hover\" | \"always\" | \"none\";\ntype LinkTone = \"accent\" | \"muted\" | \"inherit\";\n\nexport interface LinkProps extends AnchorHTMLAttributes<HTMLAnchorElement> {\n href: string;\n children: ReactNode;\n /** When to show the underline. Default \"hover\". */\n underline?: LinkUnderline;\n /** Colour: accent (default), muted for secondary links, inherit to match surrounding text. */\n tone?: LinkTone;\n /** Opens in a new tab with rel=\"noopener noreferrer\". Default false. */\n external?: boolean;\n /**\n * Render through a router link component instead of a plain anchor\n * (e.g. `component={RouterLink}` from react-router or next/link). The\n * component receives the same props; `href` is also passed as `to` for\n * react-router compatibility. Any element type: a router's Link requires\n * its own props (react-router's `to`), which a narrower type refused under\n * strict TypeScript (Sprint 25.16 A19).\n */\n component?: ElementType;\n /** An icon name (\"info\"), drawn as the theme's icon at 14 px, or an element. Not text: use children. */\n iconLeft?: IconSlot;\n /** As iconLeft, after the label. */\n iconRight?: IconSlot;\n}\n\nconst toneStyles: Record<LinkTone, string> = {\n accent: \"text-[var(--ds-accent-ink)] hover:text-[var(--ds-accent-primary-hover)] active:text-[var(--ds-accent-primary-active)]\",\n muted: \"text-[var(--ds-text-secondary)] hover:text-[var(--ds-text-primary)]\",\n inherit: \"text-inherit hover:text-[var(--ds-accent-ink)]\",\n};\n\nconst underlineStyles: Record<LinkUnderline, string> = {\n hover: \"no-underline hover:underline\",\n always: \"underline underline-offset-2\",\n none: \"no-underline\",\n};\n\n/**\n * Navigation link. Renders a real <a> (or a router link via `component`) so\n * middle-click, open-in-new-tab, right-click \"copy link\" and screen readers\n * all behave correctly. Visually identical to Button variant=\"link\".\n *\n * Use Link for NAVIGATION (to a page or URL). Use Button variant=\"link\" for an\n * ACTION that should look like a link (show more, resend code). Never use a\n * ghost Button for inline text — its padding breaks the line.\n */\nexport const Link = forwardRef<HTMLAnchorElement, LinkProps>(function Link(\n { href, children, underline = \"hover\", tone = \"accent\", external = false, component: Component, iconLeft, iconRight, className, target, rel, ...props },\n ref,\n) {\n const classes = cn(\n \"inline-flex items-center gap-ds-1 font-medium cursor-pointer\",\n \"transition-colors duration-[var(--ds-transition-speed)]\",\n FOCUS_RING,\n \"rounded-[var(--ds-radius-sm)]\",\n toneStyles[tone],\n underlineStyles[underline],\n className,\n );\n const resolvedTarget = external ? \"_blank\" : target;\n const resolvedRel = external ? cn(\"noopener noreferrer\", rel) : rel;\n const content = (\n <>\n {slotIcon(iconLeft, 14, \"Link's iconLeft\")}\n {children}\n {slotIcon(iconRight, 14, \"Link's iconRight\")}\n </>\n );\n\n if (Component) {\n return (\n <Component ref={ref} href={href} to={href} className={classes} target={resolvedTarget} rel={resolvedRel} {...props}>\n {content}\n </Component>\n );\n }\n\n return (\n <a ref={ref} href={href} className={classes} target={resolvedTarget} rel={resolvedRel} {...props}>\n {content}\n </a>\n );\n});\n","import { cn } from \"../lib/utils\";\nimport type { ReactNode } from \"react\";\n\ntype Orientation = \"horizontal\" | \"vertical\";\n\ninterface DividerProps {\n orientation?: Orientation;\n label?: ReactNode;\n className?: string;\n}\n\nexport function Divider({\n orientation = \"horizontal\",\n label,\n className,\n}: DividerProps) {\n if (orientation === \"vertical\") {\n return (\n <div\n role=\"separator\"\n aria-orientation=\"vertical\"\n className={cn(\n \"inline-block self-stretch min-h-[1em]\",\n \"w-[var(--ds-divider-width)]\",\n \"bg-[var(--ds-border-default)]\",\n className,\n )}\n />\n );\n }\n\n if (label) {\n return (\n <div\n role=\"separator\"\n className={cn(\"flex items-center gap-ds-3\", className)}\n >\n <span className=\"flex-1 h-[var(--ds-divider-width)] bg-[var(--ds-border-default)]\" />\n <span className=\"text-xs font-medium text-[var(--ds-text-muted)] shrink-0\">\n {label}\n </span>\n <span className=\"flex-1 h-[var(--ds-divider-width)] bg-[var(--ds-border-default)]\" />\n </div>\n );\n }\n\n return (\n <hr\n role=\"separator\"\n className={cn(\n \"border-none w-full\",\n \"h-[var(--ds-divider-width)]\",\n \"bg-[var(--ds-border-default)]\",\n className,\n )}\n />\n );\n}\n"]}
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { useLatest } from './chunk-WH2FUFAC.js';
2
+ import { useLatest } from './chunk-WIUGPZOH.js';
3
3
  import { useRef, useInsertionEffect, useEffect, useCallback, useState, useMemo, useLayoutEffect } from 'react';
4
4
  import { flushSync } from 'react-dom';
5
5
 
@@ -55,10 +55,34 @@ function focusInitial(root, opts = {}) {
55
55
  function useFocusBeforeOpen(open) {
56
56
  const before = useRef(null);
57
57
  useInsertionEffect(() => {
58
- if (open) before.current = document.activeElement;
58
+ trackFocus();
59
+ if (!open) return;
60
+ const active = document.activeElement;
61
+ before.current = !active || active === document.body ? justLost() ?? active : active;
59
62
  }, [open]);
60
63
  return before;
61
64
  }
65
+ var lastFocused = null;
66
+ var lastFocusedAt = 0;
67
+ var lastActedAt = 0;
68
+ var tracking = false;
69
+ function trackFocus() {
70
+ if (tracking || typeof document === "undefined") return;
71
+ tracking = true;
72
+ document.addEventListener("focusin", (e) => {
73
+ lastFocused = e.target instanceof Element ? e.target : null;
74
+ lastFocusedAt = performance.now();
75
+ }, true);
76
+ const acted = () => {
77
+ lastActedAt = performance.now();
78
+ };
79
+ for (const type of ["keydown", "pointerdown", "click"]) document.addEventListener(type, acted, true);
80
+ }
81
+ function justLost() {
82
+ const recent = lastActedAt >= lastFocusedAt && performance.now() - lastActedAt < 1e3;
83
+ return lastFocused && !lastFocused.isConnected && recent ? lastFocused : null;
84
+ }
85
+ trackFocus();
62
86
  function pathAbove(to, from) {
63
87
  const up = to.replace(/\/+$/, "");
64
88
  return from.startsWith(`${up}/`) && from.replace(/\/+$/, "") !== up;
@@ -74,6 +98,59 @@ function deletedRow(before, now) {
74
98
  for (let j = k; j < (refilled ? last : now.length); j++) if (now[j] !== before[j + 1]) return -1;
75
99
  return k;
76
100
  }
101
+ function focusForTheMoment(el) {
102
+ const own = el.getAttribute("tabindex");
103
+ if (own === null) el.setAttribute("tabindex", "-1");
104
+ el.focus();
105
+ if (document.activeElement !== el) {
106
+ if (own === null) el.removeAttribute("tabindex");
107
+ return false;
108
+ }
109
+ let ring = false;
110
+ try {
111
+ ring = el.matches(":focus-visible");
112
+ } catch {
113
+ }
114
+ const { outline, outlineOffset } = el.style;
115
+ if (ring) {
116
+ el.style.outline = "2px solid var(--ds-focus)";
117
+ el.style.outlineOffset = "2px";
118
+ }
119
+ el.addEventListener("blur", () => {
120
+ if (own === null) el.removeAttribute("tabindex");
121
+ if (ring) Object.assign(el.style, { outline, outlineOffset });
122
+ }, { once: true });
123
+ return true;
124
+ }
125
+ var HEADING = 'h1, h2, h3, h4, h5, h6, [role="heading"]';
126
+ var LAST_RESORT_MS = 200;
127
+ function placesOf(el) {
128
+ const places = [];
129
+ for (let c = el, box = el.parentElement; box && box !== document.body && box.parentElement && box.parentElement !== document.body; c = box, box = box.parentElement) {
130
+ places.push({ box, prev: c.previousElementSibling, next: c.nextElementSibling });
131
+ }
132
+ return places;
133
+ }
134
+ function landLastResort(places, closing) {
135
+ const at = places.findIndex((p) => p.box.isConnected);
136
+ if (at < 0) return false;
137
+ const { box, prev, next } = places[at];
138
+ const kids = Array.from(box.children);
139
+ const from = prev?.parentElement === box ? kids.indexOf(prev) + 1 : 0;
140
+ const to = next?.parentElement === box ? kids.indexOf(next) : kids.length;
141
+ const areas = [kids.slice(from, Math.max(from, to)), ...places.slice(at).map((p) => [p.box])];
142
+ const counts = (el) => !closing?.contains(el);
143
+ for (const area of areas) {
144
+ const stop = area.flatMap((a) => [...isTabStop(a) ? [a] : [], ...tabStops(a)]).find(counts);
145
+ if (stop) {
146
+ stop.focus();
147
+ if (document.activeElement === stop) return true;
148
+ }
149
+ const heading = area.flatMap((a) => [...a.matches(HEADING) ? [a] : [], ...a.querySelectorAll(HEADING)]).find((h) => h instanceof HTMLElement && isRendered(h) && counts(h));
150
+ if (heading && focusForTheMoment(heading)) return true;
151
+ }
152
+ return false;
153
+ }
77
154
  function rememberFocus(el, { ignoreRoute = false } = {}) {
78
155
  const { href, pathname } = location;
79
156
  const row = el.closest(ROW);
@@ -86,6 +163,7 @@ function rememberFocus(el, { ignoreRoute = false } = {}) {
86
163
  const texts = rows.map((r) => r.textContent ?? "");
87
164
  const keyOf = (r) => r?.getAttribute("data-row-key") ?? null;
88
165
  const key = keyOf(row);
166
+ const places = placesOf(el);
89
167
  const pageChanged = () => {
90
168
  if (ignoreRoute) return false;
91
169
  if (location.pathname !== pathname) return !pathAbove(location.pathname, pathname);
@@ -118,16 +196,26 @@ function rememberFocus(el, { ignoreRoute = false } = {}) {
118
196
  return k >= 0 && k <= at ? list.children[Math.max(0, at - 1)] ?? void 0 : void 0;
119
197
  };
120
198
  const neighbour = () => inRow(byKey(keyOf(before)) ?? before) || inRow(byKey(keyOf(after)) ?? after) || !!list?.isConnected && land(tabStops(list)[0]);
199
+ const lastResort = () => {
200
+ setTimeout(() => {
201
+ const active = document.activeElement;
202
+ if (active && active !== document.body && active.isConnected || pageChanged()) return;
203
+ landLastResort(places);
204
+ }, LAST_RESORT_MS);
205
+ return false;
206
+ };
121
207
  let unwatch = null;
122
208
  const watch = () => {
123
209
  unwatch?.();
124
210
  if (!list || typeof MutationObserver === "undefined") return;
125
- const observer = new MutationObserver(() => {
211
+ const observer = new MutationObserver((changes) => {
126
212
  if (el.isConnected) return;
127
213
  const active = document.activeElement;
128
214
  const dropped = !active || active === document.body || !active.isConnected;
129
215
  stop();
130
- if (dropped && !pageChanged()) neighbour();
216
+ if (!dropped || pageChanged()) return;
217
+ const fromList = changes.some((c) => c.target === list || c.target === list.parentNode);
218
+ if (!(fromList && neighbour())) lastResort();
131
219
  });
132
220
  const onFocusIn = (e) => {
133
221
  if (e.target !== el) stop();
@@ -141,6 +229,7 @@ function rememberFocus(el, { ignoreRoute = false } = {}) {
141
229
  }
142
230
  observer.observe(list, { childList: true });
143
231
  if (list.parentNode) observer.observe(list.parentNode, { childList: true });
232
+ for (const { box } of places) observer.observe(box, { childList: true });
144
233
  document.addEventListener("focusin", onFocusIn, true);
145
234
  unwatch = stop;
146
235
  };
@@ -154,7 +243,89 @@ function rememberFocus(el, { ignoreRoute = false } = {}) {
154
243
  return true;
155
244
  }
156
245
  if (row && !row.isConnected && neighbour()) return true;
157
- return land(fallback);
246
+ return land(fallback) || lastResort();
247
+ }
248
+ };
249
+ }
250
+ function useFocusKeptInList(listRef) {
251
+ useEffect(() => {
252
+ if (typeof MutationObserver === "undefined") return;
253
+ let held = null;
254
+ let observer = null;
255
+ const forget = () => {
256
+ held = null;
257
+ observer?.disconnect();
258
+ observer = null;
259
+ };
260
+ const onFocusIn = (e) => {
261
+ const list = listRef.current;
262
+ const t = e.target;
263
+ if (!list || !(t instanceof HTMLElement) || !list.contains(t)) {
264
+ if (held) forget();
265
+ return;
266
+ }
267
+ held = rememberFocus(t);
268
+ if (observer) return;
269
+ observer = new MutationObserver(() => {
270
+ const h = held;
271
+ if (!h || h.el.isConnected) return;
272
+ const active = document.activeElement;
273
+ forget();
274
+ if (!active || active === document.body || !active.isConnected) h.restore();
275
+ });
276
+ observer.observe(list, { childList: true, subtree: true });
277
+ };
278
+ const onFocusOut = (e) => {
279
+ if (!held || e.target !== held.el) return;
280
+ queueMicrotask(() => {
281
+ if (held?.el.isConnected && !listRef.current?.contains(document.activeElement)) forget();
282
+ });
283
+ };
284
+ document.addEventListener("focusin", onFocusIn, true);
285
+ document.addEventListener("focusout", onFocusOut, true);
286
+ return () => {
287
+ document.removeEventListener("focusin", onFocusIn, true);
288
+ document.removeEventListener("focusout", onFocusOut, true);
289
+ const h = held;
290
+ forget();
291
+ const active = document.activeElement;
292
+ if (h && !h.el.isConnected && (!active || active === document.body || !active.isConnected)) h.restore();
293
+ };
294
+ }, [listRef]);
295
+ }
296
+ var openers = /* @__PURE__ */ new WeakMap();
297
+ function rememberOpener(active, root) {
298
+ let own = active instanceof HTMLElement && active !== document.body && active.isConnected ? rememberFocus(active) : null;
299
+ const controller = !own && root?.id ? document.querySelector(`[aria-controls~="${CSS.escape(root.id)}"]`) : null;
300
+ if (controller) own = rememberFocus(controller);
301
+ let around = null;
302
+ for (let n = active; n && !around; n = n.parentElement) {
303
+ const opener = openers.get(n);
304
+ if (opener) around = { root: n, opener };
305
+ }
306
+ const back = own ?? around?.opener;
307
+ if (!back) {
308
+ if (!root) return null;
309
+ const places = placesOf(root);
310
+ const { pathname } = location;
311
+ return {
312
+ el: null,
313
+ restore() {
314
+ setTimeout(() => {
315
+ const now = document.activeElement;
316
+ if (now && now !== document.body && now.isConnected && !root.contains(now) || location.pathname !== pathname) return;
317
+ landLastResort(places, root);
318
+ }, LAST_RESORT_MS);
319
+ return false;
320
+ }
321
+ };
322
+ }
323
+ if (root) openers.set(root, back);
324
+ return {
325
+ el: own?.el ?? null,
326
+ restore(fallback) {
327
+ if (own?.restore(fallback)) return true;
328
+ return !!around && !around.root.isConnected && around.opener.restore();
158
329
  }
159
330
  };
160
331
  }
@@ -163,8 +334,7 @@ function useReturnFocus(open, root) {
163
334
  const before = useFocusBeforeOpen(open);
164
335
  useEffect(() => {
165
336
  if (open) {
166
- const active2 = before.current;
167
- remembered.current = active2 instanceof HTMLElement && active2 !== document.body && active2.isConnected ? rememberFocus(active2) : null;
337
+ remembered.current = rememberOpener(before.current, root?.current);
168
338
  return;
169
339
  }
170
340
  const r = remembered.current;
@@ -191,10 +361,14 @@ function rovingTabStop(items, isChecked, isDisabled = () => false) {
191
361
  function focusAfterRemoval(items, index, fallback) {
192
362
  (items[index - 1] ?? items[index] ?? fallback)?.focus();
193
363
  }
194
- function focusAfterSelfRemoval(control, { item, group } = {}) {
364
+ function mayStop(root) {
365
+ const disabled = (el) => (el instanceof HTMLButtonElement || el instanceof HTMLInputElement || el instanceof HTMLSelectElement || el instanceof HTMLTextAreaElement) && el.disabled;
366
+ return Array.from(root.querySelectorAll(`${FOCUSABLE}, button:disabled, input:disabled, select:disabled, textarea:disabled`)).filter((el) => disabled(el) ? !(el instanceof HTMLInputElement && el.type === "hidden") : isTabStop(el)).sort((a, b) => a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_FOLLOWING ? -1 : 1);
367
+ }
368
+ function focusAfterSelfRemoval(control, { item, group, to } = {}) {
195
369
  const goes = item ?? control;
196
370
  const within = group === void 0 ? goes.parentElement : group;
197
- const stops = within ? tabStops(within).filter((el) => !goes.contains(el)) : [];
371
+ const stops = within ? mayStop(within).filter((el) => !goes.contains(el)) : [];
198
372
  const before = stops.filter((el) => goes.compareDocumentPosition(el) & Node.DOCUMENT_POSITION_PRECEDING).reverse();
199
373
  const after = stops.filter((el) => goes.compareDocumentPosition(el) & Node.DOCUMENT_POSITION_FOLLOWING);
200
374
  const stopsOf = (el) => [...isTabStop(el) ? [el] : [], ...tabStops(el)];
@@ -224,7 +398,7 @@ function focusAfterSelfRemoval(control, { item, group } = {}) {
224
398
  within.focus();
225
399
  return document.activeElement === within;
226
400
  };
227
- const place = () => land(sameBefore) || land(before[0]) || land(sameAfter) || land(after[0]) || landOnGroup();
401
+ const place = () => land(typeof to === "function" ? to() : to) || land(sameBefore) || before.some(land) || land(sameAfter) || after.some(land) || landOnGroup();
228
402
  if (typeof MutationObserver === "undefined") return () => {
229
403
  };
230
404
  const observer = new MutationObserver(() => {
@@ -338,6 +512,7 @@ function usePopupFocus(open, { trigger, panel, close, tabExits, onTabOut, marked
338
512
  const inPanel = active instanceof Node && !!panel.current?.contains(active);
339
513
  const opener = active instanceof HTMLElement && active !== document.body && !inPanel ? active : trigger.current;
340
514
  remembered.current = opener ? rememberFocus(opener) : null;
515
+ if (panel.current && remembered.current) openers.set(panel.current, remembered.current);
341
516
  lastPress.current = null;
342
517
  }, [open, trigger, panel, before]);
343
518
  useEffect(() => {
@@ -517,12 +692,13 @@ function useGridKeyboard({ container, active, setActive, keyOf, move, onActivate
517
692
  return { onKeyDown, tabIndexOf, focusActive, focus };
518
693
  }
519
694
  var ALWAYS_TOP = () => true;
520
- function useFocusTrap(root, active, isTop = ALWAYS_TOP) {
695
+ function useFocusTrap(root, active, isTop = ALWAYS_TOP, also) {
521
696
  useEffect(() => {
522
697
  if (!active) return;
523
698
  const onKeyDown = (e) => {
524
699
  if (e.key !== "Tab" || e.defaultPrevented || !root.current || !isTop()) return;
525
- const focusable = tabStops(root.current);
700
+ const scope = [root.current, also?.current].filter((el) => !!el);
701
+ const focusable = scope.flatMap((el) => tabStops(el)).sort((a, b) => a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_FOLLOWING ? -1 : 1);
526
702
  if (focusable.length === 0) {
527
703
  e.preventDefault();
528
704
  return;
@@ -530,7 +706,7 @@ function useFocusTrap(root, active, isTop = ALWAYS_TOP) {
530
706
  const first = focusable[0];
531
707
  const last = focusable[focusable.length - 1];
532
708
  const current = document.activeElement;
533
- const inside = current instanceof Node && root.current.contains(current);
709
+ const inside = current instanceof Node && scope.some((el) => el.contains(current));
534
710
  if (e.shiftKey) {
535
711
  if (!inside || current === first) {
536
712
  e.preventDefault();
@@ -543,7 +719,24 @@ function useFocusTrap(root, active, isTop = ALWAYS_TOP) {
543
719
  };
544
720
  document.addEventListener("keydown", onKeyDown);
545
721
  return () => document.removeEventListener("keydown", onKeyDown);
546
- }, [root, active, isTop]);
722
+ }, [root, active, isTop, also]);
723
+ }
724
+ function inertOutside(keep, within) {
725
+ const made = [];
726
+ const visit = (el) => {
727
+ for (const child of Array.from(el.children)) {
728
+ if (keep.includes(child)) continue;
729
+ if (keep.some((k) => child.contains(k))) visit(child);
730
+ else if (!child.hasAttribute("inert")) {
731
+ child.setAttribute("inert", "");
732
+ made.push(child);
733
+ }
734
+ }
735
+ };
736
+ visit(within);
737
+ return () => {
738
+ for (const el of made) el.removeAttribute("inert");
739
+ };
547
740
  }
548
741
  function useNonModalDialog(root, active, onClose, isTop = ALWAYS_TOP) {
549
742
  const onCloseRef = useLatest(onClose);
@@ -567,6 +760,6 @@ function useNonModalDialog(root, active, onClose, isTop = ALWAYS_TOP) {
567
760
  }, [active, root, isTop, onCloseRef]);
568
761
  }
569
762
 
570
- export { CONTROL_ANCESTOR, FIELD, FOCUSABLE, OVERLAY_CLOSE_ATTR, ZOOM_KEYS, focusAfterRemoval, focusAfterSelfRemoval, focusInitial, isTabStop, rememberFocus, rovingTabStop, tabStops, useCloseOnFocusOut, useFocusBeforeOpen, useFocusLeave, useFocusTrap, useGridKeyboard, useNonModalDialog, useOverlayLayer, usePopupFocus, usePressMarks, useReturnFocus };
571
- //# sourceMappingURL=chunk-OIOII5L6.js.map
572
- //# sourceMappingURL=chunk-OIOII5L6.js.map
763
+ export { CONTROL_ANCESTOR, FIELD, FOCUSABLE, OVERLAY_CLOSE_ATTR, ZOOM_KEYS, focusAfterRemoval, focusAfterSelfRemoval, focusInitial, inertOutside, isTabStop, rememberFocus, rememberOpener, rovingTabStop, tabStops, useCloseOnFocusOut, useFocusBeforeOpen, useFocusKeptInList, useFocusLeave, useFocusTrap, useGridKeyboard, useNonModalDialog, useOverlayLayer, usePopupFocus, usePressMarks, useReturnFocus };
764
+ //# sourceMappingURL=chunk-R5QXMNW7.js.map
765
+ //# sourceMappingURL=chunk-R5QXMNW7.js.map