gridsmith-ui 0.18.0 → 0.19.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/charts.js +3 -3
- package/dist/charts.js.map +1 -1
- package/dist/chat.js +4 -4
- package/dist/{chunk-CIVSNXFG.js → chunk-5PDTHKW3.js} +17 -9
- package/dist/chunk-5PDTHKW3.js.map +1 -0
- package/dist/{chunk-XGSQOMEY.js → chunk-EQDR57AM.js} +4 -4
- package/dist/{chunk-XGSQOMEY.js.map → chunk-EQDR57AM.js.map} +1 -1
- package/dist/{chunk-EMCSARQO.js → chunk-ILIODA7W.js} +3 -3
- package/dist/{chunk-EMCSARQO.js.map → chunk-ILIODA7W.js.map} +1 -1
- package/dist/{chunk-OENJCGTJ.js → chunk-JN37OVTP.js} +4 -4
- package/dist/{chunk-OENJCGTJ.js.map → chunk-JN37OVTP.js.map} +1 -1
- package/dist/{chunk-4KVFH5KC.js → chunk-M2QRNBDQ.js} +4 -3
- package/dist/chunk-M2QRNBDQ.js.map +1 -0
- package/dist/{chunk-Z63OSN64.js → chunk-NCIZQYXQ.js} +7 -4
- package/dist/chunk-NCIZQYXQ.js.map +1 -0
- package/dist/{chunk-PVTGMCVR.js → chunk-XYDIBW3J.js} +4 -4
- package/dist/{chunk-PVTGMCVR.js.map → chunk-XYDIBW3J.js.map} +1 -1
- package/dist/data-grid.js +3 -3
- package/dist/editor.js +3 -3
- package/dist/editor.js.map +1 -1
- package/dist/index.d.ts +146 -53
- package/dist/index.js +437 -156
- package/dist/index.js.map +1 -1
- package/dist/kanban.js +3 -3
- package/dist/resizable.d.ts +8 -1
- package/dist/resizable.js +35 -15
- package/dist/resizable.js.map +1 -1
- package/dist/roots.css +164 -2
- package/dist/tailwind.css +14 -0
- package/dist/utils.js +1 -1
- package/dist/virtualized.js +1 -1
- package/dist-static/tailwind.css +14 -0
- package/package.json +1 -1
- package/dist/chunk-4KVFH5KC.js.map +0 -1
- package/dist/chunk-CIVSNXFG.js.map +0 -1
- package/dist/chunk-Z63OSN64.js.map +0 -1
package/dist/chat.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { Divider, CodeBlock, Link } from './chunk-
|
|
2
|
-
import './chunk-
|
|
3
|
-
import './chunk-
|
|
1
|
+
import { Divider, CodeBlock, Link } from './chunk-EQDR57AM.js';
|
|
2
|
+
import './chunk-XYDIBW3J.js';
|
|
3
|
+
import './chunk-ILIODA7W.js';
|
|
4
4
|
import './chunk-7Q46JXSK.js';
|
|
5
5
|
import './chunk-WH2FUFAC.js';
|
|
6
6
|
import './chunk-4LDYR7QP.js';
|
|
7
|
-
import { cn } from './chunk-
|
|
7
|
+
import { cn } from './chunk-M2QRNBDQ.js';
|
|
8
8
|
import { memo, Children, isValidElement } from 'react';
|
|
9
9
|
import Markdown from 'react-markdown';
|
|
10
10
|
import remarkGfm from 'remark-gfm';
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { useReturnFocus, focusInitial, useOverlayLayer, useFocusTrap, OVERLAY_CLOSE_ATTR, useNonModalDialog } from './chunk-JXANCXK6.js';
|
|
2
2
|
import { PreferencesContext } from './chunk-TKVTZWBN.js';
|
|
3
3
|
import { useBreakpoint, readBreakpointPx } from './chunk-CRQ6KCRD.js';
|
|
4
|
-
import { TooltipCtx, Tooltip, useTextOverflow } from './chunk-
|
|
4
|
+
import { TooltipCtx, Tooltip, useTextOverflow } from './chunk-ILIODA7W.js';
|
|
5
5
|
import { useLatest } from './chunk-WH2FUFAC.js';
|
|
6
6
|
import { Icon } from './chunk-4LDYR7QP.js';
|
|
7
|
-
import { cn, lockBodyScroll, unlockBodyScroll, GLASS_OVERLAY } from './chunk-
|
|
7
|
+
import { cn, lockBodyScroll, unlockBodyScroll, OVERLAY_SURFACE, GLASS_OVERLAY } from './chunk-M2QRNBDQ.js';
|
|
8
8
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
9
9
|
import { createContext, forwardRef, useContext, version, useState, useCallback, useRef, useEffect, isValidElement, useMemo, useId, useLayoutEffect } from 'react';
|
|
10
10
|
import { createPortal } from 'react-dom';
|
|
@@ -394,7 +394,8 @@ function Sheet({ open, onClose: onCloseProp, title, children, footer, confirm, d
|
|
|
394
394
|
"data-ds-sheet": "",
|
|
395
395
|
className: cn(
|
|
396
396
|
`${positionClass} bottom-0 left-0 right-0 z-10 flex flex-col`,
|
|
397
|
-
|
|
397
|
+
OVERLAY_SURFACE,
|
|
398
|
+
"text-[var(--ds-text-primary)]",
|
|
398
399
|
GLASS_OVERLAY,
|
|
399
400
|
"border-t-[length:var(--ds-border-width)] border-[var(--ds-border-default)]",
|
|
400
401
|
"rounded-t-[var(--ds-radius-xl)]",
|
|
@@ -726,7 +727,8 @@ function DrawerPanel({ open, onClose, position = "right", width = "400px", title
|
|
|
726
727
|
className: cn(
|
|
727
728
|
`${positionClass} z-10 flex flex-col`,
|
|
728
729
|
nonModal && "pointer-events-auto",
|
|
729
|
-
|
|
730
|
+
OVERLAY_SURFACE,
|
|
731
|
+
"text-[var(--ds-text-primary)]",
|
|
730
732
|
GLASS_OVERLAY,
|
|
731
733
|
// flush drops the edge border for children that draw their own (the mobile
|
|
732
734
|
// menu's Sidebar); a non-modal panel has no backdrop to separate it from
|
|
@@ -975,10 +977,16 @@ var AppShell = forwardRef(function AppShell2({
|
|
|
975
977
|
}
|
|
976
978
|
) });
|
|
977
979
|
});
|
|
978
|
-
function useCompact(ref, breakpoint) {
|
|
980
|
+
function useCompact(ref, breakpoint, band = 0) {
|
|
979
981
|
const px = typeof breakpoint === "number" ? breakpoint : readBreakpointPx(breakpoint);
|
|
980
982
|
const width = useElementWidth(ref);
|
|
981
|
-
return width
|
|
983
|
+
return useBelow(width, px, band);
|
|
984
|
+
}
|
|
985
|
+
function useBelow(width, threshold, band = 0) {
|
|
986
|
+
const [below, setBelow] = useState(false);
|
|
987
|
+
const next = width > 0 && width < (below ? threshold + band : threshold);
|
|
988
|
+
if (next !== below) setBelow(next);
|
|
989
|
+
return next;
|
|
982
990
|
}
|
|
983
991
|
function useElementWidth(ref) {
|
|
984
992
|
const [width, setWidth] = useState(0);
|
|
@@ -996,6 +1004,6 @@ function useElementWidth(ref) {
|
|
|
996
1004
|
return width;
|
|
997
1005
|
}
|
|
998
1006
|
|
|
999
|
-
export { AppShell, Button, ButtonSizeContext, ControlSizeContext, DiscardConfirm, Drawer, DrawerFooterCtx, OverlayCloseCtx, REACT_VERSION_PROBLEM, ResizeEdge, Sheet, SkipLink, Spinner, defaultMaxWidth, pxOf, useAppShell, useCloseSettle, useCompact, useDirtyGuard, useElementWidth, useRememberedWidth, useUnsavedChanges };
|
|
1000
|
-
//# sourceMappingURL=chunk-
|
|
1001
|
-
//# sourceMappingURL=chunk-
|
|
1007
|
+
export { AppShell, Button, ButtonSizeContext, ControlSizeContext, DiscardConfirm, Drawer, DrawerFooterCtx, OverlayCloseCtx, REACT_VERSION_PROBLEM, ResizeEdge, Sheet, SkipLink, Spinner, defaultMaxWidth, pxOf, useAppShell, useBelow, useCloseSettle, useCompact, useDirtyGuard, useElementWidth, useRememberedWidth, useUnsavedChanges };
|
|
1008
|
+
//# sourceMappingURL=chunk-5PDTHKW3.js.map
|
|
1009
|
+
//# sourceMappingURL=chunk-5PDTHKW3.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../showcase/src/components/Spinner.tsx","../../../showcase/src/components/Button.tsx","../../../showcase/src/lib/use-close-settle.ts","../../../showcase/src/components/DiscardConfirm.tsx","../../../showcase/src/components/Sheet.tsx","../../../showcase/src/lib/edge-resize.tsx","../../../showcase/src/components/Drawer.tsx","../../../showcase/src/components/SkipLink.tsx","../../../showcase/src/lib/react-version.ts","../../../showcase/src/components/AppShell.tsx","../../../showcase/src/lib/use-compact.ts"],"names":["Button","jsx","t","createContext","useEffect","jsxs","useRef","useState","useCallback","useId","createPortal","useContext","forwardRef","AppShell"],"mappings":"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","file":"chunk-5PDTHKW3.js","sourcesContent":["import { cn } from \"../lib/utils\";\n\nconst sizes = {\n sm: \"h-4 w-4 border-[1.5px]\",\n md: \"h-6 w-6 border-2\",\n lg: \"h-8 w-8 border-[2.5px]\",\n} as const;\n\ninterface SpinnerProps {\n size?: keyof typeof sizes;\n color?: \"default\" | \"inherit\";\n label?: string;\n className?: string;\n}\n\nexport function Spinner({ size = \"md\", color = \"default\", label = \"Loading\", className }: SpinnerProps) {\n return (\n <span\n role=\"status\"\n aria-label={label}\n className={cn(\n \"inline-block rounded-[var(--ds-radius-full)] animate-spin\",\n color === \"inherit\"\n ? \"border-current/30 border-t-current\"\n : \"border-[var(--ds-bg-emphasis)] border-t-[var(--ds-accent-primary)]\",\n sizes[size],\n className\n )}\n />\n );\n}\n","import { cn } from \"../lib/utils\";\nimport { createContext, useContext, forwardRef, type ButtonHTMLAttributes, type CSSProperties, type ReactNode } from \"react\";\nimport { Tooltip, TooltipCtx } from \"./Tooltip\";\nimport { Spinner } from \"./Spinner\";\n\ntype ButtonVariant = \"default\" | \"secondary\" | \"tertiary\" | \"outline\" | \"ghost\" | \"destructive\" | \"success\" | \"warning\" | \"link\";\ntype ButtonSize = \"xs\" | \"sm\" | \"md\" | \"lg\" | \"icon-xs\" | \"icon-sm\" | \"icon\" | \"icon-lg\";\n\nexport type ControlSize = \"sm\" | \"md\" | \"lg\";\nexport const ControlSizeContext = createContext<ControlSize | null>(null);\nexport const ButtonSizeContext = ControlSizeContext;\n\ninterface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {\n variant?: ButtonVariant;\n size?: ButtonSize;\n iconLeft?: ReactNode;\n iconRight?: ReactNode;\n loading?: boolean;\n children?: ReactNode;\n}\n\nconst variantStyles: Record<ButtonVariant, string> = {\n default: \"bg-[var(--ds-accent-primary)] [background-image:var(--ds-gradient)] [background-origin:border-box] text-[var(--ds-text-on-primary)] border-transparent hover:bg-[var(--ds-accent-primary-hover)] hover:brightness-110\",\n secondary: \"bg-[var(--ds-bg-surface)] text-[var(--ds-text-primary)] border-[var(--ds-border-default)] hover:bg-[var(--ds-bg-muted)]\",\n tertiary: \"bg-[var(--ds-bg-muted)] text-[var(--ds-text-primary)] border-transparent hover:brightness-95\",\n outline: \"bg-[var(--ds-input-bg)] text-[var(--ds-text-primary)] border-[var(--ds-border-default)] hover:bg-[var(--ds-bg-muted)]\",\n ghost: \"bg-transparent text-[var(--ds-text-primary)] border-transparent hover:bg-[var(--ds-bg-muted)] shadow-none\",\n destructive: \"bg-[var(--ds-status-error)] text-[var(--ds-text-on-error)] border-transparent hover:opacity-90\",\n success: \"bg-[var(--ds-status-success)] text-[var(--ds-text-on-success)] border-transparent hover:opacity-90\",\n warning: \"bg-[var(--ds-status-warning)] text-[var(--ds-text-on-warning)] border-transparent hover:opacity-90\",\n link: \"bg-transparent text-[var(--ds-accent-primary)] hover:text-[var(--ds-accent-primary-hover)] hover:underline\",\n};\n\nconst sizeStyles: Record<ButtonSize, string> = {\n // xs / icon-xs: dense tool chrome (builder toolbars, inline row actions).\n xs: \"h-ds-6 px-ds-3 py-0 text-xs\",\n sm: \"h-[var(--ds-control-height-sm)] px-ds-4 py-ds-1 text-xs\",\n md: \"h-[var(--ds-control-height-md)] px-ds-6 py-ds-2 text-sm\",\n lg: \"h-[var(--ds-control-height-lg)] px-ds-8 py-ds-3 text-base\",\n \"icon-xs\": \"h-ds-6 w-ds-6 p-0\",\n \"icon-sm\": \"h-[var(--ds-control-height-sm)] w-[var(--ds-control-height-sm)] p-0\",\n icon: \"h-[var(--ds-control-height-md)] w-[var(--ds-control-height-md)] p-0\",\n \"icon-lg\": \"h-[var(--ds-control-height-lg)] w-[var(--ds-control-height-lg)] p-0\",\n};\n\n// Link buttons have no box, so only the text size follows `size`.\nconst linkSizeStyles: Record<ButtonSize, string> = {\n xs: \"text-xs\",\n sm: \"text-xs\",\n md: \"text-sm\",\n lg: \"text-base\",\n \"icon-xs\": \"text-xs\",\n \"icon-sm\": \"text-xs\",\n icon: \"text-sm\",\n \"icon-lg\": \"text-base\",\n};\n\nconst iconPaddingReduce: Record<Exclude<ButtonSize, \"icon\" | \"icon-xs\" | \"icon-sm\" | \"icon-lg\">, number> = {\n xs: 2,\n sm: 2,\n md: 4,\n lg: 6,\n};\n\nconst HOVER_SCALE_CAP = { '--_btn-scale': 'min(var(--ds-hover-scale), 1.02)' } as CSSProperties;\n\nexport const Button = forwardRef<HTMLButtonElement, ButtonProps>(function Button({ variant = \"default\", size: sizeProp, iconLeft, iconRight, loading, className, children, disabled, style, onClick, ...props }, ref) {\n const contextSize = useContext(ControlSizeContext);\n const size = sizeProp ?? contextSize ?? \"md\";\n const isLink = variant === \"link\";\n const spinnerSize = size === \"lg\" || size === \"icon-lg\" ? \"md\" : \"sm\";\n let paddingStyle: CSSProperties | undefined;\n const isIconSize = size === \"icon\" || size === \"icon-xs\" || size === \"icon-sm\" || size === \"icon-lg\";\n if (!isIconSize && !isLink && (iconLeft || iconRight)) {\n const reduce = iconPaddingReduce[size];\n paddingStyle = {};\n if (iconLeft) paddingStyle.paddingLeft = `calc(${getCssPadding(size)} - ${reduce}px)`;\n if (iconRight) paddingStyle.paddingRight = `calc(${getCssPadding(size)} - ${reduce}px)`;\n }\n\n const isLoading = loading && !disabled;\n const isDisabled = !!disabled;\n\n const handleClick = isLoading\n ? (e: React.MouseEvent<HTMLButtonElement>) => { e.preventDefault(); }\n : onClick;\n\n const ariaLabel = props[\"aria-label\"];\n // Round 15 (52.7): inside an explicit <Tooltip> the caller owns the label; the automatic one from aria-label would be a second tooltip.\n const inTooltip = useContext(TooltipCtx);\n\n const btn = (\n <button\n ref={ref}\n data-variant={variant}\n className={cn(\n \"relative inline-flex items-center justify-center gap-ds-2 whitespace-nowrap font-medium\",\n isLink\n ? cn(\n \"px-0 py-ds-0.5 h-auto\",\n linkSizeStyles[size],\n \"transition-colors duration-[var(--ds-transition-speed)]\",\n \"focus-visible:outline-2 focus-visible:outline-[var(--ds-accent-primary)] focus-visible:outline-offset-2\",\n \"cursor-pointer\",\n \"active:text-[var(--ds-accent-primary-active)]\",\n )\n : cn(\n \"border-[length:var(--ds-border-width)]\",\n \"rounded-[var(--ds-radius-md)]\",\n \"shadow-[var(--ds-shadow-button)]\",\n \"hover:scale-[var(--_btn-scale)] hover:-translate-y-[var(--ds-hover-lift)]\",\n \"active:shadow-[var(--ds-shadow-button-pressed)] active:translate-x-[var(--ds-press-depth)] active:translate-y-[var(--ds-press-depth)]\",\n \"[transition:var(--ds-transition-interactive)]\",\n \"focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]\",\n \"cursor-pointer disabled:cursor-not-allowed disabled:opacity-disabled\",\n sizeStyles[size],\n ),\n variantStyles[variant],\n isLoading && !isLink && \"cursor-wait pointer-events-none\",\n className\n )}\n disabled={isDisabled}\n aria-busy={isLoading || undefined}\n aria-disabled={isLoading && !disabled ? true : undefined}\n onClick={handleClick}\n style={isLink ? style : { ...HOVER_SCALE_CAP, ...paddingStyle, ...style }}\n {...props}\n >\n {loading && !isLink && (\n <span className=\"absolute inset-0 flex items-center justify-center\">\n <Spinner size={spinnerSize} color=\"inherit\" />\n </span>\n )}\n <span className={cn(\"inline-flex items-center gap-ds-2 min-w-0\", loading && !isLink && \"invisible\")}>\n {iconLeft}\n {children}\n {iconRight}\n </span>\n </button>\n );\n\n if (isIconSize && ariaLabel && !inTooltip) {\n return <Tooltip content={ariaLabel}>{btn}</Tooltip>;\n }\n\n return btn;\n});\n\nfunction getCssPadding(size: Exclude<ButtonSize, \"icon\" | \"icon-xs\" | \"icon-sm\" | \"icon-lg\">): string {\n switch (size) {\n case \"xs\": return \"var(--ds-space-3)\";\n case \"sm\": return \"var(--ds-space-4)\";\n case \"md\": return \"var(--ds-space-6)\";\n case \"lg\": return \"var(--ds-space-8)\";\n }\n}\n","import { useEffect, type RefObject } from \"react\";\nimport { useLatest } from \"./use-latest\";\n\n/** Longest transition (duration + delay) declared on `el`, in milliseconds. */\nfunction transitionMs(el: HTMLElement): number {\n const cs = getComputedStyle(el);\n const parse = (list: string) =>\n list.split(\",\").map((raw) => {\n const s = raw.trim();\n if (!s) return 0;\n const n = parseFloat(s);\n if (Number.isNaN(n)) return 0;\n return s.endsWith(\"ms\") ? n : n * 1000;\n });\n const durations = parse(cs.transitionDuration || \"0s\");\n const delays = parse(cs.transitionDelay || \"0s\");\n let max = 0;\n durations.forEach((d, i) => {\n const total = d + (delays[i] ?? delays[0] ?? 0);\n if (total > max) max = total;\n });\n return max;\n}\n\n/**\n * Run `onSettled` once an overlay's close transition has finished.\n *\n * Overlays used to unmount on `transitionend`, but a transition of zero\n * duration never fires that event — and `prefers-reduced-motion` sets every\n * transition to zero — so a closed Drawer stayed mounted off-screen with its\n * controls still in the Tab order. This settles on the event when there is a\n * transition, immediately (next tick) when there is none, and on a timeout if\n * the browser never reports the end. Reopening during the close cancels it.\n */\nexport function useCloseSettle(open: boolean, elRef: RefObject<HTMLElement | null>, onSettled: () => void) {\n const cb = useLatest(onSettled);\n useEffect(() => {\n if (open) return;\n const el = elRef.current;\n const ms = el ? transitionMs(el) : 0;\n let done = false;\n const finish = () => {\n if (done) return;\n done = true;\n cb.current();\n };\n if (!el || ms === 0) {\n const t = setTimeout(finish, 0);\n return () => clearTimeout(t);\n }\n const onEnd = (e: TransitionEvent) => {\n if (e.target === el) finish();\n };\n el.addEventListener(\"transitionend\", onEnd);\n const t = setTimeout(finish, ms + 50);\n return () => {\n el.removeEventListener(\"transitionend\", onEnd);\n clearTimeout(t);\n };\n }, [open, elRef, cb]);\n}\n","import { createContext, useCallback, useEffect, useRef, useState } from \"react\";\nimport { Button } from \"./Button\";\n\n/**\n * The open overlay's guarded close (round 21): a Drawer, Dialog, or a Sheet given `dirty`, provides it so a form inside\n * can close the overlay through the same unsaved-changes question Escape and the close control ask. FormWrapper's\n * `onCancel` uses it; run 58's hand-wired Cancel closed a half-filled invite with no question while Escape asked.\n * `then` runs once the overlay has closed — never when the user keeps editing (the review of 23 September: the\n * form's own onCancel was dropped inside an overlay).\n */\nexport const OverlayCloseCtx = createContext<((then?: () => void) => void) | null>(null);\n\n/**\n * The dirty guard an overlay with a form shares (Sprint 25.2, C1): while the\n * content is dirty, every close path — Escape, backdrop, the close control —\n * asks first, inside the overlay rather than in a second dialog. The page\n * passes `dirty`; the overlay does the rest.\n */\nexport function useDirtyGuard(dirty: boolean | undefined, onClose: () => void, onDiscard?: () => void) {\n const [wantsConfirm, setWantsConfirm] = useState(false);\n const confirming = wantsConfirm && !!dirty;\n // What runs after the close goes ahead (a form's own onCancel). A close path wired as a click handler passes its event\n // here, so only a function counts; the overlay's own onClose is not run twice.\n const pending = useRef<unknown>(undefined);\n const runAfter = useCallback((then: unknown) => { if (typeof then === \"function\" && then !== onClose) (then as () => void)(); }, [onClose]);\n const requestClose = useCallback((then?: unknown) => {\n if (!dirty) { onClose(); runAfter(then); return; }\n pending.current = then;\n // A second close request while the question is showing (Escape again, another backdrop click) keeps editing.\n setWantsConfirm((c) => !c);\n }, [dirty, onClose, runAfter]);\n const keep = useCallback(() => { pending.current = undefined; setWantsConfirm(false); }, []);\n const discard = useCallback(() => {\n setWantsConfirm(false);\n onDiscard?.();\n onClose();\n const then = pending.current;\n pending.current = undefined;\n runAfter(then);\n }, [onClose, onDiscard, runAfter]);\n return { confirming, requestClose, keep, discard };\n}\n\nexport function DiscardConfirm({ open, onKeep, onDiscard }: { open: boolean; onKeep: () => void; onDiscard: () => void }) {\n const keepRef = useRef<HTMLButtonElement>(null);\n const returnTo = useRef<HTMLElement | null>(null);\n const overlay = useRef<HTMLElement | null>(null);\n // Focus moves to \"Keep editing\" while the question shows and goes back where it was when it closes — or to the\n // overlay's first control when nothing inside it had focus — so a non-modal drawer keeps answering Escape and a\n // screen reader keeps its place (Sprint 25.2 review).\n useEffect(() => {\n if (!open) return;\n const active = document.activeElement instanceof HTMLElement ? document.activeElement : null;\n overlay.current = keepRef.current?.closest<HTMLElement>(\"[role='dialog'], [role='alertdialog']\") ?? null;\n returnTo.current = active && active !== document.body && overlay.current?.contains(active) ? active : null;\n keepRef.current?.focus();\n return () => {\n if (document.activeElement !== document.body) return;\n const back = returnTo.current;\n if (back && back.isConnected) { back.focus(); return; }\n const first = overlay.current?.querySelector<HTMLElement>(\"button:not([disabled]), [href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex='-1'])\");\n (first ?? overlay.current)?.focus();\n };\n }, [open]);\n if (!open) return null;\n return (\n <div\n role=\"group\"\n aria-label=\"Unsaved changes\"\n data-discard-confirm=\"\"\n className=\"shrink-0 flex flex-wrap items-center justify-between gap-ds-3 border-t-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)] bg-[var(--ds-status-warning-bg)]\"\n style={{ padding: \"var(--ds-space-3) var(--ds-space-5)\" }}\n >\n <p className=\"text-sm text-[var(--ds-text-primary)]\">You have unsaved changes.</p>\n <div className=\"flex items-center gap-ds-2\">\n <Button ref={keepRef} variant=\"secondary\" size=\"sm\" onClick={onKeep}>Keep editing</Button>\n <Button variant=\"destructive\" size=\"sm\" onClick={onDiscard}>Discard changes</Button>\n </div>\n </div>\n );\n}\n","import { useEffect, useRef, useState, useCallback, useId, type ReactNode } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { cn, OVERLAY_SURFACE, GLASS_OVERLAY, lockBodyScroll, unlockBodyScroll } from \"../lib/utils\";\nimport { Icon } from \"../lib/icons\";\nimport { focusInitial, useReturnFocus, useFocusTrap, useOverlayLayer, OVERLAY_CLOSE_ATTR } from \"../lib/focus\";\nimport { useCloseSettle } from \"../lib/use-close-settle\";\nimport { useLatest } from \"../lib/use-latest\";\nimport { useDirtyGuard, DiscardConfirm, OverlayCloseCtx } from \"./DiscardConfirm\";\n\ninterface SheetProps {\n open: boolean;\n onClose: () => void;\n title?: ReactNode;\n children: ReactNode;\n footer?: ReactNode;\n /** A strip between the content and the footer (the Drawer's unsaved-changes question). */\n confirm?: ReactNode;\n /**\n * The content has unsaved changes: every close path — Escape, the backdrop, dragging it down, the close control and a\n * FormWrapper's Cancel — asks before discarding them, inside the sheet, as a Drawer and a Dialog do (the review of\n * 23 September: a sheet holding a form threw it away with no question).\n */\n dirty?: boolean;\n /** Runs when the user discards unsaved changes, before onClose (reset the form here). */\n onDiscard?: () => void;\n /** Heights the sheet snaps to, as fractions of the viewport (or container). Default [0.5, 0.92]. */\n snapPoints?: number[];\n /** Render inside this element (absolute positioning, no body scroll lock) instead of document.body. */\n container?: Element | DocumentFragment;\n /** Remove default content padding — use when the child handles its own spacing. */\n flush?: boolean;\n /** Keep the sheet in the DOM while closed (hidden, out of the tab order) so its content's state survives close and reopen. Default false. */\n keepMounted?: boolean;\n /** id applied to the dialog element, for an opener's aria-controls. */\n id?: string;\n /** id of the element that names the dialog when no title is rendered. */\n labelledBy?: string;\n}\n\nexport function Sheet({ open, onClose: onCloseProp, title, children, footer, confirm, dirty, onDiscard, snapPoints = [0.5, 0.92], container, flush, keepMounted = false, id, labelledBy }: SheetProps) {\n // every close path goes through the guard; with no `dirty` it closes at once, as before (a Drawer's phone sheet\n // passes its own guarded close and no `dirty`)\n const guard = useDirtyGuard(dirty, onCloseProp, onDiscard);\n const onClose = guard.requestClose;\n const titleId = useId();\n const panelRef = useRef<HTMLDivElement>(null);\n // Stays mounted while the close transition plays; mounts as soon as `open` flips.\n const [mounted, setMounted] = useState(open);\n const [hidden, setHidden] = useState(!open);\n const [snapIdx, setSnapIdx] = useState(0);\n const [dragOffset, setDragOffset] = useState(0);\n const [dragging, setDragging] = useState(false);\n const dragStartY = useRef(0);\n const startHeight = useRef(0);\n const onCloseRef = useLatest(onClose);\n\n // Reset on every open. This is React's \"adjust state when a prop changes\"\n // pattern: it runs before commit, so the first painted frame is already correct.\n const [prevOpen, setPrevOpen] = useState(open);\n if (open !== prevOpen) {\n setPrevOpen(open);\n if (open) { setMounted(true); setHidden(false); setSnapIdx(0); setDragOffset(0); }\n }\n // While open, mounted and shown — checked every render, as Drawer, CornerPanel and AsidePanel do (the visual pass of\n // 23 September): the close settle runs once at load and sets `mounted` false while it already is; React keeps that\n // update and replays it after the first open, so a sheet mounted only on the change of `open` vanished on the first\n // open after every page load.\n if (open && !mounted) setMounted(true);\n if (open && hidden) setHidden(false);\n\n // Snap fractions are relative to the viewport, or to the container when one is given.\n const viewportHeight = useCallback(\n () => (container instanceof HTMLElement ? container.clientHeight : window.innerHeight),\n [container],\n );\n\n // After the close transition settles (at once under reduced motion): unmount, or hide when keepMounted.\n useCloseSettle(open, panelRef, () => {\n if (keepMounted) setHidden(true);\n else setMounted(false);\n });\n\n useReturnFocus(open, panelRef);\n\n useEffect(() => {\n if (!open || !mounted) return;\n const raf = requestAnimationFrame(() => focusInitial(panelRef.current));\n return () => cancelAnimationFrame(raf);\n }, [open, mounted]);\n\n const isTopLayer = useOverlayLayer(open);\n useFocusTrap(panelRef, open, isTopLayer);\n\n useEffect(() => {\n if (!open) return;\n // An Escape a control inside already handled (a list closing) is its own.\n const onKeyDown = (e: KeyboardEvent) => {\n if (e.key !== \"Escape\" || e.defaultPrevented || !isTopLayer()) return;\n e.preventDefault();\n onCloseRef.current();\n };\n document.addEventListener(\"keydown\", onKeyDown);\n if (!container) lockBodyScroll();\n return () => {\n document.removeEventListener(\"keydown\", onKeyDown);\n if (!container) unlockBodyScroll();\n };\n }, [open, container, onCloseRef, isTopLayer]);\n\n const handlePointerDown = useCallback((e: React.PointerEvent) => {\n setDragging(true);\n dragStartY.current = e.clientY;\n startHeight.current = (snapPoints[snapIdx] ?? snapPoints[0]) * viewportHeight();\n setDragOffset(0);\n (e.target as HTMLElement).setPointerCapture(e.pointerId);\n }, [snapIdx, snapPoints, viewportHeight]);\n\n const handlePointerMove = useCallback((e: React.PointerEvent) => {\n if (!dragging) return;\n const delta = dragStartY.current - e.clientY;\n setDragOffset(delta);\n }, [dragging]);\n\n const handlePointerUp = useCallback(() => {\n if (!dragging) return;\n setDragging(false);\n const currentHeightPx = startHeight.current + dragOffset;\n const currentFraction = currentHeightPx / viewportHeight();\n\n if (currentFraction < snapPoints[0] * 0.6) {\n onClose();\n setDragOffset(0);\n return;\n }\n\n let bestIdx = 0;\n let bestDist = Math.abs(currentFraction - snapPoints[0]);\n for (let i = 1; i < snapPoints.length; i++) {\n const dist = Math.abs(currentFraction - snapPoints[i]);\n if (dist < bestDist) { bestDist = dist; bestIdx = i; }\n }\n setSnapIdx(bestIdx);\n setDragOffset(0);\n }, [dragging, dragOffset, snapPoints, onClose, viewportHeight]);\n\n if (!mounted) return null;\n\n const baseHeight = (snapPoints[snapIdx] ?? snapPoints[0]) * 100;\n const heightUnit = container ? \"%\" : \"vh\";\n const dragPx = dragging ? dragOffset : 0;\n const positionClass = container ? \"absolute\" : \"fixed\";\n\n return createPortal(\n <div\n hidden={keepMounted && hidden ? true : undefined}\n className={cn(\n `${positionClass} inset-0 z-[var(--ds-z-modal)] transition-opacity duration-[var(--ds-transition-speed)]`,\n open ? \"pointer-events-auto\" : \"pointer-events-none\",\n )}\n >\n <div\n className={cn(\n \"absolute inset-0 bg-black/50 transition-opacity duration-[var(--ds-transition-speed)]\",\n open ? \"opacity-100\" : \"opacity-0\",\n )}\n onClick={onClose}\n />\n <div\n ref={panelRef}\n id={id}\n role=\"dialog\"\n data-gs=\"sheet\"\n aria-modal=\"true\"\n aria-labelledby={title ? titleId : labelledBy}\n data-ds-sheet=\"\"\n className={cn(\n `${positionClass} bottom-0 left-0 right-0 z-10 flex flex-col`,\n OVERLAY_SURFACE, \"text-[var(--ds-text-primary)]\",\n GLASS_OVERLAY,\n \"border-t-[length:var(--ds-border-width)] border-[var(--ds-border-default)]\",\n \"rounded-t-[var(--ds-radius-xl)]\",\n !dragging && \"transition-[transform,height] duration-[var(--ds-transition-speed)] ease-[var(--ds-transition-ease)]\",\n open ? \"translate-y-0\" : \"translate-y-full\",\n )}\n style={{\n containerType: \"inline-size\",\n height: dragPx ? `calc(${baseHeight}${heightUnit} + ${dragPx}px)` : `${baseHeight}${heightUnit}`,\n }}\n >\n <div\n className=\"flex justify-center pt-ds-2 pb-ds-1 cursor-grab active:cursor-grabbing touch-none\"\n onPointerDown={handlePointerDown}\n onPointerMove={handlePointerMove}\n onPointerUp={handlePointerUp}\n onPointerCancel={handlePointerUp}\n >\n <div className=\"w-10 h-1 rounded-[var(--ds-radius-full)] bg-[var(--ds-border-default)]\" />\n </div>\n\n {title && (\n <div\n className=\"flex items-center justify-between shrink-0 border-b-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]\"\n style={{ padding: \"var(--ds-space-2) var(--ds-space-5)\" }}\n >\n <h2 id={titleId} className=\"font-[family-name:var(--ds-font-display)] text-lg font-[var(--ds-weight-heading)] text-[var(--ds-text-primary)] truncate\">{title}</h2>\n <button\n onClick={onClose}\n {...{ [OVERLAY_CLOSE_ATTR]: \"\" }}\n className=\"text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] transition-colors cursor-pointer\"\n aria-label=\"Close\"\n >\n <Icon name=\"close\" size={18} />\n </button>\n </div>\n )}\n\n <div\n className=\"flex-1 overflow-y-auto\"\n style={flush ? undefined : { padding: \"var(--ds-space-5)\" }}\n >\n {/* a form inside closes through the question too — only when this sheet guards itself; a Drawer's phone sheet\n keeps the Drawer's own guarded close above it */}\n {dirty !== undefined ? <OverlayCloseCtx value={guard.requestClose}>{children}</OverlayCloseCtx> : children}\n </div>\n\n {confirm}\n {dirty !== undefined && <DiscardConfirm open={guard.confirming} onKeep={guard.keep} onDiscard={guard.discard} />}\n\n {footer && (\n <div\n className=\"shrink-0 flex items-center justify-end gap-ds-2 border-t-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]\"\n style={{ padding: \"var(--ds-space-3) var(--ds-space-5)\" }}\n >\n {footer}\n </div>\n )}\n </div>\n </div>,\n container ?? document.body,\n );\n}\n","import { useCallback, useEffect, useRef, useState } from \"react\";\nimport { cn } from \"./utils\";\nimport { useLatest } from \"./use-latest\";\n\n/**\n * A drag-to-resize edge shared by the docked AsidePanel and the non-modal\n * Drawer. Visually it is the panel's page-side edge: hover shows the resize\n * cursor and the line thickens in the accent colour; it stays lit while\n * dragging. Nothing else appears for mouse users.\n *\n * Keyboard, invisibly: the same edge is a focusable separator (WAI-ARIA\n * window-splitter pattern). On focus it lights up as on hover; Left/Right\n * nudge the width by a step (Shift for a larger one), Home/End snap to the\n * bounds, Escape restores the width from before the interaction, and a\n * double-click (or Enter) snaps back to the default. This is what satisfies\n * WCAG 2.1.1 and 2.5.7 without a visible button.\n *\n * The width the user chose is remembered for the session (per `memoryKey`),\n * like the sidebar's collapsed state — never persisted.\n */\n\nexport interface ResizeEdgeProps {\n /** Which edge of the panel the handle sits on — the side facing the page. A right-docked panel's handle is on its \"left\" edge. */\n edge: \"left\" | \"right\";\n /** Current width in px. */\n width: number;\n /** Lower bound in px — the width the app configured. */\n min: number;\n /** Upper bound in px; a function so it can follow the viewport. */\n max: () => number;\n /** The width to snap back to. */\n defaultWidth: number;\n onResize: (width: number) => void;\n /** Accessible name, e.g. \"Resize assistant\". */\n label: string;\n /** Called when a pointer drag starts and ends — panels switch off their width animation while it runs so the edge follows the pointer exactly. */\n onDraggingChange?: (dragging: boolean) => void;\n className?: string;\n}\n\nconst STEP = 16;\nconst BIG_STEP = 64;\n\nfunction clamp(v: number, min: number, max: number) {\n return Math.min(Math.max(v, min), max);\n}\n\nexport function ResizeEdge({ edge, width, min, max, defaultWidth, onResize, label, onDraggingChange, className }: ResizeEdgeProps) {\n const [dragging, setDragging] = useState(false);\n const start = useRef<{ x: number; width: number } | null>(null);\n const latestOnResize = useLatest(onResize);\n\n // Dragging the handle away from the panel makes it wider: for a handle on the\n // panel's left edge that is a leftward drag (negative dx), on its right edge a rightward one.\n const direction = edge === \"left\" ? -1 : 1;\n\n const onPointerDown = useCallback(\n (e: React.PointerEvent<HTMLDivElement>) => {\n if (e.button !== 0) return;\n e.preventDefault();\n start.current = { x: e.clientX, width };\n setDragging(true);\n e.currentTarget.setPointerCapture(e.pointerId);\n },\n [width],\n );\n\n const onPointerMove = useCallback(\n (e: React.PointerEvent<HTMLDivElement>) => {\n if (!start.current) return;\n const next = clamp(start.current.width + direction * (e.clientX - start.current.x), min, max());\n latestOnResize.current(next);\n },\n [direction, min, max, latestOnResize],\n );\n\n const endDrag = useCallback(() => {\n start.current = null;\n setDragging(false);\n }, []);\n\n const latestOnDraggingChange = useLatest(onDraggingChange);\n useEffect(() => {\n latestOnDraggingChange.current?.(dragging);\n }, [dragging, latestOnDraggingChange]);\n\n // Escape during a drag reverts to the width before it (corpus: Escape cancels\n // any in-progress pointer interaction).\n useEffect(() => {\n if (!dragging) return;\n const onKey = (e: KeyboardEvent) => {\n if (e.key !== \"Escape\" || !start.current) return;\n latestOnResize.current(start.current.width);\n endDrag();\n };\n document.addEventListener(\"keydown\", onKey);\n return () => document.removeEventListener(\"keydown\", onKey);\n }, [dragging, endDrag, latestOnResize]);\n\n const onKeyDown = (e: React.KeyboardEvent<HTMLDivElement>) => {\n const step = e.shiftKey ? BIG_STEP : STEP;\n let next: number | null = null;\n // Left/Right move the edge itself; which way that widens depends on the edge.\n if (e.key === \"ArrowLeft\") next = width - direction * step;\n else if (e.key === \"ArrowRight\") next = width + direction * step;\n else if (e.key === \"Home\") next = min;\n else if (e.key === \"End\") next = max();\n else if (e.key === \"Enter\") next = defaultWidth;\n if (next === null) return;\n e.preventDefault();\n onResize(clamp(next, min, max()));\n };\n\n return (\n <div\n role=\"separator\"\n tabIndex={0}\n aria-orientation=\"vertical\"\n aria-label={label}\n aria-valuemin={min}\n aria-valuemax={max()}\n aria-valuenow={Math.round(width)}\n data-resize-edge={edge}\n data-dragging={dragging || undefined}\n onPointerDown={onPointerDown}\n onPointerMove={onPointerMove}\n onPointerUp={endDrag}\n onPointerCancel={endDrag}\n onDoubleClick={() => onResize(clamp(defaultWidth, min, max()))}\n onKeyDown={onKeyDown}\n className={cn(\n // A narrow absolutely-positioned strip over the edge — never a flex child that takes width.\n \"group/edge absolute top-0 bottom-0 z-10 w-ds-2 cursor-col-resize touch-none select-none outline-none\",\n edge === \"left\" ? \"-left-ds-1\" : \"-right-ds-1\",\n className,\n )}\n >\n {/* The visible line: the panel's own border at rest, thicker and accent on hover / focus / drag. */}\n <div\n aria-hidden=\"true\"\n className={cn(\n \"absolute top-0 bottom-0 left-1/2 w-px -translate-x-1/2 transition-[width,background-color] duration-[var(--ds-transition-speed)]\",\n \"group-hover/edge:w-[3px] group-hover/edge:bg-[var(--ds-accent-primary)]\",\n \"group-focus-visible/edge:w-[3px] group-focus-visible/edge:bg-[var(--ds-accent-primary)]\",\n dragging && \"w-[3px] bg-[var(--ds-accent-primary)]\",\n )}\n />\n </div>\n );\n}\n\n// ─── Session memory for chosen widths ────────────────────────────────────────\n\nconst remembered = new Map<string, number>();\n\n/**\n * The width a user dragged a panel to, kept for the session under `key`.\n * Returns [width | null, remember].\n */\nexport function useRememberedWidth(key: string | undefined): [number | null, (w: number | null) => void] {\n const [width, setWidth] = useState<number | null>(() => (key ? remembered.get(key) ?? null : null));\n const remember = useCallback(\n (w: number | null) => {\n setWidth(w);\n if (!key) return;\n if (w === null) remembered.delete(key);\n else remembered.set(key, w);\n },\n [key],\n );\n return [width, remember];\n}\n\n/** Test seam. */\nexport function clearRememberedWidths() {\n remembered.clear();\n}\n\n/** Parse a px length; anything else (a token, a percentage) reads as null and the panel measures itself instead. */\nexport function pxOf(length: string | undefined): number | null {\n if (!length) return null;\n const m = /^(\\d+(?:\\.\\d+)?)px$/.exec(length.trim());\n return m ? parseFloat(m[1]) : null;\n}\n\n/** Default upper bound: sixty percent of the viewport (or of the container). */\nexport function defaultMaxWidth(container?: Element | null): number {\n const base = container instanceof HTMLElement ? container.clientWidth : typeof window !== \"undefined\" ? window.innerWidth : 1200;\n return Math.round(base * 0.6);\n}\n","import { useEffect, useRef, useState, useId, useCallback, useMemo, createContext, type ReactNode } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { cn, OVERLAY_SURFACE, GLASS_OVERLAY, lockBodyScroll, unlockBodyScroll } from \"../lib/utils\";\nimport { Icon } from \"../lib/icons\";\nimport { focusInitial, useReturnFocus, useFocusTrap, useOverlayLayer, useNonModalDialog, OVERLAY_CLOSE_ATTR } from \"../lib/focus\";\nimport { useCloseSettle } from \"../lib/use-close-settle\";\nimport { ResizeEdge, useRememberedWidth, pxOf, defaultMaxWidth } from \"../lib/edge-resize\";\nimport { Tooltip } from \"./Tooltip\";\nimport { useTextOverflow } from \"../lib/use-text-overflow\";\nimport { useBreakpoint } from \"../lib/use-breakpoint\";\nimport { useDirtyGuard, DiscardConfirm, OverlayCloseCtx } from \"./DiscardConfirm\";\nimport { Sheet } from \"./Sheet\";\nimport { useLatest } from \"../lib/use-latest\";\n\n// ---------------------------------------------------------------------------\n// DrawerFooterContext — FormWrapper registers its actions here so the overlay\n// renders them in its footer area (outside the form's DOM tree, linked by the\n// HTML form attribute). An explicit `footer` prop on Drawer/Sheet wins.\n// ---------------------------------------------------------------------------\n\nexport interface DrawerFooterContextValue {\n registerActions: (id: string, actions: ReactNode) => void;\n unregisterActions: (id: string) => void;\n}\n\nexport const DrawerFooterCtx = createContext<DrawerFooterContextValue | null>(null);\n\ninterface DrawerProps {\n open: boolean;\n onClose: () => void;\n position?: \"left\" | \"right\" | \"bottom\";\n width?: string;\n title?: ReactNode;\n children: ReactNode;\n footer?: ReactNode;\n container?: Element | DocumentFragment;\n /** Remove default content padding — use when the child (e.g. Sidebar) handles its own spacing. */\n flush?: boolean;\n /** Use a lighter backdrop (no blur, subtle dim). Use for compact overlays. */\n lightBackdrop?: boolean;\n /** Offset the drawer from the top of its container. When set, the area above this offset remains visible and interactive (e.g. keeping a navbar accessible). */\n topOffset?: string;\n /**\n * What the drawer becomes at phone width (≤ the sm breakpoint).\n * \"sheet\" (default for right and bottom): a draggable bottom Sheet with snap points.\n * \"panel\" (default for left, which is the navigation convention): a full-height side panel.\n * lightBackdrop and topOffset do not apply in sheet mode.\n */\n mobile?: \"sheet\" | \"panel\";\n /** Snap points for the phone-width Sheet, as fractions of the viewport. Default [0.5, 0.92]. */\n snapPoints?: number[];\n /**\n * Default true. false makes the drawer a persistent, non-modal panel the user works alongside\n * (an assistant, help): no backdrop, no scroll lock, no focus trap — the page stays operable.\n * It closes only on Escape while focus is inside it, its close control, or onClose from the\n * consumer; an outside click does nothing. At phone width the Sheet is always modal.\n */\n modal?: boolean;\n /**\n * Keep the panel in the DOM while closed (hidden and out of the tab order) so a half-typed\n * message, the scroll position and any in-progress rendering survive close and reopen.\n * Default false — the panel unmounts after its close transition, as it always has.\n */\n keepMounted?: boolean;\n /** id applied to the dialog element, for an opener's aria-controls. */\n id?: string;\n /** id of the element that names the dialog when no title is rendered — e.g. ChatPanel's heading. */\n labelledBy?: string;\n /**\n * Let the user drag the page-side edge to widen a non-modal side drawer,\n * between `width` and maxWidth (default 60% of the viewport). Default false —\n * ordinary drawers keep the one shared width. Ignored when modal or at phone width.\n */\n resizable?: boolean;\n maxWidth?: string;\n /** The content has unsaved changes: every close path asks before discarding, inside the drawer (Sprint 25.2, C1). */\n dirty?: boolean;\n /** Called when the user chooses to discard, before onClose. */\n onDiscard?: () => void;\n}\n\nconst slideClasses: Record<string, { panel: string; open: string; closed: string }> = {\n right: {\n panel: \"top-0 right-0 h-full\",\n open: \"translate-x-0\",\n closed: \"translate-x-full\",\n },\n left: {\n panel: \"top-0 left-0 h-full\",\n open: \"translate-x-0\",\n closed: \"-translate-x-full\",\n },\n bottom: {\n panel: \"bottom-0 left-0 right-0\",\n open: \"translate-y-0\",\n closed: \"translate-y-full\",\n },\n};\n\nconst borderByPosition: Record<string, string> = {\n right: \"border-l-[length:var(--ds-border-width)] border-l-[var(--ds-border-default)]\",\n left: \"border-r-[length:var(--ds-border-width)] border-r-[var(--ds-border-default)]\",\n bottom: \"border-t-[length:var(--ds-border-width)] border-t-[var(--ds-border-default)]\",\n};\n\nexport function Drawer(props: DrawerProps) {\n const { position = \"right\", mobile, snapPoints, open, onClose, title, children, footer, container, flush, keepMounted, id, labelledBy, dirty, onDiscard } = props;\n const isPhone = useBreakpoint(\"sm\");\n const mobileMode = mobile ?? (position === \"left\" ? \"panel\" : \"sheet\");\n const guard = useDirtyGuard(dirty, onClose, onDiscard);\n const confirm = <DiscardConfirm open={guard.confirming} onKeep={guard.keep} onDiscard={guard.discard} />;\n\n // Registered actions from FormWrapper children (C10).\n const [actionsMap, setActionsMap] = useState<Map<string, ReactNode>>(new Map());\n const registerActions = useCallback((formId: string, acts: ReactNode) => {\n setActionsMap((prev) => new Map(prev).set(formId, acts));\n }, []);\n const unregisterActions = useCallback((formId: string) => {\n setActionsMap((prev) => { const next = new Map(prev); next.delete(formId); return next; });\n }, []);\n const registeredActions = actionsMap.size > 0\n ? <>{Array.from(actionsMap.values())}</>\n : null;\n // An explicit footer wins; otherwise fall back to FormWrapper-registered actions.\n const effectiveFooter = footer ?? registeredActions;\n const footerCtx = useMemo<DrawerFooterContextValue>(\n () => ({ registerActions, unregisterActions }),\n [registerActions, unregisterActions]\n );\n\n if (isPhone && mobileMode === \"sheet\") {\n return (\n <DrawerFooterCtx value={footerCtx}>\n <OverlayCloseCtx value={guard.requestClose}>\n <Sheet open={open} onClose={guard.requestClose} title={title} footer={effectiveFooter} confirm={confirm} container={container} flush={flush} snapPoints={snapPoints} keepMounted={keepMounted} id={id} labelledBy={labelledBy}>\n {children}\n </Sheet>\n </OverlayCloseCtx>\n </DrawerFooterCtx>\n );\n }\n return (\n <DrawerFooterCtx value={footerCtx}>\n <OverlayCloseCtx value={guard.requestClose}>\n <DrawerPanel {...props} footer={effectiveFooter} onClose={guard.requestClose} confirm={confirm} />\n </OverlayCloseCtx>\n </DrawerFooterCtx>\n );\n}\n\nfunction DrawerPanel({ open, onClose, position = \"right\", width = \"400px\", title, children, footer, container, flush, lightBackdrop, topOffset, modal = true, keepMounted = false, id, labelledBy, resizable = false, maxWidth, confirm }: DrawerProps & { confirm?: ReactNode }) {\n const nonModal = !modal;\n // Drag-to-resize (non-modal side drawers only): the configured width is the\n // minimum; the user's choice is remembered for the session.\n const [chosen, remember] = useRememberedWidth(id ?? labelledBy);\n const canResize = nonModal && resizable && position !== \"bottom\";\n const effectiveWidth = canResize && chosen !== null ? `${chosen}px` : width;\n const minPx = pxOf(width) ?? 320;\n const maxPx = () => pxOf(maxWidth) ?? defaultMaxWidth(container instanceof Element ? container : null);\n const titleId = useId();\n const { ref: titleOverflowRef, isTruncated: titleTruncated } = useTextOverflow({ lines: 1 });\n const isMobile = useBreakpoint(\"sm\");\n const panelRef = useRef<HTMLDivElement>(null);\n const [mounted, setMounted] = useState(open);\n // keepMounted: the panel stays in the DOM and this flips instead of `mounted`.\n const [hidden, setHidden] = useState(!open);\n const onCloseRef = useLatest(onClose);\n // Mount (or unhide) as soon as `open` flips — render-time state adjustments, so\n // the first painted frame already has the panel.\n if (open && !mounted) setMounted(true);\n if (open && hidden) setHidden(false);\n\n const isTopLayer = useOverlayLayer(open);\n\n // ── Modal mechanics (the default) ──\n useEffect(() => {\n if (!open || nonModal) return;\n\n // An Escape a control inside already handled (a list closing) is its own.\n const onKeyDown = (e: KeyboardEvent) => {\n if (e.key !== \"Escape\" || e.defaultPrevented || !isTopLayer()) return;\n e.preventDefault();\n onCloseRef.current();\n };\n\n document.addEventListener(\"keydown\", onKeyDown);\n if (!container) lockBodyScroll();\n\n return () => {\n document.removeEventListener(\"keydown\", onKeyDown);\n if (!container) unlockBodyScroll();\n };\n }, [open, nonModal, container, onCloseRef, isTopLayer]);\n\n useReturnFocus(open && !nonModal, panelRef);\n // A drawer offset below a navbar leaves that navbar interactive by design,\n // so it is not modal and must not trap focus.\n useFocusTrap(panelRef, open && !topOffset && !nonModal, isTopLayer);\n\n // The panel only exists once `mounted` flips, so depend on it too — an\n // [open]-only effect ran before the panel rendered and focused nothing.\n useEffect(() => {\n if (!open || !mounted || nonModal) return;\n const raf = requestAnimationFrame(() => focusInitial(panelRef.current));\n return () => cancelAnimationFrame(raf);\n }, [open, mounted, nonModal]);\n\n // ── Non-modal mechanics ──\n useNonModalDialog(panelRef, open && mounted && nonModal, onClose, isTopLayer);\n\n // After the close transition settles (at once under reduced motion): unmount,\n // or just hide when the consumer wants the panel's state preserved.\n useCloseSettle(open, panelRef, () => {\n if (keepMounted) setHidden(true);\n else setMounted(false);\n });\n\n if (!mounted) return null;\n\n const slide = slideClasses[position];\n const isHorizontal = position === \"left\" || position === \"right\";\n\n const positionClass = container ? \"absolute\" : \"fixed\";\n\n return createPortal(\n <div\n hidden={keepMounted && hidden ? true : undefined}\n className={cn(\n `${positionClass} transition-opacity duration-[var(--ds-transition-speed)]`,\n // A non-modal panel never intercepts the page: the wrapper is inert to the\n // pointer and only the panel itself accepts events.\n nonModal ? \"z-[var(--ds-z-overlay)] pointer-events-none\" : cn(\"z-[var(--ds-z-modal)]\", open ? \"pointer-events-auto\" : \"pointer-events-none\"),\n topOffset ? \"left-0 right-0 bottom-0\" : \"inset-0\",\n )}\n style={topOffset ? { top: topOffset } : undefined}\n >\n {/* Backdrop — modal only */}\n {!nonModal && (\n <div\n className={cn(\n \"absolute inset-0 transition-opacity duration-[var(--ds-transition-speed)]\",\n lightBackdrop\n ? \"bg-black/15\"\n : cn(\"bg-black/50\", \"[backdrop-filter:blur(calc(var(--ds-glass-blur)*0.3))] [-webkit-backdrop-filter:blur(calc(var(--ds-glass-blur)*0.3))]\"),\n open ? \"opacity-100\" : \"opacity-0\"\n )}\n onClick={onClose}\n />\n )}\n\n {/* Panel */}\n <div\n ref={panelRef}\n id={id}\n role=\"dialog\"\n data-gs=\"drawer\"\n aria-modal={nonModal ? undefined : \"true\"}\n aria-labelledby={title ? titleId : labelledBy}\n style={{\n containerType: \"inline-size\",\n width: isHorizontal ? effectiveWidth : undefined,\n maxWidth: isHorizontal ? \"100%\" : undefined,\n height: isMobile ? \"100%\" : undefined,\n maxHeight: !isMobile && !isHorizontal ? \"80vh\" : undefined,\n }}\n className={cn(\n `${positionClass} z-10 flex flex-col`,\n nonModal && \"pointer-events-auto\",\n OVERLAY_SURFACE, \"text-[var(--ds-text-primary)]\",\n GLASS_OVERLAY,\n // flush drops the edge border for children that draw their own (the mobile\n // menu's Sidebar); a non-modal panel has no backdrop to separate it from\n // the page, so it always keeps the border.\n (!flush || nonModal) && borderByPosition[position],\n \"transition-transform duration-[var(--ds-transition-speed)] ease-[var(--ds-transition-ease)]\",\n isHorizontal && position === \"left\" && \"rounded-r-[var(--ds-radius-lg)] overflow-hidden\",\n isHorizontal && position === \"right\" && \"rounded-l-[var(--ds-radius-lg)] overflow-hidden\",\n !isHorizontal && \"rounded-t-[var(--ds-radius-lg)] overflow-hidden\",\n (lightBackdrop || nonModal) && \"shadow-[var(--ds-shadow-overlay)]\",\n slide.panel,\n open ? slide.open : slide.closed\n )}\n >\n {canResize && open && (\n <ResizeEdge\n edge={position === \"right\" ? \"left\" : \"right\"}\n width={chosen ?? minPx}\n min={minPx}\n max={maxPx}\n defaultWidth={minPx}\n onResize={(w) => remember(w === minPx ? null : w)}\n label=\"Resize panel\"\n />\n )}\n\n {/* Header */}\n {title && (\n <div\n className=\"flex items-center justify-between shrink-0 border-b-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]\"\n style={{\n padding: \"var(--ds-space-3) var(--ds-space-6)\",\n minHeight: \"calc(var(--ds-space-unit) * 6 + 1.75rem + 2px + var(--ds-border-width))\",\n }}\n >\n {titleTruncated ? (\n <Tooltip content={title}>\n <h2 ref={titleOverflowRef} id={titleId} className=\"font-[family-name:var(--ds-font-display)] text-lg font-[var(--ds-weight-heading)] text-[var(--ds-text-primary)] truncate\">{title}</h2>\n </Tooltip>\n ) : (\n <h2 ref={titleOverflowRef} id={titleId} className=\"font-[family-name:var(--ds-font-display)] text-lg font-[var(--ds-weight-heading)] text-[var(--ds-text-primary)] truncate\">{title}</h2>\n )}\n <button\n onClick={onClose}\n {...{ [OVERLAY_CLOSE_ATTR]: \"\" }}\n className=\"text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] transition-colors cursor-pointer\"\n aria-label=\"Close\"\n >\n <Icon name=\"close\" size={18} />\n </button>\n </div>\n )}\n\n {/* Content */}\n <div\n className=\"flex-1 overflow-y-auto\"\n style={flush ? undefined : { padding: \"var(--ds-space-5)\" }}\n >\n {children}\n </div>\n\n {confirm}\n\n {/* Footer */}\n {footer && (\n <div\n className=\"shrink-0 flex items-center justify-end gap-ds-2 border-t-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]\"\n style={{ padding: \"var(--ds-space-3) var(--ds-space-5)\" }}\n >\n {footer}\n </div>\n )}\n </div>\n </div>,\n container ?? document.body,\n );\n}\n","import { cn } from \"../lib/utils\";\n\ninterface SkipLinkProps {\n /** The id of the main region (AppShell names its <main> \"main\"). */\n href?: string;\n children?: string;\n className?: string;\n}\n\n/**\n * The first focusable element on a page with repeated navigation: invisible\n * until it receives keyboard focus, then a small floating button that jumps\n * past the sidebar and navbar to the main content (WCAG 2.4.1). AppShell\n * renders one by default; a page outside AppShell composes it first.\n */\nexport function SkipLink({ href = \"#main\", children = \"Skip to content\", className }: SkipLinkProps) {\n return (\n <a\n href={href}\n className={cn(\n \"sr-only focus:not-sr-only focus:fixed focus:top-[var(--ds-space-2)] focus:left-[var(--ds-space-2)] focus:z-[var(--ds-z-tooltip)]\",\n \"focus:px-[var(--ds-space-3)] focus:py-[var(--ds-space-2)] focus:rounded-[var(--ds-radius-md)] focus:text-sm focus:font-medium\",\n \"focus:bg-[var(--ds-bg-surface-elevated)] focus:text-[var(--ds-text-primary)] focus:shadow-[var(--ds-shadow-md)]\",\n \"focus:outline-none focus:ring-2 focus:ring-[var(--ds-accent-primary)]\",\n className\n )}\n >\n {children}\n </a>\n );\n}\n","import { version } from \"react\";\n\n/**\n * gridsmith-ui needs React 19: its components render React 19's context providers and take `ref` as a prop, so on\n * React 18 the shell crashes with React's own \"render is not a function\". The words a React 18 app gets instead, so\n * the fix is named (Sprint 25.7, the owner's call of 26 September 2026: the package says React 19 only). An\n * experimental build (0.0.0-…) is taken as current.\n */\nexport function reactVersionProblem(v: string = version): string | null {\n if (v.startsWith(\"0.0.0\")) return null;\n const major = Number.parseInt(v, 10);\n return Number.isFinite(major) && major < 19\n ? `gridsmith-ui needs React 19, and this app has React ${v}. Upgrade react, react-dom, @types/react and @types/react-dom to 19, then reinstall; an install forced with --force or --legacy-peer-deps cannot run.`\n : null;\n}\n\n/** Evaluated once: the shell and the page container throw it before rendering anything React 18 cannot. */\nexport const REACT_VERSION_PROBLEM = reactVersionProblem();\n","import { isValidElement, useState, useCallback, useEffect, useRef, forwardRef, createContext, useContext, type ReactNode } from \"react\";\nimport { REACT_VERSION_PROBLEM } from \"../lib/react-version\";\nimport type { AppShellTheme, ChromePosition } from \"../lib/shell-theme\";\nimport { PreferencesContext, type AppShellPreferences } from \"../lib/preferences\";\nimport { SkipLink } from \"./SkipLink\";\nimport { cn } from \"../lib/utils\";\nimport { useBreakpoint } from \"../lib/use-breakpoint\";\nimport { Drawer } from \"./Drawer\";\n\nexport interface AppShellContextValue {\n hasSidebar: boolean;\n hasMobileMenu: boolean;\n hasMobileNav: boolean;\n sidebarOpen: boolean;\n setSidebarOpen: (open: boolean) => void;\n isMobile: boolean;\n /** True only for tablet-sized viewports (between sm and md breakpoints). Drawer shows here, not on small mobile. */\n isTablet: boolean;\n /**\n * Effective sidebar collapse for a traditional Sidebar rendered in the shell.\n * The user's explicit choice wins; otherwise the auto tier applies — collapsed\n * to a rail at or below the `lg` breakpoint, expanded above it. Lives here rather\n * than in Sidebar so it survives the sidebar unmounting in the drawer range.\n */\n sidebarCollapsed: boolean;\n /** Records an explicit user choice. Overrides the auto tier in both directions for the session. */\n setSidebarCollapsed: (collapsed: boolean) => void;\n /** True while a docked AsidePanel in the aside slot is open beside the content. Pages may hide non-essential chrome on it. */\n asideOpen: boolean;\n /** Set by AsidePanel; not for pages to call. */\n setAsideOpen: (open: boolean) => void;\n /** Which side the aside slot is on (AppShell's asideSide). */\n asideSide: \"right\" | \"left\";\n /** True while the docked AsidePanel is floating — a floating PageHeader drops its gutter on that side, as it does beside a floating Sidebar. */\n asideFloating: boolean;\n /** Set by AsidePanel; not for pages to call. */\n setAsideFloating: (floating: boolean) => void;\n /**\n * The shell's root element, for previews that need to render overlays inside their frame\n * (the dashboard builder passes it to Launcher, CornerPanel and Drawer as `container`).\n * Components never read it themselves: a container moves the toast-inset claim onto that\n * element, where a body-level ToastProvider cannot see it.\n */\n container: HTMLElement | null;\n /** The theme's shell-level decisions (Sprint 25). PageHeader and PageContainer resolve their defaults from it. */\n theme: AppShellTheme | null;\n /** The current route is the home page (`currentPath === homePath`); decides `colourfulHomeOnly`. */\n isHome: boolean;\n /** The rendered Navbar floats (registered by the Navbar; the theme's `navbarPosition` until it has). */\n navbarFloating: boolean;\n /** The rendered Sidebar floats, and is a sidebar rather than a drawer: false below md and in stacked layouts. */\n sidebarFloating: boolean;\n /** Called by Sidebar and Navbar so the shell knows the chrome that is actually rendered. Returns the unregister. */\n registerChrome: (kind: \"navbar\" | \"sidebar\", position: ChromePosition) => () => void;\n /** True when the shell renders a Launcher above sm — PageContainer adjusts its bottom padding to clear the launcher. */\n hasLauncher: boolean;\n /** The bottom corner that launcher occupies (a ribbon occupies none), so the container reads that corner's inset variable. */\n launcherCorner: \"bottom-right\" | \"bottom-left\" | null;\n /** The shell renders an app footer under the page. Its children sit in a wrapper whose height is not definite, so a\n * `fill` SplitView reads `--ds-main-height` (published on the shell element) instead of `h-full`. */\n hasFooter: boolean;\n /** The flow this shell is in focus mode for (Sprint 25.7, C1), or null. The Navbar and PageHeader read it. */\n focus: AppShellFocus | null;\n /** A page inside the shell has unsaved changes (useUnsavedChanges): focus mode's Exit asks before it leaves. */\n hasUnsavedChanges: boolean;\n /** Set by useUnsavedChanges; not for pages to call. Returns the release. */\n addUnsavedChanges: () => () => void;\n}\n\n/**\n * Focus mode (Sprint 25.7, C1): a task flow the user completes before or outside the app — setup, onboarding,\n * checkout, an import — renders in the same shell with the navigation taken away. The header keeps the logo and the\n * assistant, and its one way out is the exit control.\n */\nexport interface AppShellFocus {\n /**\n * `before-app`: a flow before the app (setup, onboarding). The exit control, \"Save and log out\", takes the user\n * menu's place. `in-app`: a flow inside the app (checkout, an import). \"Exit\" goes back to where the user came from,\n * asks first while the page has unsaved changes, and the user menu stays.\n */\n kind: \"before-app\" | \"in-app\";\n /** The exit control's label. Default \"Save and log out\" before the app, \"Exit\" inside it. */\n exitLabel?: string;\n /** What the exit control does: save and log out, or return to where the user came from. */\n onExit?: () => void;\n}\n\nconst AppShellContext = createContext<AppShellContextValue | null>(null);\n\nexport function useAppShell() {\n return useContext(AppShellContext);\n}\n\n/**\n * Tells the shell this page has unsaved changes, so focus mode's Exit asks before it leaves (Sprint 25.7, C1). Pass the\n * same `dirty` a Drawer takes; outside a shell it does nothing.\n */\nexport function useUnsavedChanges(dirty: boolean) {\n const add = useContext(AppShellContext)?.addUnsavedChanges;\n useEffect(() => {\n if (!dirty || !add) return;\n return add();\n }, [dirty, add]);\n}\n\ntype AppShellLayout = \"sidebar\" | \"stacked\" | \"sidebar-header\" | \"multi-column\";\n\ninterface AppShellProps {\n layout?: AppShellLayout;\n sidebar?: ReactNode;\n /** Content to render in the mobile drawer. For sidebar layouts, this is typically a Sidebar+SidebarNav. For header layouts, a MobileHeaderMenu. */\n mobileMenu?: ReactNode;\n /** Override drawer width for the mobile menu. Defaults to --ds-drawer-width. */\n mobileMenuWidth?: string;\n /** Use a lighter backdrop for the mobile menu drawer. */\n mobileMenuLightBackdrop?: boolean;\n /** Remove drawer padding and borders. Default true. Set false for compact overlays. */\n mobileMenuFlush?: boolean;\n navbar?: ReactNode;\n mobileNav?: ReactNode;\n /** Rendered below the page content inside the scrolling region and pinned to the bottom on short pages. Ignored when `scrollable` is false. */\n footer?: ReactNode;\n /** Render a SkipLink as the first focusable element (default true); it targets `mainId`. */\n skipLink?: boolean;\n /** The id of the <main> region the skip link jumps to. */\n mainId?: string;\n /** A docked AsidePanel rendered beside the content column: the page narrows to make room. Rendered at every width — the panel decides its own fallbacks. */\n aside?: ReactNode;\n /** Which side of the content the aside sits on. Default \"right\". Pass the same value to the AsidePanel. */\n asideSide?: \"right\" | \"left\";\n /**\n * A Launcher for the assistant. Rendered only above the sm breakpoint — a conditional render,\n * because the Launcher portals out of any wrapper — so on phones the Navbar button is the entry point\n * and it never collides with BottomNav.\n */\n launcher?: ReactNode;\n children: ReactNode;\n className?: string;\n /** When false, main area won't scroll — use for full-height layouts like ResizablePanelGroup. Default true. */\n scrollable?: boolean;\n /** The theme's shell-level decisions: what the generated shell passes once so pages carry nothing (Sprint 25). */\n theme?: AppShellTheme;\n /** The customer's UX preferences, passed once by the generated shell so pages and components carry nothing (Sprint 25.6). */\n preferences?: AppShellPreferences;\n /** The current route's path, so the shell knows which page is home. */\n currentPath?: string;\n /** The home page's path. Default \"/\". */\n homePath?: string;\n /**\n * Focus mode for a flow outside the navigation (setup, onboarding, checkout). The sidebar, mobile menu and bottom\n * nav are not rendered, and the Navbar drops its links and search; the logo, the assistant (its launcher and its\n * docked panel in the aside slot), the skip link, the theme, the preferences and the page spacing stay. The\n * generated layout passes it; a page never does.\n */\n focus?: AppShellFocus;\n}\n\nexport const AppShell = forwardRef<HTMLDivElement, AppShellProps>(function AppShell({\n layout = \"sidebar\",\n sidebar,\n mobileMenu,\n mobileMenuWidth,\n mobileMenuLightBackdrop,\n mobileMenuFlush = true,\n navbar,\n mobileNav,\n footer,\n skipLink = true,\n mainId = \"main\",\n aside,\n asideSide = \"right\",\n launcher,\n children,\n className,\n scrollable = true,\n theme,\n preferences,\n currentPath,\n homePath = \"/\",\n focus,\n}, ref) {\n // gridsmith-ui needs React 19: say so before rendering anything React 18 cannot (the package says React 19 only)\n if (REACT_VERSION_PROBLEM) throw new Error(REACT_VERSION_PROBLEM);\n const [sidebarOpen, setSidebarOpen] = useState(false);\n const [asideOpen, setAsideOpen] = useState(false);\n const [asideFloating, setAsideFloating] = useState(false);\n const isMobile = useBreakpoint(\"md\");\n const isSmallMobile = useBreakpoint(\"sm\");\n const isTablet = isMobile && !isSmallMobile;\n // Sidebar tiers: expanded above lg, auto-rail between md and lg, drawer at or below md.\n // `userCollapsed` is null until the collapse button is used; from then on it wins.\n const autoCollapsed = useBreakpoint(\"lg\");\n const [userCollapsed, setUserCollapsed] = useState<boolean | null>(null);\n const sidebarCollapsed = userCollapsed ?? autoCollapsed;\n // Focus mode takes the navigation away: no sidebar, mobile menu or bottom nav, and the context says so. The aside\n // stays: in the generated shell it is the assistant's docked panel, and a flow keeps the assistant (D9).\n const inFocus = focus != null;\n const hasSidebar = !inFocus && (layout === \"sidebar\" || layout === \"sidebar-header\") && sidebar != null;\n const hasMobileMenu = !inFocus && mobileMenu != null;\n const hasMobileNav = !inFocus && mobileNav != null;\n const [unsavedCount, setUnsavedCount] = useState(0);\n const addUnsavedChanges = useCallback(() => {\n setUnsavedCount((n) => n + 1);\n let released = false;\n return () => { if (released) return; released = true; setUnsavedCount((n) => n - 1); };\n }, []);\n const showMobileDrawer = hasMobileMenu && !(isSmallMobile && hasMobileNav);\n const [shellEl, setShellEl] = useState<HTMLDivElement | null>(null);\n // The chrome that is actually rendered, reported by Sidebar and Navbar; the theme's positions until they report.\n const [chrome, setChrome] = useState<{ navbar?: ChromePosition; sidebar?: ChromePosition }>({});\n const registerChrome = useCallback((kind: \"navbar\" | \"sidebar\", position: ChromePosition) => {\n setChrome((c) => (c[kind] === position ? c : { ...c, [kind]: position }));\n return () => setChrome((c) => { if (!(kind in c)) return c; const next = { ...c }; delete next[kind]; return next; });\n }, []);\n const navbarFloating = (chrome.navbar ?? theme?.navbarPosition) === \"floating\";\n const sidebarFloating = hasSidebar && !isMobile && (chrome.sidebar ?? theme?.sidebarPosition) === \"floating\";\n const isHome = currentPath != null && currentPath === homePath;\n // With a footer the children wrapper is `min-h-full`, which gives a child no definite height to fill (C6): main's\n // height is published as --ds-main-height on the shell element for the fill SplitView. Written straight to the\n // element from a ResizeObserver; nothing re-renders.\n const hasFooter = footer != null && scrollable;\n const mainRef = useRef<HTMLElement | null>(null);\n useEffect(() => {\n const main = mainRef.current;\n if (!hasFooter || !shellEl || !main || typeof ResizeObserver === \"undefined\") { shellEl?.style.removeProperty(\"--ds-main-height\"); return; }\n const ro = new ResizeObserver(() => shellEl.style.setProperty(\"--ds-main-height\", `${main.clientHeight}px`));\n ro.observe(main);\n return () => { ro.disconnect(); shellEl.style.removeProperty(\"--ds-main-height\"); };\n }, [hasFooter, shellEl]);\n\n // C7: the launcher element says which corner it takes (Launcher's `edge`; a ribbon claims no corner).\n const hasLauncher = !!launcher && !isSmallMobile;\n const launcherProps = isValidElement(launcher) ? (launcher.props as { edge?: string; variant?: string }) : null;\n const launcherCorner: AppShellContextValue[\"launcherCorner\"] = !hasLauncher ? null\n : launcherProps?.variant === \"ribbon\" ? null\n : launcherProps?.edge === \"bottom-left\" ? \"bottom-left\"\n : launcherProps?.edge === \"right\" || launcherProps?.edge === \"left\" || launcherProps?.edge === \"bottom\" ? null\n : \"bottom-right\";\n\n return (\n <PreferencesContext value={preferences ?? null}>\n <AppShellContext\n value={{ hasSidebar, hasMobileMenu, hasMobileNav, sidebarOpen, setSidebarOpen, isMobile, isTablet, sidebarCollapsed, setSidebarCollapsed: setUserCollapsed, asideOpen, setAsideOpen, asideSide, asideFloating, setAsideFloating, container: shellEl, theme: theme ?? null, isHome, navbarFloating, sidebarFloating, registerChrome, hasLauncher, launcherCorner, hasFooter, focus: focus ?? null, hasUnsavedChanges: unsavedCount > 0, addUnsavedChanges }}\n >\n <div ref={(el) => {\n setShellEl(el);\n if (typeof ref === \"function\") ref(el);\n else if (ref) (ref as React.MutableRefObject<HTMLDivElement | null>).current = el;\n }} className={cn(\"relative h-screen flex flex-col bg-[var(--ds-bg-canvas)] overflow-hidden\", className)}>\n {skipLink && <SkipLink href={`#${mainId}`} />}\n {layout === \"sidebar-header\" && navbar}\n {layout === \"multi-column\" && navbar}\n\n <div className=\"flex flex-1 min-h-0\">\n {hasSidebar && !isMobile && (\n <div className=\"shrink-0 h-full\">\n {sidebar}\n </div>\n )}\n\n {/* A left-docked aside sits between the sidebar and the content. */}\n {aside && asideSide === \"left\" && aside}\n\n <div className=\"flex-1 flex flex-col min-w-0 min-h-0\">\n {layout === \"sidebar\" && navbar}\n {layout === \"stacked\" && navbar}\n\n <main\n ref={mainRef}\n id={mainId}\n tabIndex={-1} /* the skip link's target: focusable by script, never by Tab */\n className={cn(\n \"flex-1 min-h-0 focus:outline-none\",\n scrollable ? \"overflow-y-auto\" : \"relative\",\n layout === \"multi-column\" && \"flex\",\n )}\n style={{ containerType: \"inline-size\" }}\n >\n {scrollable ? (\n footer ? (\n <div className=\"min-h-full flex flex-col\">\n <div className=\"flex-1\">{children}</div>\n {footer}\n </div>\n ) : children\n ) : (\n <div className=\"absolute inset-0\">{children}</div>\n )}\n </main>\n </div>\n\n {/* The content column is flex-1 min-w-0, so it gives up width to the aside and <main>'s container query fires. */}\n {aside && asideSide === \"right\" && aside}\n </div>\n\n {showMobileDrawer && isMobile && (\n <Drawer\n open={sidebarOpen}\n onClose={() => setSidebarOpen(false)}\n position=\"left\"\n width={mobileMenuWidth ?? \"var(--ds-drawer-width)\"}\n container={shellEl ?? undefined}\n flush={mobileMenuFlush}\n lightBackdrop={mobileMenuLightBackdrop}\n topOffset={layout !== \"stacked\" && navbar != null ? \"var(--ds-navbar-height)\" : undefined}\n >\n {mobileMenu}\n </Drawer>\n )}\n\n {isSmallMobile && hasMobileNav && (\n <div className=\"sticky bottom-0 z-[var(--ds-z-sticky)]\">\n {mobileNav}\n </div>\n )}\n\n {/* Phone width: the Navbar button is the entry point; the launcher is not rendered at all. */}\n {!isSmallMobile && launcher}\n </div>\n </AppShellContext>\n </PreferencesContext>\n );\n});\n","import { useState, useCallback, useLayoutEffect, type RefObject } from \"react\";\nimport { readBreakpointPx, type BreakpointKey } from \"./use-breakpoint\";\n\n/**\n * True when the observed element is narrower than the breakpoint — a container\n * measurement, not the viewport, so a layout inside a sidebar shell or the\n * builder's canvas answers for the width it actually has. One implementation\n * for TableToolbar, SettingsLayout and the examples (Sprint 25.2).\n *\n * An unlaid-out element (tests, SSR) reports width 0 and is treated as not\n * compact; tests inject a width by overriding `offsetWidth`.\n */\nexport function useCompact(ref: RefObject<HTMLElement | null>, breakpoint: number | BreakpointKey, band = 0): boolean {\n const px = typeof breakpoint === \"number\" ? breakpoint : readBreakpointPx(breakpoint);\n const width = useElementWidth(ref);\n return useBelow(width, px, band);\n}\n\n/**\n * Whether a width is below a threshold, held across `band` px above it once it is (round 27 review): a layout whose\n * answer changes the width it measures — an aside that collapses removes a page scrollbar, which widens the layout\n * back over the threshold — otherwise flips on every frame at the edge (SplitView's aside toggled about 90 times in\n * 1.5 s with a 15 px scrollbar). The answer turns true below `threshold` and false again only at `threshold + band`.\n * A width of 0 (no layout yet) is never below.\n */\nexport function useBelow(width: number, threshold: number, band = 0): boolean {\n const [below, setBelow] = useState(false);\n const next = width > 0 && width < (below ? threshold + band : threshold);\n // render-time state adjustment: the answer is known now, so no frame paints the other one\n if (next !== below) setBelow(next);\n return next;\n}\n\n/** The element's laid-out width in px, kept current by a ResizeObserver; 0 until it has a layout (tests, SSR). */\nexport function useElementWidth(ref: RefObject<HTMLElement | null>): number {\n const [width, setWidth] = useState(0);\n const check = useCallback(() => {\n const next = ref.current?.offsetWidth ?? 0;\n if (next > 0) setWidth(next);\n }, [ref]);\n useLayoutEffect(() => {\n check();\n if (!ref.current || typeof ResizeObserver === \"undefined\") return;\n const observer = new ResizeObserver(check);\n observer.observe(ref.current);\n return () => observer.disconnect();\n }, [check, ref]);\n return width;\n}\n"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { Badge } from './chunk-
|
|
1
|
+
import { Badge } from './chunk-XYDIBW3J.js';
|
|
2
2
|
import { Icon } from './chunk-4LDYR7QP.js';
|
|
3
|
-
import { cn } from './chunk-
|
|
3
|
+
import { cn } from './chunk-M2QRNBDQ.js';
|
|
4
4
|
import { forwardRef, useState, useCallback } from 'react';
|
|
5
5
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
6
6
|
|
|
@@ -157,5 +157,5 @@ function Divider({
|
|
|
157
157
|
}
|
|
158
158
|
|
|
159
159
|
export { CodeBlock, Divider, Link };
|
|
160
|
-
//# sourceMappingURL=chunk-
|
|
161
|
-
//# sourceMappingURL=chunk-
|
|
160
|
+
//# sourceMappingURL=chunk-EQDR57AM.js.map
|
|
161
|
+
//# sourceMappingURL=chunk-EQDR57AM.js.map
|
|
@@ -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-XGSQOMEY.js","sourcesContent":["import { useState, useCallback } from \"react\";\nimport { cn } 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-visible:shadow-[var(--ds-shadow-focus)] outline-none\",\n )}\n aria-label={copied ? \"Copied\" : \"Copy code\"}\n >\n <Icon name={copied ? \"check\" : \"folder\"} 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 ComponentType, type ReactNode } from \"react\";\nimport { cn } from \"../lib/utils\";\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.\n */\n component?: ComponentType<Record<string, unknown>>;\n iconLeft?: ReactNode;\n iconRight?: ReactNode;\n}\n\nconst toneStyles: Record<LinkTone, string> = {\n accent: \"text-[var(--ds-accent-primary)] 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-primary)]\",\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-visible:outline-2 focus-visible:outline-[var(--ds-accent-primary)] focus-visible:outline-offset-2 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 {iconLeft}\n {children}\n {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-EQDR57AM.js","sourcesContent":["import { useState, useCallback } from \"react\";\nimport { cn } 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-visible:shadow-[var(--ds-shadow-focus)] outline-none\",\n )}\n aria-label={copied ? \"Copied\" : \"Copy code\"}\n >\n <Icon name={copied ? \"check\" : \"folder\"} 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 ComponentType, type ReactNode } from \"react\";\nimport { cn } from \"../lib/utils\";\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.\n */\n component?: ComponentType<Record<string, unknown>>;\n iconLeft?: ReactNode;\n iconRight?: ReactNode;\n}\n\nconst toneStyles: Record<LinkTone, string> = {\n accent: \"text-[var(--ds-accent-primary)] 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-primary)]\",\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-visible:outline-2 focus-visible:outline-[var(--ds-accent-primary)] focus-visible:outline-offset-2 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 {iconLeft}\n {children}\n {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,6 +1,6 @@
|
|
|
1
1
|
import { Slot, mergeRefs } from './chunk-7Q46JXSK.js';
|
|
2
2
|
import { useLatest } from './chunk-WH2FUFAC.js';
|
|
3
|
-
import { cn, GLASS_DROPDOWN } from './chunk-
|
|
3
|
+
import { cn, GLASS_DROPDOWN } from './chunk-M2QRNBDQ.js';
|
|
4
4
|
import { createContext, useState, useRef, useCallback, useLayoutEffect, useId, useEffect } from 'react';
|
|
5
5
|
import { createPortal } from 'react-dom';
|
|
6
6
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
@@ -289,5 +289,5 @@ function useTextOverflow(options = {}) {
|
|
|
289
289
|
}
|
|
290
290
|
|
|
291
291
|
export { Tooltip, TooltipCtx, usePosition, useTextOverflow };
|
|
292
|
-
//# sourceMappingURL=chunk-
|
|
293
|
-
//# sourceMappingURL=chunk-
|
|
292
|
+
//# sourceMappingURL=chunk-ILIODA7W.js.map
|
|
293
|
+
//# sourceMappingURL=chunk-ILIODA7W.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../showcase/src/lib/use-position.ts","../../../showcase/src/components/Tooltip.tsx","../../../showcase/src/lib/use-text-overflow.ts"],"names":["rafId","useState","useRef","useCallback","useEffect"],"mappings":"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","file":"chunk-EMCSARQO.js","sourcesContent":["import { useState, useCallback, useLayoutEffect, useRef, type RefObject } from \"react\";\n\nexport type Side = \"top\" | \"right\" | \"bottom\" | \"left\";\nexport type Align = \"start\" | \"center\" | \"end\";\n\ninterface PositionOptions {\n side?: Side;\n align?: Align;\n offset?: number;\n flip?: boolean;\n}\n\ninterface PositionResult {\n top: number;\n left: number;\n placement: Side;\n}\n\nconst VIEWPORT_PADDING = 8;\n\nexport function usePosition(\n triggerRef: RefObject<HTMLElement | null>,\n floatingRef: RefObject<HTMLElement | null>,\n open: boolean,\n options: PositionOptions = {}\n): PositionResult {\n const { side = \"bottom\", align = \"center\", offset = 8, flip = true } = options;\n const [pos, setPos] = useState<PositionResult>({ top: 0, left: 0, placement: side });\n const rafId = useRef(0);\n\n const compute = useCallback(() => {\n const trigger = triggerRef.current;\n const floating = floatingRef.current;\n if (!trigger || !floating) return;\n\n const tRect = trigger.getBoundingClientRect();\n const fRect = floating.getBoundingClientRect();\n const vw = window.innerWidth;\n const vh = window.innerHeight;\n\n let placement = side;\n\n if (flip) {\n if (placement === \"bottom\" && tRect.bottom + offset + fRect.height > vh - VIEWPORT_PADDING && tRect.top - offset - fRect.height > VIEWPORT_PADDING) {\n placement = \"top\";\n } else if (placement === \"top\" && tRect.top - offset - fRect.height < VIEWPORT_PADDING && tRect.bottom + offset + fRect.height < vh - VIEWPORT_PADDING) {\n placement = \"bottom\";\n } else if (placement === \"right\" && tRect.right + offset + fRect.width > vw - VIEWPORT_PADDING && tRect.left - offset - fRect.width > VIEWPORT_PADDING) {\n placement = \"left\";\n } else if (placement === \"left\" && tRect.left - offset - fRect.width < VIEWPORT_PADDING && tRect.right + offset + fRect.width < vw - VIEWPORT_PADDING) {\n placement = \"right\";\n }\n }\n\n let top: number;\n let left: number;\n\n if (placement === \"bottom\" || placement === \"top\") {\n top = placement === \"bottom\" ? tRect.bottom + offset : tRect.top - fRect.height - offset;\n\n switch (align) {\n case \"start\":\n left = tRect.left;\n break;\n case \"end\":\n left = tRect.right - fRect.width;\n break;\n default:\n left = tRect.left + (tRect.width - fRect.width) / 2;\n }\n } else {\n left = placement === \"right\" ? tRect.right + offset : tRect.left - fRect.width - offset;\n\n switch (align) {\n case \"start\":\n top = tRect.top;\n break;\n case \"end\":\n top = tRect.bottom - fRect.height;\n break;\n default:\n top = tRect.top + (tRect.height - fRect.height) / 2;\n }\n }\n\n left = Math.max(VIEWPORT_PADDING, Math.min(left, vw - fRect.width - VIEWPORT_PADDING));\n top = Math.max(VIEWPORT_PADDING, Math.min(top, vh - fRect.height - VIEWPORT_PADDING));\n\n setPos({ top, left, placement });\n }, [triggerRef, floatingRef, side, align, offset, flip]);\n\n useLayoutEffect(() => {\n if (!open) return;\n\n compute();\n\n const onUpdate = () => {\n cancelAnimationFrame(rafId.current);\n rafId.current = requestAnimationFrame(compute);\n };\n\n window.addEventListener(\"scroll\", onUpdate, true);\n window.addEventListener(\"resize\", onUpdate);\n\n return () => {\n cancelAnimationFrame(rafId.current);\n window.removeEventListener(\"scroll\", onUpdate, true);\n window.removeEventListener(\"resize\", onUpdate);\n };\n }, [open, compute]);\n\n return pos;\n}\n","import { useState, useRef, useCallback, useEffect, useId, type HTMLAttributes, type ReactNode, type Ref, createContext } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { cn, GLASS_DROPDOWN } from \"../lib/utils\";\nimport { Slot, mergeRefs } from \"../lib/slot\";\nimport { usePosition, type Side } from \"../lib/use-position\";\n\ninterface TooltipProps extends Omit<HTMLAttributes<HTMLElement>, \"content\"> {\n content: ReactNode;\n children: ReactNode;\n side?: Side;\n delay?: number;\n className?: string;\n container?: Element | DocumentFragment;\n /**\n * Keep the Tooltip in the tree but never show it. Use this instead of rendering\n * the Tooltip only sometimes: adding or removing the wrapper remounts its child,\n * which drops focus from a field inside it (Sprint 25.7, the Combobox).\n */\n disabled?: boolean;\n /**\n * A Tooltip can itself be the child of a Slot — `<DropdownMenu trigger={<Tooltip …><Button/></Tooltip>}>` —\n * so the ref and handlers a parent merges onto it are passed through to its own trigger (14 Sep 2026).\n */\n ref?: Ref<HTMLElement>;\n}\n\n// 600ms: long enough that passing the pointer over a toolbar, or landing focus\n// on an icon button, does not flash a label; short enough to still feel live.\n/** True inside an explicit <Tooltip>: an icon-size Button then skips the tooltip it would otherwise make from its aria-label (round 15, 52.7 — two tooltips on one button). */\nexport const TooltipCtx = createContext(false);\n\nexport function Tooltip({ content, children, side = \"top\", delay = 600, className, container, disabled = false, ref: forwardedRef, ...slotProps }: TooltipProps) {\n const [open, setOpen] = useState(false);\n // Disabling while shown hides it (render-time state adjustment).\n if (disabled && open) setOpen(false);\n const triggerRef = useRef<HTMLElement>(null);\n const floatingRef = useRef<HTMLDivElement>(null);\n const timeoutRef = useRef<ReturnType<typeof setTimeout>>(undefined);\n // Set when the trigger is activated: the label must not reappear (from the\n // focus the click leaves behind, or a still-pending timer) until the pointer\n // leaves and comes back.\n const suppressedRef = useRef(false);\n const id = useId();\n\n const pos = usePosition(triggerRef, floatingRef, open, { side, offset: 6, flip: true });\n\n const cancel = useCallback(() => {\n clearTimeout(timeoutRef.current);\n timeoutRef.current = undefined;\n }, []);\n\n // One pending timer at a time: hover and focus both call show(), and the\n // earlier timer used to be orphaned, firing after hide() had run and leaving\n // the tooltip up with nothing left to close it.\n const show = useCallback(() => {\n if (disabled || suppressedRef.current) return;\n cancel();\n timeoutRef.current = setTimeout(() => setOpen(true), delay);\n }, [delay, cancel, disabled]);\n\n const hide = useCallback(() => {\n cancel();\n setOpen(false);\n }, [cancel]);\n\n // Pointer focus (a click) does not warrant a label; keyboard focus does.\n const showOnFocus = useCallback((e: React.FocusEvent<HTMLElement>) => {\n let keyboard = true;\n try { keyboard = e.currentTarget.matches(\":focus-visible\"); } catch { /* selector unsupported: assume keyboard */ }\n if (keyboard) show();\n }, [show]);\n\n // Activating the trigger dismisses the label and keeps it away until the\n // pointer has left — what opens next (a menu, a dialog) owns the screen.\n const dismissOnActivate = useCallback(() => {\n suppressedRef.current = true;\n hide();\n }, [hide]);\n\n // Suppression lifts when the pointer leaves or focus moves on — a keyboard\n // user never produces a mouseleave, so blur must reset it too.\n const leave = useCallback(() => {\n suppressedRef.current = false;\n hide();\n }, [hide]);\n\n // Escape dismisses an open tooltip (WCAG 1.4.13); it does not stop the key\n // reaching whatever overlay is also listening.\n useEffect(() => {\n if (!open) return;\n const onKey = (e: KeyboardEvent) => { if (e.key === \"Escape\") hide(); };\n document.addEventListener(\"keydown\", onKey);\n return () => document.removeEventListener(\"keydown\", onKey);\n }, [open, hide]);\n\n useEffect(() => cancel, [cancel]);\n\n return (\n <TooltipCtx value={true}>\n <Slot\n {...slotProps}\n ref={mergeRefs(triggerRef, forwardedRef)}\n onMouseEnter={(e) => { slotProps.onMouseEnter?.(e); show(); }}\n onMouseLeave={(e) => { slotProps.onMouseLeave?.(e); leave(); }}\n onFocus={(e) => { slotProps.onFocus?.(e); showOnFocus(e); }}\n onBlur={(e) => { slotProps.onBlur?.(e); leave(); }}\n onPointerDown={(e) => { slotProps.onPointerDown?.(e); dismissOnActivate(); }}\n onKeyDown={(e) => { slotProps.onKeyDown?.(e); if (e.key === \"Enter\" || e.key === \" \") dismissOnActivate(); }}\n aria-describedby={open ? id : undefined}\n >\n {children}\n </Slot>\n {open && createPortal(\n <div\n ref={floatingRef}\n id={id}\n role=\"tooltip\"\n className={cn(\n \"fixed z-[var(--ds-z-tooltip)] pointer-events-none\",\n \"px-ds-2.5 py-ds-1.5 text-xs\",\n \"max-w-[280px] break-words\",\n \"bg-[var(--ds-bg-surface-elevated)] text-[var(--ds-text-primary)]\",\n GLASS_DROPDOWN,\n \"border-[length:var(--ds-border-width)] border-[var(--ds-border-default)]\",\n \"rounded-[var(--ds-radius-sm)]\",\n className\n )}\n style={{ top: pos.top, left: pos.left }}\n >\n {content}\n </div>,\n container ?? document.body\n )}\n </TooltipCtx>\n );\n}\n","import { useState, useCallback, useRef, useEffect } from \"react\";\nimport { useLatest } from \"./use-latest\";\n\n// ─── Shared ResizeObserver (singleton per document) ────────────────────────────\n// All useTextOverflow instances share a single ResizeObserver. This avoids the\n// performance cost of 80+ independent observers on pages with many truncated elements.\n\ntype OverflowCallback = () => void;\n\nconst registry = new WeakMap<Element, Set<OverflowCallback>>();\nlet sharedObserver: ResizeObserver | null = null;\nlet rafId: number | null = null;\nconst pendingElements = new Set<Element>();\n\nfunction getSharedObserver(): ResizeObserver {\n if (sharedObserver) return sharedObserver;\n sharedObserver = new ResizeObserver((entries) => {\n for (const entry of entries) {\n pendingElements.add(entry.target);\n }\n if (rafId === null) {\n rafId = requestAnimationFrame(flush);\n }\n });\n return sharedObserver;\n}\n\nfunction flush() {\n rafId = null;\n for (const el of pendingElements) {\n const callbacks = registry.get(el);\n if (callbacks) {\n for (const cb of callbacks) cb();\n }\n }\n pendingElements.clear();\n}\n\nfunction observe(el: Element, callback: OverflowCallback) {\n let set = registry.get(el);\n if (!set) {\n set = new Set();\n registry.set(el, set);\n }\n set.add(callback);\n if (set.size === 1) {\n getSharedObserver().observe(el);\n }\n}\n\nfunction unobserve(el: Element, callback: OverflowCallback) {\n const set = registry.get(el);\n if (!set) return;\n set.delete(callback);\n if (set.size === 0) {\n registry.delete(el);\n getSharedObserver().unobserve(el);\n }\n}\n\n// ─── Overflow detection ────────────────────────────────────────────────────────\n\nconst TOLERANCE = 1; // px — accounts for integer rounding in scrollWidth/clientWidth\n\nfunction checkOverflow(el: HTMLElement, lines: number): boolean {\n if (lines <= 1) {\n return el.scrollWidth - el.clientWidth > TOLERANCE;\n }\n return el.scrollHeight - el.clientHeight > TOLERANCE;\n}\n\n// ─── Hook ──────────────────────────────────────────────────────────────────────\n\nexport interface UseTextOverflowOptions {\n /** Number of visible lines before truncation. 1 = single-line ellipsis, >1 = line-clamp. */\n lines?: number;\n /** Disable overflow detection (e.g. when component is hidden) */\n disabled?: boolean;\n /** Content key — triggers re-check when this value changes (use for dynamic text content) */\n content?: unknown;\n}\n\nexport interface UseTextOverflowResult {\n /** Callback ref — attach to the element that has truncation CSS applied */\n ref: (node: HTMLElement | null) => void;\n /** True when the element's text is currently overflowing/truncated */\n isTruncated: boolean;\n}\n\n/**\n * Detects whether an element's text content is overflowing (truncated).\n * Uses a single shared ResizeObserver for all instances on the page.\n *\n * @example\n * const { ref, isTruncated } = useTextOverflow({ lines: 1 });\n * return (\n * <Tooltip content={fullText} disabled={!isTruncated}>\n * <span ref={ref} className=\"truncate\">{fullText}</span>\n * </Tooltip>\n * );\n */\nexport function useTextOverflow(options: UseTextOverflowOptions = {}): UseTextOverflowResult {\n const { lines = 1, disabled = false, content } = options;\n const [isTruncated, setIsTruncated] = useState(false);\n const elementRef = useRef<HTMLElement | null>(null);\n // The observer-registered wrapper delegates to the latest check logic via checkRef.\n const registeredRef = useRef<OverflowCallback | null>(null);\n\n const doCheck = useCallback(() => {\n if (!elementRef.current || disabled) {\n setIsTruncated(false);\n return;\n }\n const next = checkOverflow(elementRef.current, lines);\n setIsTruncated((prev) => (prev !== next ? next : prev));\n }, [lines, disabled]);\n\n // Latest check logic, updated in a layout effect so the stable wrapper never runs a stale closure.\n const checkRef = useLatest<OverflowCallback>(doCheck);\n\n // Re-check when content changes (handles dynamic text like Dropdown selection)\n // or when disabled state changes\n // Measures the committed DOM, so it must stay a post-layout effect.\n /* eslint-disable react-hooks/set-state-in-effect -- overflow is a layout measurement */\n useEffect(() => {\n if (disabled) {\n setIsTruncated(false);\n } else if (elementRef.current) {\n const next = checkOverflow(elementRef.current, lines);\n setIsTruncated((prev) => (prev !== next ? next : prev));\n }\n }, [content, lines, disabled]);\n /* eslint-enable react-hooks/set-state-in-effect */\n\n const ref = useCallback(\n (node: HTMLElement | null) => {\n const prev = elementRef.current;\n\n // Unregister previous element using the SAME function we registered with\n if (prev && registeredRef.current) {\n unobserve(prev, registeredRef.current);\n registeredRef.current = null;\n }\n\n elementRef.current = node;\n\n if (node && !disabled) {\n // Stable wrapper that delegates to the latest check logic\n const wrapper: OverflowCallback = () => checkRef.current?.();\n registeredRef.current = wrapper;\n observe(node, wrapper);\n // Initial check on mount\n const initial = checkOverflow(node, lines);\n setIsTruncated(initial);\n }\n },\n [lines, disabled, checkRef],\n );\n\n // Cleanup on unmount — uses the registered wrapper, not the check function\n useEffect(() => {\n return () => {\n if (elementRef.current && registeredRef.current) {\n unobserve(elementRef.current, registeredRef.current);\n }\n };\n }, []);\n\n return { ref, isTruncated };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../../showcase/src/lib/use-position.ts","../../../showcase/src/components/Tooltip.tsx","../../../showcase/src/lib/use-text-overflow.ts"],"names":["rafId","useState","useRef","useCallback","useEffect"],"mappings":"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","file":"chunk-ILIODA7W.js","sourcesContent":["import { useState, useCallback, useLayoutEffect, useRef, type RefObject } from \"react\";\n\nexport type Side = \"top\" | \"right\" | \"bottom\" | \"left\";\nexport type Align = \"start\" | \"center\" | \"end\";\n\ninterface PositionOptions {\n side?: Side;\n align?: Align;\n offset?: number;\n flip?: boolean;\n}\n\ninterface PositionResult {\n top: number;\n left: number;\n placement: Side;\n}\n\nconst VIEWPORT_PADDING = 8;\n\nexport function usePosition(\n triggerRef: RefObject<HTMLElement | null>,\n floatingRef: RefObject<HTMLElement | null>,\n open: boolean,\n options: PositionOptions = {}\n): PositionResult {\n const { side = \"bottom\", align = \"center\", offset = 8, flip = true } = options;\n const [pos, setPos] = useState<PositionResult>({ top: 0, left: 0, placement: side });\n const rafId = useRef(0);\n\n const compute = useCallback(() => {\n const trigger = triggerRef.current;\n const floating = floatingRef.current;\n if (!trigger || !floating) return;\n\n const tRect = trigger.getBoundingClientRect();\n const fRect = floating.getBoundingClientRect();\n const vw = window.innerWidth;\n const vh = window.innerHeight;\n\n let placement = side;\n\n if (flip) {\n if (placement === \"bottom\" && tRect.bottom + offset + fRect.height > vh - VIEWPORT_PADDING && tRect.top - offset - fRect.height > VIEWPORT_PADDING) {\n placement = \"top\";\n } else if (placement === \"top\" && tRect.top - offset - fRect.height < VIEWPORT_PADDING && tRect.bottom + offset + fRect.height < vh - VIEWPORT_PADDING) {\n placement = \"bottom\";\n } else if (placement === \"right\" && tRect.right + offset + fRect.width > vw - VIEWPORT_PADDING && tRect.left - offset - fRect.width > VIEWPORT_PADDING) {\n placement = \"left\";\n } else if (placement === \"left\" && tRect.left - offset - fRect.width < VIEWPORT_PADDING && tRect.right + offset + fRect.width < vw - VIEWPORT_PADDING) {\n placement = \"right\";\n }\n }\n\n let top: number;\n let left: number;\n\n if (placement === \"bottom\" || placement === \"top\") {\n top = placement === \"bottom\" ? tRect.bottom + offset : tRect.top - fRect.height - offset;\n\n switch (align) {\n case \"start\":\n left = tRect.left;\n break;\n case \"end\":\n left = tRect.right - fRect.width;\n break;\n default:\n left = tRect.left + (tRect.width - fRect.width) / 2;\n }\n } else {\n left = placement === \"right\" ? tRect.right + offset : tRect.left - fRect.width - offset;\n\n switch (align) {\n case \"start\":\n top = tRect.top;\n break;\n case \"end\":\n top = tRect.bottom - fRect.height;\n break;\n default:\n top = tRect.top + (tRect.height - fRect.height) / 2;\n }\n }\n\n left = Math.max(VIEWPORT_PADDING, Math.min(left, vw - fRect.width - VIEWPORT_PADDING));\n top = Math.max(VIEWPORT_PADDING, Math.min(top, vh - fRect.height - VIEWPORT_PADDING));\n\n setPos({ top, left, placement });\n }, [triggerRef, floatingRef, side, align, offset, flip]);\n\n useLayoutEffect(() => {\n if (!open) return;\n\n compute();\n\n const onUpdate = () => {\n cancelAnimationFrame(rafId.current);\n rafId.current = requestAnimationFrame(compute);\n };\n\n window.addEventListener(\"scroll\", onUpdate, true);\n window.addEventListener(\"resize\", onUpdate);\n\n return () => {\n cancelAnimationFrame(rafId.current);\n window.removeEventListener(\"scroll\", onUpdate, true);\n window.removeEventListener(\"resize\", onUpdate);\n };\n }, [open, compute]);\n\n return pos;\n}\n","import { useState, useRef, useCallback, useEffect, useId, type HTMLAttributes, type ReactNode, type Ref, createContext } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { cn, GLASS_DROPDOWN } from \"../lib/utils\";\nimport { Slot, mergeRefs } from \"../lib/slot\";\nimport { usePosition, type Side } from \"../lib/use-position\";\n\ninterface TooltipProps extends Omit<HTMLAttributes<HTMLElement>, \"content\"> {\n content: ReactNode;\n children: ReactNode;\n side?: Side;\n delay?: number;\n className?: string;\n container?: Element | DocumentFragment;\n /**\n * Keep the Tooltip in the tree but never show it. Use this instead of rendering\n * the Tooltip only sometimes: adding or removing the wrapper remounts its child,\n * which drops focus from a field inside it (Sprint 25.7, the Combobox).\n */\n disabled?: boolean;\n /**\n * A Tooltip can itself be the child of a Slot — `<DropdownMenu trigger={<Tooltip …><Button/></Tooltip>}>` —\n * so the ref and handlers a parent merges onto it are passed through to its own trigger (14 Sep 2026).\n */\n ref?: Ref<HTMLElement>;\n}\n\n// 600ms: long enough that passing the pointer over a toolbar, or landing focus\n// on an icon button, does not flash a label; short enough to still feel live.\n/** True inside an explicit <Tooltip>: an icon-size Button then skips the tooltip it would otherwise make from its aria-label (round 15, 52.7 — two tooltips on one button). */\nexport const TooltipCtx = createContext(false);\n\nexport function Tooltip({ content, children, side = \"top\", delay = 600, className, container, disabled = false, ref: forwardedRef, ...slotProps }: TooltipProps) {\n const [open, setOpen] = useState(false);\n // Disabling while shown hides it (render-time state adjustment).\n if (disabled && open) setOpen(false);\n const triggerRef = useRef<HTMLElement>(null);\n const floatingRef = useRef<HTMLDivElement>(null);\n const timeoutRef = useRef<ReturnType<typeof setTimeout>>(undefined);\n // Set when the trigger is activated: the label must not reappear (from the\n // focus the click leaves behind, or a still-pending timer) until the pointer\n // leaves and comes back.\n const suppressedRef = useRef(false);\n const id = useId();\n\n const pos = usePosition(triggerRef, floatingRef, open, { side, offset: 6, flip: true });\n\n const cancel = useCallback(() => {\n clearTimeout(timeoutRef.current);\n timeoutRef.current = undefined;\n }, []);\n\n // One pending timer at a time: hover and focus both call show(), and the\n // earlier timer used to be orphaned, firing after hide() had run and leaving\n // the tooltip up with nothing left to close it.\n const show = useCallback(() => {\n if (disabled || suppressedRef.current) return;\n cancel();\n timeoutRef.current = setTimeout(() => setOpen(true), delay);\n }, [delay, cancel, disabled]);\n\n const hide = useCallback(() => {\n cancel();\n setOpen(false);\n }, [cancel]);\n\n // Pointer focus (a click) does not warrant a label; keyboard focus does.\n const showOnFocus = useCallback((e: React.FocusEvent<HTMLElement>) => {\n let keyboard = true;\n try { keyboard = e.currentTarget.matches(\":focus-visible\"); } catch { /* selector unsupported: assume keyboard */ }\n if (keyboard) show();\n }, [show]);\n\n // Activating the trigger dismisses the label and keeps it away until the\n // pointer has left — what opens next (a menu, a dialog) owns the screen.\n const dismissOnActivate = useCallback(() => {\n suppressedRef.current = true;\n hide();\n }, [hide]);\n\n // Suppression lifts when the pointer leaves or focus moves on — a keyboard\n // user never produces a mouseleave, so blur must reset it too.\n const leave = useCallback(() => {\n suppressedRef.current = false;\n hide();\n }, [hide]);\n\n // Escape dismisses an open tooltip (WCAG 1.4.13); it does not stop the key\n // reaching whatever overlay is also listening.\n useEffect(() => {\n if (!open) return;\n const onKey = (e: KeyboardEvent) => { if (e.key === \"Escape\") hide(); };\n document.addEventListener(\"keydown\", onKey);\n return () => document.removeEventListener(\"keydown\", onKey);\n }, [open, hide]);\n\n useEffect(() => cancel, [cancel]);\n\n return (\n <TooltipCtx value={true}>\n <Slot\n {...slotProps}\n ref={mergeRefs(triggerRef, forwardedRef)}\n onMouseEnter={(e) => { slotProps.onMouseEnter?.(e); show(); }}\n onMouseLeave={(e) => { slotProps.onMouseLeave?.(e); leave(); }}\n onFocus={(e) => { slotProps.onFocus?.(e); showOnFocus(e); }}\n onBlur={(e) => { slotProps.onBlur?.(e); leave(); }}\n onPointerDown={(e) => { slotProps.onPointerDown?.(e); dismissOnActivate(); }}\n onKeyDown={(e) => { slotProps.onKeyDown?.(e); if (e.key === \"Enter\" || e.key === \" \") dismissOnActivate(); }}\n aria-describedby={open ? id : undefined}\n >\n {children}\n </Slot>\n {open && createPortal(\n <div\n ref={floatingRef}\n id={id}\n role=\"tooltip\"\n className={cn(\n \"fixed z-[var(--ds-z-tooltip)] pointer-events-none\",\n \"px-ds-2.5 py-ds-1.5 text-xs\",\n \"max-w-[280px] break-words\",\n \"bg-[var(--ds-bg-surface-elevated)] text-[var(--ds-text-primary)]\",\n GLASS_DROPDOWN,\n \"border-[length:var(--ds-border-width)] border-[var(--ds-border-default)]\",\n \"rounded-[var(--ds-radius-sm)]\",\n className\n )}\n style={{ top: pos.top, left: pos.left }}\n >\n {content}\n </div>,\n container ?? document.body\n )}\n </TooltipCtx>\n );\n}\n","import { useState, useCallback, useRef, useEffect } from \"react\";\nimport { useLatest } from \"./use-latest\";\n\n// ─── Shared ResizeObserver (singleton per document) ────────────────────────────\n// All useTextOverflow instances share a single ResizeObserver. This avoids the\n// performance cost of 80+ independent observers on pages with many truncated elements.\n\ntype OverflowCallback = () => void;\n\nconst registry = new WeakMap<Element, Set<OverflowCallback>>();\nlet sharedObserver: ResizeObserver | null = null;\nlet rafId: number | null = null;\nconst pendingElements = new Set<Element>();\n\nfunction getSharedObserver(): ResizeObserver {\n if (sharedObserver) return sharedObserver;\n sharedObserver = new ResizeObserver((entries) => {\n for (const entry of entries) {\n pendingElements.add(entry.target);\n }\n if (rafId === null) {\n rafId = requestAnimationFrame(flush);\n }\n });\n return sharedObserver;\n}\n\nfunction flush() {\n rafId = null;\n for (const el of pendingElements) {\n const callbacks = registry.get(el);\n if (callbacks) {\n for (const cb of callbacks) cb();\n }\n }\n pendingElements.clear();\n}\n\nfunction observe(el: Element, callback: OverflowCallback) {\n let set = registry.get(el);\n if (!set) {\n set = new Set();\n registry.set(el, set);\n }\n set.add(callback);\n if (set.size === 1) {\n getSharedObserver().observe(el);\n }\n}\n\nfunction unobserve(el: Element, callback: OverflowCallback) {\n const set = registry.get(el);\n if (!set) return;\n set.delete(callback);\n if (set.size === 0) {\n registry.delete(el);\n getSharedObserver().unobserve(el);\n }\n}\n\n// ─── Overflow detection ────────────────────────────────────────────────────────\n\nconst TOLERANCE = 1; // px — accounts for integer rounding in scrollWidth/clientWidth\n\nfunction checkOverflow(el: HTMLElement, lines: number): boolean {\n if (lines <= 1) {\n return el.scrollWidth - el.clientWidth > TOLERANCE;\n }\n return el.scrollHeight - el.clientHeight > TOLERANCE;\n}\n\n// ─── Hook ──────────────────────────────────────────────────────────────────────\n\nexport interface UseTextOverflowOptions {\n /** Number of visible lines before truncation. 1 = single-line ellipsis, >1 = line-clamp. */\n lines?: number;\n /** Disable overflow detection (e.g. when component is hidden) */\n disabled?: boolean;\n /** Content key — triggers re-check when this value changes (use for dynamic text content) */\n content?: unknown;\n}\n\nexport interface UseTextOverflowResult {\n /** Callback ref — attach to the element that has truncation CSS applied */\n ref: (node: HTMLElement | null) => void;\n /** True when the element's text is currently overflowing/truncated */\n isTruncated: boolean;\n}\n\n/**\n * Detects whether an element's text content is overflowing (truncated).\n * Uses a single shared ResizeObserver for all instances on the page.\n *\n * @example\n * const { ref, isTruncated } = useTextOverflow({ lines: 1 });\n * return (\n * <Tooltip content={fullText} disabled={!isTruncated}>\n * <span ref={ref} className=\"truncate\">{fullText}</span>\n * </Tooltip>\n * );\n */\nexport function useTextOverflow(options: UseTextOverflowOptions = {}): UseTextOverflowResult {\n const { lines = 1, disabled = false, content } = options;\n const [isTruncated, setIsTruncated] = useState(false);\n const elementRef = useRef<HTMLElement | null>(null);\n // The observer-registered wrapper delegates to the latest check logic via checkRef.\n const registeredRef = useRef<OverflowCallback | null>(null);\n\n const doCheck = useCallback(() => {\n if (!elementRef.current || disabled) {\n setIsTruncated(false);\n return;\n }\n const next = checkOverflow(elementRef.current, lines);\n setIsTruncated((prev) => (prev !== next ? next : prev));\n }, [lines, disabled]);\n\n // Latest check logic, updated in a layout effect so the stable wrapper never runs a stale closure.\n const checkRef = useLatest<OverflowCallback>(doCheck);\n\n // Re-check when content changes (handles dynamic text like Dropdown selection)\n // or when disabled state changes\n // Measures the committed DOM, so it must stay a post-layout effect.\n /* eslint-disable react-hooks/set-state-in-effect -- overflow is a layout measurement */\n useEffect(() => {\n if (disabled) {\n setIsTruncated(false);\n } else if (elementRef.current) {\n const next = checkOverflow(elementRef.current, lines);\n setIsTruncated((prev) => (prev !== next ? next : prev));\n }\n }, [content, lines, disabled]);\n /* eslint-enable react-hooks/set-state-in-effect */\n\n const ref = useCallback(\n (node: HTMLElement | null) => {\n const prev = elementRef.current;\n\n // Unregister previous element using the SAME function we registered with\n if (prev && registeredRef.current) {\n unobserve(prev, registeredRef.current);\n registeredRef.current = null;\n }\n\n elementRef.current = node;\n\n if (node && !disabled) {\n // Stable wrapper that delegates to the latest check logic\n const wrapper: OverflowCallback = () => checkRef.current?.();\n registeredRef.current = wrapper;\n observe(node, wrapper);\n // Initial check on mount\n const initial = checkOverflow(node, lines);\n setIsTruncated(initial);\n }\n },\n [lines, disabled, checkRef],\n );\n\n // Cleanup on unmount — uses the registered wrapper, not the check function\n useEffect(() => {\n return () => {\n if (elementRef.current && registeredRef.current) {\n unobserve(elementRef.current, registeredRef.current);\n }\n };\n }, []);\n\n return { ref, isTruncated };\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { useTextOverflow, Tooltip } from './chunk-
|
|
2
|
-
import { cn } from './chunk-
|
|
1
|
+
import { useTextOverflow, Tooltip } from './chunk-ILIODA7W.js';
|
|
2
|
+
import { cn } from './chunk-M2QRNBDQ.js';
|
|
3
3
|
import { Fragment } from 'react';
|
|
4
4
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
5
5
|
|
|
@@ -63,5 +63,5 @@ function CardValue({ value }) {
|
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
export { CardValue, inferColumnKinds };
|
|
66
|
-
//# sourceMappingURL=chunk-
|
|
67
|
-
//# sourceMappingURL=chunk-
|
|
66
|
+
//# sourceMappingURL=chunk-JN37OVTP.js.map
|
|
67
|
+
//# sourceMappingURL=chunk-JN37OVTP.js.map
|