gridsmith-ui 0.30.0 → 0.30.2

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 (70) hide show
  1. package/CHANGELOG.md +61 -1
  2. package/dist/charts.js +21 -8
  3. package/dist/charts.js.map +1 -1
  4. package/dist/chat.js +15 -9
  5. package/dist/chat.js.map +1 -1
  6. package/dist/{chunk-OIOII5L6.js → chunk-4HJDOZ2M.js} +303 -20
  7. package/dist/chunk-4HJDOZ2M.js.map +1 -0
  8. package/dist/{chunk-INGF2CPW.js → chunk-6C2IUMY7.js} +3 -3
  9. package/dist/{chunk-INGF2CPW.js.map → chunk-6C2IUMY7.js.map} +1 -1
  10. package/dist/chunk-ACLKDE5W.js +59 -0
  11. package/dist/chunk-ACLKDE5W.js.map +1 -0
  12. package/dist/{chunk-NLXQ323J.js → chunk-BZRZENBS.js} +5 -4
  13. package/dist/chunk-BZRZENBS.js.map +1 -0
  14. package/dist/{chunk-RHWTMTU5.js → chunk-DBHVJ7Z3.js} +5 -49
  15. package/dist/chunk-DBHVJ7Z3.js.map +1 -0
  16. package/dist/{chunk-Z4MCD73B.js → chunk-HVGHGBKV.js} +6 -7
  17. package/dist/chunk-HVGHGBKV.js.map +1 -0
  18. package/dist/{chunk-UNS4TGGK.js → chunk-K6IDOCGE.js} +77 -27
  19. package/dist/chunk-K6IDOCGE.js.map +1 -0
  20. package/dist/{chunk-Q36JVJX4.js → chunk-MIUSSYVE.js} +4 -4
  21. package/dist/{chunk-Q36JVJX4.js.map → chunk-MIUSSYVE.js.map} +1 -1
  22. package/dist/{chunk-F2BNJSON.js → chunk-SIWERRP2.js} +70 -69
  23. package/dist/chunk-SIWERRP2.js.map +1 -0
  24. package/dist/{chunk-KTPGMJUK.js → chunk-SQHKC4HA.js} +8 -5
  25. package/dist/chunk-SQHKC4HA.js.map +1 -0
  26. package/dist/{chunk-NI5542ZM.js → chunk-USHW523V.js} +81 -24
  27. package/dist/chunk-USHW523V.js.map +1 -0
  28. package/dist/{chunk-GQVBZ4GW.js → chunk-WWN6CQKI.js} +31 -104
  29. package/dist/chunk-WWN6CQKI.js.map +1 -0
  30. package/dist/{chunk-JTU7OBYJ.js → chunk-YL5KD5RC.js} +4 -3
  31. package/dist/chunk-YL5KD5RC.js.map +1 -0
  32. package/dist/{chunk-6A5RHW2W.js → chunk-ZASGFL5D.js} +4 -5
  33. package/dist/chunk-ZASGFL5D.js.map +1 -0
  34. package/dist/chunk-ZCDA74RQ.js +110 -0
  35. package/dist/chunk-ZCDA74RQ.js.map +1 -0
  36. package/dist/data-grid.js +8 -10
  37. package/dist/data-grid.js.map +1 -1
  38. package/dist/editor-mentions.js +3 -5
  39. package/dist/editor-mentions.js.map +1 -1
  40. package/dist/editor.js +8 -7
  41. package/dist/editor.js.map +1 -1
  42. package/dist/index.d.ts +14 -1
  43. package/dist/index.js +198 -105
  44. package/dist/index.js.map +1 -1
  45. package/dist/kanban.js +11 -12
  46. package/dist/kanban.js.map +1 -1
  47. package/dist/resizable.js +42 -14
  48. package/dist/resizable.js.map +1 -1
  49. package/dist/utils.js.map +1 -1
  50. package/dist/virtualized.d.ts +6 -1
  51. package/dist/virtualized.js +12 -11
  52. package/dist/virtualized.js.map +1 -1
  53. package/package.json +1 -1
  54. package/dist/chunk-6A5RHW2W.js.map +0 -1
  55. package/dist/chunk-F2BNJSON.js.map +0 -1
  56. package/dist/chunk-GQVBZ4GW.js.map +0 -1
  57. package/dist/chunk-HP7WUZPK.js +0 -81
  58. package/dist/chunk-HP7WUZPK.js.map +0 -1
  59. package/dist/chunk-HTXP5BMM.js +0 -38
  60. package/dist/chunk-HTXP5BMM.js.map +0 -1
  61. package/dist/chunk-JTU7OBYJ.js.map +0 -1
  62. package/dist/chunk-KTPGMJUK.js.map +0 -1
  63. package/dist/chunk-NI5542ZM.js.map +0 -1
  64. package/dist/chunk-NLXQ323J.js.map +0 -1
  65. package/dist/chunk-OIOII5L6.js.map +0 -1
  66. package/dist/chunk-RHWTMTU5.js.map +0 -1
  67. package/dist/chunk-UNS4TGGK.js.map +0 -1
  68. package/dist/chunk-WH2FUFAC.js +0 -15
  69. package/dist/chunk-WH2FUFAC.js.map +0 -1
  70. package/dist/chunk-Z4MCD73B.js.map +0 -1
@@ -1,7 +1,8 @@
1
1
  "use client";
2
- import { Badge } from './chunk-NLXQ323J.js';
2
+ import { Badge } from './chunk-BZRZENBS.js';
3
+ import { useKeyboardScroll } from './chunk-ACLKDE5W.js';
3
4
  import { slotIcon, Icon } from './chunk-L6HWACK7.js';
4
- import { cn, FOCUS_RING } from './chunk-JTU7OBYJ.js';
5
+ import { cn, FOCUS_RING, FOCUS_INSET } from './chunk-YL5KD5RC.js';
5
6
  import { forwardRef, useState, useCallback } from 'react';
6
7
  import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
7
8
 
@@ -23,6 +24,8 @@ function CodeBlock({
23
24
  }, [code]);
24
25
  const lines = code.split("\n");
25
26
  const wraps = wrap ?? lines.length === 1;
27
+ const [scroller, setScroller] = useState(null);
28
+ useKeyboardScroll(scroller, "Code", !wraps, false, "x");
26
29
  const gutterWidth = showLineNumbers ? `${String(lines.length).length + 1}ch` : void 0;
27
30
  return /* @__PURE__ */ jsxs(
28
31
  "div",
@@ -60,7 +63,7 @@ function CodeBlock({
60
63
  }
61
64
  )
62
65
  ] }),
63
- /* @__PURE__ */ jsx("div", { className: wraps ? void 0 : "overflow-x-auto", "data-wrap": wraps ? "true" : void 0, children: /* @__PURE__ */ jsx("pre", { className: cn("p-ds-4 text-sm leading-relaxed font-[family-name:var(--ds-font-mono)]", wraps && "whitespace-pre-wrap break-words"), children: /* @__PURE__ */ jsx("code", { children: lines.map((line, i) => (
66
+ /* @__PURE__ */ jsx("div", { ref: setScroller, className: wraps ? void 0 : cn("overflow-x-auto", FOCUS_INSET), "data-wrap": wraps ? "true" : void 0, children: /* @__PURE__ */ jsx("pre", { className: cn("p-ds-4 text-sm leading-relaxed font-[family-name:var(--ds-font-mono)]", wraps && "whitespace-pre-wrap break-words"), children: /* @__PURE__ */ jsx("code", { children: lines.map((line, i) => (
64
67
  // with line numbers each line is a two-column row, so a wrapped line continues under its text, not under the gutter
65
68
  /* @__PURE__ */ jsxs("span", { className: showLineNumbers ? "grid grid-cols-[max-content_1fr]" : "block", children: [
66
69
  showLineNumbers && /* @__PURE__ */ jsx(
@@ -159,5 +162,5 @@ function Divider({
159
162
  }
160
163
 
161
164
  export { CodeBlock, Divider, Link };
162
- //# sourceMappingURL=chunk-KTPGMJUK.js.map
163
- //# sourceMappingURL=chunk-KTPGMJUK.js.map
165
+ //# sourceMappingURL=chunk-SQHKC4HA.js.map
166
+ //# sourceMappingURL=chunk-SQHKC4HA.js.map
@@ -0,0 +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-SQHKC4HA.js","sourcesContent":["import { useState, useCallback } from \"react\";\nimport { cn, FOCUS_INSET, FOCUS_RING } from \"../lib/utils\";\nimport { useKeyboardScroll } from \"../lib/use-keyboard-scroll\";\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 // code that scrolls sideways, with nothing in it to Tab to: a Tab stop while it scrolls (Sprint 25.30 item 2)\n const [scroller, setScroller] = useState<HTMLDivElement | null>(null);\n useKeyboardScroll(scroller, \"Code\", !wraps, false, \"x\");\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 ref={setScroller} className={wraps ? undefined : cn(\"overflow-x-auto\", FOCUS_INSET)} 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"]}
@@ -2,15 +2,13 @@
2
2
  import { useShellPreferences, PREFERENCE_HOUSE_DEFAULTS } from './chunk-TYNDXMBV.js';
3
3
  import { useInputModality } from './chunk-7RKC5C7G.js';
4
4
  import { useReportedChange, useOptionalFormContext, FormChangeCtx } from './chunk-72SDAX54.js';
5
- import { ControlSizeContext, triggerType, RowsCtx, Button } from './chunk-Q36JVJX4.js';
6
- import { useRevealFocus } from './chunk-HTXP5BMM.js';
7
- import { useFocusLeave, usePopupFocus, focusAfterRemoval, usePressMarks, focusInitial } from './chunk-OIOII5L6.js';
8
- import { useTextOverflow, AutoTooltip } from './chunk-GQVBZ4GW.js';
9
- import { Slot } from './chunk-7Q46JXSK.js';
5
+ import { ControlSizeContext, triggerType, RowsCtx, Button } from './chunk-MIUSSYVE.js';
6
+ import { useTextOverflow } from './chunk-ZCDA74RQ.js';
7
+ import { useRevealFocus, AutoTooltip } from './chunk-WWN6CQKI.js';
10
8
  import { Icon, warnOnce } from './chunk-L6HWACK7.js';
11
- import { usePosition } from './chunk-HP7WUZPK.js';
12
- import { useLatest } from './chunk-WH2FUFAC.js';
13
- import { cn, ERROR_HAS_FOCUS_RING, FIELD_HAS_FOCUS_RING, ERROR_FOCUS_RING, FIELD_FOCUS_RING, FOCUS_RING, ERROR_ACTIVE_RING, ACTIVE_RING, ERROR_FOCUS_WITHIN_RING, FIELD_FOCUS_WITHIN_RING, GLASS_DROPDOWN } from './chunk-JTU7OBYJ.js';
9
+ import { Slot } from './chunk-7Q46JXSK.js';
10
+ import { useLatest, useFocusLeave, usePopupFocus, focusAfterRemoval, usePosition, usePressMarks, focusInitial, focusAfterSelfRemoval, tabStops } from './chunk-4HJDOZ2M.js';
11
+ import { cn, ERROR_HAS_FOCUS_RING, FIELD_HAS_FOCUS_RING, ERROR_FOCUS_RING, FIELD_FOCUS_RING, FOCUS_RING, ERROR_ACTIVE_RING, ACTIVE_RING, ERROR_FOCUS_WITHIN_RING, FIELD_FOCUS_WITHIN_RING, GLASS_DROPDOWN } from './chunk-YL5KD5RC.js';
14
12
  import { createContext, useContext, useRef, useCallback, useEffect, useId, useState, Children, isValidElement, useMemo, cloneElement, useLayoutEffect } from 'react';
15
13
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
16
14
  import { createPortal } from 'react-dom';
@@ -411,6 +409,7 @@ function Dropdown({
411
409
  const triggerId = control.id ?? generatedId;
412
410
  const labelSpanId = `${triggerId}-label`;
413
411
  const labelledBy = control.labelId ? `${control.labelId} ${triggerId}` : label && !ariaLabel ? `${labelSpanId} ${triggerId}` : void 0;
412
+ const listLabelledBy = control.labelId ?? (label && !ariaLabel ? labelSpanId : void 0);
414
413
  const invalid = control.invalid;
415
414
  const size = sizeProp ?? contextSize ?? "md";
416
415
  const [open, setOpen] = useState(false);
@@ -558,6 +557,8 @@ function Dropdown({
558
557
  groups.get(g).push(opt);
559
558
  }
560
559
  const hasGroups = Array.from(groups.keys()).some((k) => k !== "");
560
+ const drawn = hasGroups ? Array.from(groups.values()).flat() : filtered;
561
+ const stopId = (drawn.find((o) => selectedValues.includes(o.id)) ?? drawn[0])?.id;
561
562
  const handleSelect = (id) => {
562
563
  if (multiple) {
563
564
  const arr = selectedValues.includes(id) ? selectedValues.filter((v) => v !== id) : [...selectedValues, id];
@@ -654,12 +655,13 @@ function Dropdown({
654
655
  className: cn("w-full bg-transparent text-[var(--ds-text-primary)] placeholder:text-[var(--ds-text-muted)] outline-none", size === "sm" ? "text-xs" : "text-sm")
655
656
  }
656
657
  ) }),
657
- /* @__PURE__ */ jsx("div", { ref: setListbox, role: "listbox", className: "overflow-y-auto scroll-p-[4px]", style: { padding: "max(var(--ds-space-1), 4px)", maxHeight: "var(--ds-dropdown-max-height)" }, children: filtered.length === 0 ? /* @__PURE__ */ jsx("p", { className: cn("text-[var(--ds-text-muted)] text-center py-ds-4", size === "sm" ? "text-xs" : "text-sm"), children: "No options found" }) : hasGroups ? Array.from(groups.entries()).map(([group, opts]) => /* @__PURE__ */ jsxs("div", { children: [
658
+ /* @__PURE__ */ jsx("div", { ref: setListbox, role: "listbox", "aria-labelledby": listLabelledBy, "aria-label": listLabelledBy ? void 0 : ariaLabel, "aria-multiselectable": multiple || void 0, className: "overflow-y-auto scroll-p-[4px]", style: { padding: "max(var(--ds-space-1), 4px)", maxHeight: "var(--ds-dropdown-max-height)" }, children: filtered.length === 0 ? /* @__PURE__ */ jsx("p", { className: cn("text-[var(--ds-text-muted)] text-center py-ds-4", size === "sm" ? "text-xs" : "text-sm"), children: "No options found" }) : hasGroups ? Array.from(groups.entries()).map(([group, opts]) => /* @__PURE__ */ jsxs("div", { children: [
658
659
  group && /* @__PURE__ */ jsx("p", { className: "text-2xs font-medium uppercase tracking-wider text-[var(--ds-text-muted)] px-ds-2 pt-ds-2 pb-ds-1", children: group }),
659
660
  opts.map((opt) => /* @__PURE__ */ jsx(
660
661
  OptionButton,
661
662
  {
662
663
  opt,
664
+ tabStop: opt.id === stopId,
663
665
  isSelected: selectedValues.includes(opt.id),
664
666
  multiple,
665
667
  onSelect: handleSelect,
@@ -671,6 +673,7 @@ function Dropdown({
671
673
  OptionButton,
672
674
  {
673
675
  opt,
676
+ tabStop: opt.id === stopId,
674
677
  isSelected: selectedValues.includes(opt.id),
675
678
  multiple,
676
679
  onSelect: handleSelect,
@@ -691,7 +694,7 @@ function Dropdown({
691
694
  className: "inline-flex items-center gap-ds-1 text-xs rounded-[var(--ds-radius-sm)] bg-[var(--ds-bg-muted)] text-[var(--ds-text-secondary)] px-ds-1.5 py-ds-0.5",
692
695
  children: [
693
696
  opt.label,
694
- /* @__PURE__ */ jsx(
697
+ /* @__PURE__ */ jsx(AutoTooltip, { content: `Remove ${opt.label}`, children: /* @__PURE__ */ jsx(
695
698
  "button",
696
699
  {
697
700
  type: "button",
@@ -704,7 +707,7 @@ function Dropdown({
704
707
  "aria-label": `Remove ${opt.label}`,
705
708
  children: /* @__PURE__ */ jsx(Icon, { name: "close", size: 10 })
706
709
  }
707
- )
710
+ ) })
708
711
  ]
709
712
  },
710
713
  v
@@ -714,6 +717,7 @@ function Dropdown({
714
717
  }
715
718
  function OptionButton({
716
719
  opt,
720
+ tabStop,
717
721
  isSelected,
718
722
  multiple,
719
723
  onSelect,
@@ -726,7 +730,7 @@ function OptionButton({
726
730
  role: "option",
727
731
  "data-option-id": opt.id,
728
732
  "aria-selected": isSelected,
729
- tabIndex: -1,
733
+ tabIndex: tabStop ? 0 : -1,
730
734
  onClick: () => onSelect(opt.id),
731
735
  className: cn(
732
736
  "w-full text-left cursor-pointer rounded-[var(--ds-radius-sm)]",
@@ -1098,11 +1102,31 @@ function contentTop(el) {
1098
1102
  }
1099
1103
  function LoadMore({ hasMore, onLoadMore, loadMoreLabel, currentPage, scroll, className }) {
1100
1104
  const marker = useRef(null);
1105
+ const button = useRef(null);
1106
+ const pager = useRef(null);
1107
+ const watching = useRef(null);
1108
+ const press = () => {
1109
+ const b = button.current, root = pager.current;
1110
+ if (b && root && document.activeElement === b) {
1111
+ const list = root.previousElementSibling;
1112
+ const had = new Set(rowsOf(list));
1113
+ watching.current?.();
1114
+ watching.current = focusAfterSelfRemoval(b, {
1115
+ item: root,
1116
+ to: () => {
1117
+ const fresh = rowsOf(list).find((r) => !had.has(r));
1118
+ return fresh ? tabStops(fresh)[0] ?? fresh : null;
1119
+ }
1120
+ });
1121
+ }
1122
+ onLoadMore();
1123
+ };
1101
1124
  const load = useLatest(onLoadMore);
1102
1125
  const loadedAt = useRef(null);
1126
+ const [held, setHeld] = useState(false);
1103
1127
  useEffect(() => {
1104
1128
  const el = marker.current;
1105
- if (!scroll || !hasMore || !el || typeof IntersectionObserver === "undefined") return;
1129
+ if (!scroll || !hasMore || !el || held || typeof IntersectionObserver === "undefined") return;
1106
1130
  const observer = new IntersectionObserver((entries) => {
1107
1131
  if (!entries.some((e) => e.isIntersecting)) return;
1108
1132
  const at = contentTop(el);
@@ -1119,13 +1143,40 @@ function LoadMore({ hasMore, onLoadMore, loadMoreLabel, currentPage, scroll, cla
1119
1143
  observer.disconnect();
1120
1144
  window.removeEventListener("scroll", rearm, { capture: true });
1121
1145
  };
1122
- }, [scroll, hasMore, currentPage, load]);
1146
+ }, [scroll, hasMore, currentPage, load, held]);
1147
+ useEffect(() => {
1148
+ const b = button.current;
1149
+ if (b && document.activeElement === b) b.scrollIntoView?.({ block: "nearest" });
1150
+ }, [currentPage]);
1123
1151
  if (!hasMore) return null;
1124
- return /* @__PURE__ */ jsxs("div", { "data-ds-pager": "", "data-pagination-mode": scroll ? "infinite-scroll" : "load-more", className: cn("flex flex-col items-center", className), children: [
1152
+ return /* @__PURE__ */ jsxs("div", { ref: pager, "data-ds-pager": "", "data-pagination-mode": scroll ? "infinite-scroll" : "load-more", className: cn("flex flex-col items-center", className), children: [
1125
1153
  scroll && /* @__PURE__ */ jsx("div", { ref: marker, "data-load-more-trigger": "", "aria-hidden": "true", className: "h-px w-full" }),
1126
- /* @__PURE__ */ jsx(Button, { type: "button", variant: "secondary", onClick: onLoadMore, children: loadMoreLabel ?? "Load more" })
1154
+ /* @__PURE__ */ jsx(
1155
+ Button,
1156
+ {
1157
+ ref: button,
1158
+ type: "button",
1159
+ variant: "secondary",
1160
+ onClick: press,
1161
+ onFocus: (e) => setHeld(scroll && byKeyboard(e.currentTarget)),
1162
+ onBlur: () => setHeld(false),
1163
+ children: loadMoreLabel ?? "Load more"
1164
+ }
1165
+ )
1127
1166
  ] });
1128
1167
  }
1168
+ function rowsOf(list) {
1169
+ if (!list) return [];
1170
+ const marked = list.querySelectorAll("[data-row-key], [data-row-index]");
1171
+ return Array.from(marked.length ? marked : list.querySelectorAll('tbody > tr, li, [role="row"], [data-card]'));
1172
+ }
1173
+ function byKeyboard(el) {
1174
+ try {
1175
+ return el.matches(":focus-visible");
1176
+ } catch {
1177
+ return true;
1178
+ }
1179
+ }
1129
1180
  function PageNumbers({ currentPage, totalPages, onPageChange, pageSize: pageSizeProp, pageSizeOptions, onPageSizeChange, className }) {
1130
1181
  const pages = buildPageRange(currentPage, totalPages);
1131
1182
  const preferences = useShellPreferences();
@@ -1148,11 +1199,14 @@ function PageNumbers({ currentPage, totalPages, onPageChange, pageSize: pageSize
1148
1199
  ) })
1149
1200
  ] }),
1150
1201
  totalPages > 1 && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-ds-1", children: [
1151
- /* @__PURE__ */ jsx(
1202
+ /* @__PURE__ */ jsx(AutoTooltip, { content: "Previous page", children: /* @__PURE__ */ jsx(
1152
1203
  "button",
1153
1204
  {
1154
1205
  type: "button",
1155
- onClick: () => onPageChange(currentPage - 1),
1206
+ onClick: (e) => {
1207
+ focusAfterSelfRemoval(e.currentTarget);
1208
+ onPageChange(currentPage - 1);
1209
+ },
1156
1210
  disabled: currentPage <= 1,
1157
1211
  "aria-label": "Previous page",
1158
1212
  className: cn(
@@ -1167,7 +1221,7 @@ function PageNumbers({ currentPage, totalPages, onPageChange, pageSize: pageSize
1167
1221
  ),
1168
1222
  children: /* @__PURE__ */ jsx(Icon, { name: "chevron-right", size: 16, className: "rotate-180" })
1169
1223
  }
1170
- ),
1224
+ ) }),
1171
1225
  pages.map(
1172
1226
  (p, i) => p === "..." ? /* @__PURE__ */ jsx(EllipsisJumper, { totalPages, onPageChange }, `ellipsis-${i}`) : /* @__PURE__ */ jsx(
1173
1227
  "button",
@@ -1188,11 +1242,14 @@ function PageNumbers({ currentPage, totalPages, onPageChange, pageSize: pageSize
1188
1242
  p
1189
1243
  )
1190
1244
  ),
1191
- /* @__PURE__ */ jsx(
1245
+ /* @__PURE__ */ jsx(AutoTooltip, { content: "Next page", children: /* @__PURE__ */ jsx(
1192
1246
  "button",
1193
1247
  {
1194
1248
  type: "button",
1195
- onClick: () => onPageChange(currentPage + 1),
1249
+ onClick: (e) => {
1250
+ focusAfterSelfRemoval(e.currentTarget);
1251
+ onPageChange(currentPage + 1);
1252
+ },
1196
1253
  disabled: currentPage >= totalPages,
1197
1254
  "aria-label": "Next page",
1198
1255
  className: cn(
@@ -1207,7 +1264,7 @@ function PageNumbers({ currentPage, totalPages, onPageChange, pageSize: pageSize
1207
1264
  ),
1208
1265
  children: /* @__PURE__ */ jsx(Icon, { name: "chevron-right", size: 16 })
1209
1266
  }
1210
- )
1267
+ ) })
1211
1268
  ] })
1212
1269
  ] });
1213
1270
  }
@@ -1374,5 +1431,5 @@ function useWholeListCheck(component, length, pager) {
1374
1431
  }
1375
1432
 
1376
1433
  export { AddAnotherRowCtx, CHECK_FILL, Dropdown, Field, FilterRowContext, InlineFieldError, Input, Label, NumberInput, OutsideField, Pagination, Popover, SWITCH_KNOB_MOTION, SWITCH_KNOB_OFF, SWITCH_KNOB_ON, SWITCH_TRACK_OFF, SWITCH_TRACK_ON, Textarea, Toggle, pagerPart, useField, useFieldControl, usePagination, useWholeListCheck };
1377
- //# sourceMappingURL=chunk-NI5542ZM.js.map
1378
- //# sourceMappingURL=chunk-NI5542ZM.js.map
1434
+ //# sourceMappingURL=chunk-USHW523V.js.map
1435
+ //# sourceMappingURL=chunk-USHW523V.js.map