@tetrascience-npm/tetrascience-react-ui 1.0.0-beta.155.1 → 1.0.0-beta.157.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/composed/AssistantLayout/AssistantLayout.cjs +1 -1
- package/dist/components/composed/AssistantLayout/AssistantLayout.cjs.map +1 -1
- package/dist/components/composed/AssistantLayout/AssistantLayout.d.ts +15 -1
- package/dist/components/composed/AssistantLayout/AssistantLayout.js +132 -103
- package/dist/components/composed/AssistantLayout/AssistantLayout.js.map +1 -1
- package/dist/components/composed/DataAppShell/RightPanel.cjs +1 -1
- package/dist/components/composed/DataAppShell/RightPanel.cjs.map +1 -1
- package/dist/components/composed/DataAppShell/RightPanel.d.ts +11 -1
- package/dist/components/composed/DataAppShell/RightPanel.js +128 -126
- package/dist/components/composed/DataAppShell/RightPanel.js.map +1 -1
- package/dist/index.css +1 -1
- package/dist/index.scoped.css +1 -1
- package/dist/index.tailwind.css +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RightPanel.cjs","sources":["../../../../src/components/composed/DataAppShell/RightPanel.tsx"],"sourcesContent":["\"use client\";\n\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { PanelRightOpen, X } from \"lucide-react\";\nimport { Slot } from \"radix-ui\";\nimport * as React from \"react\";\n\nimport { Button } from \"@/components/ui/button\";\nimport { Sheet, SheetContent, SheetDescription, SheetTitle } from \"@/components/ui/sheet\";\nimport { cn } from \"@/lib/utils\";\n\n// =============================================================================\n// Width persistence — one localStorage entry per panel `id`\n// =============================================================================\n\nconst STORAGE_PREFIX = \"ts-ui.right-panel\";\n\nfunction storageKey(id: string): string {\n return `${STORAGE_PREFIX}.${id}.width`;\n}\n\nfunction clampWidth(width: number, min: number, max: number): number {\n return Math.min(max, Math.max(min, width));\n}\n\nfunction readWidth(id: string, fallback: number, min: number, max: number): number {\n if (typeof window === \"undefined\") return fallback;\n let v: number;\n try {\n v = Number(window.localStorage.getItem(storageKey(id)));\n } catch {\n // Storage can be blocked (privacy mode, sandboxed iframe) — fall back.\n return fallback;\n }\n if (!Number.isFinite(v) || v <= 0) return fallback;\n return clampWidth(v, min, max);\n}\n\nfunction persistWidth(id: string, width: number) {\n if (typeof window === \"undefined\") return;\n try {\n window.localStorage.setItem(storageKey(id), String(Math.round(width)));\n } catch {\n // Storage blocked or full — resizing still works, the width just isn't persisted.\n }\n}\n\n// =============================================================================\n// Trigger — FAB over the content area, or an icon button for the top bar\n// =============================================================================\n\nconst dataAppShellRightPanelTriggerVariants = cva(\n \"inline-flex items-center justify-center border-none cursor-pointer transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\",\n {\n variants: {\n variant: {\n /** Floating action button, bottom-right of the nearest `relative` container */\n fab: \"absolute bottom-4 right-4 z-40 rounded-full bg-primary text-primary-foreground shadow-elevation-4 hover:bg-primary/90 focus-visible:ring-offset-2 focus-visible:ring-offset-background motion-safe:animate-in motion-safe:fade-in-0 motion-safe:zoom-in-95\",\n /** Ghost icon button matching top-bar actions — place in `headerActions` */\n icon: \"rounded-lg bg-transparent text-muted-foreground hover:bg-accent hover:text-accent-foreground aria-expanded:bg-accent aria-expanded:text-foreground\",\n },\n size: {\n default: \"\",\n lg: \"\",\n },\n },\n compoundVariants: [\n { variant: \"fab\", size: \"default\", class: \"size-10 [&_svg:not([class*='size-'])]:size-4\" },\n { variant: \"fab\", size: \"lg\", class: \"size-12 [&_svg:not([class*='size-'])]:size-5\" },\n { variant: \"icon\", size: \"default\", class: \"size-7 [&_svg:not([class*='size-'])]:size-4\" },\n { variant: \"icon\", size: \"lg\", class: \"size-8 [&_svg:not([class*='size-'])]:size-4\" },\n ],\n defaultVariants: { variant: \"fab\", size: \"default\" },\n },\n);\n\nexport interface DataAppShellRightPanelTriggerProps\n extends React.ComponentProps<\"button\">,\n VariantProps<typeof dataAppShellRightPanelTriggerVariants> {\n /** Merge the trigger styling/props onto the child element instead of\n * rendering a `<button>` — makes anything clickable a panel trigger. */\n asChild?: boolean;\n}\n\n/**\n * Trigger for a `DataAppShellRightPanel`, in two variants:\n *\n * - `fab` (default) — floating action button; what the panel auto-renders\n * while closed. Positioned `absolute` — place inside a `relative` container\n * (normally the shell's content area).\n * - `icon` — ghost icon button sized like the shell's top-bar actions. Place\n * it in the shell's `headerActions`, set `showTrigger={false}` on the panel,\n * and pass the same ref to the panel's `triggerRef` so focus returns here\n * when the panel closes.\n *\n * With `asChild` the trigger renders no element of its own and instead merges\n * onto its child — any clickable element (a link, menu item, custom button)\n * can act as the trigger.\n */\nfunction DataAppShellRightPanelTrigger({\n className,\n variant,\n size,\n asChild = false,\n children,\n ...props\n}: DataAppShellRightPanelTriggerProps) {\n const Comp = asChild ? Slot.Root : \"button\";\n return (\n <Comp\n // `type` only when we own the element — a slotted child may not be a button\n {...(asChild ? {} : { type: \"button\" as const })}\n data-slot=\"data-app-shell-right-panel-trigger\"\n data-variant={variant ?? \"fab\"}\n className={cn(dataAppShellRightPanelTriggerVariants({ variant, size }), className)}\n {...props}\n >\n {asChild ? children : (children ?? <PanelRightOpen />)}\n </Comp>\n );\n}\n\n// =============================================================================\n// DragHandle — pointer + keyboard resize on the panel's left edge\n// =============================================================================\n\n/** Pixels per arrow-key press when resizing with the keyboard. */\nconst KEYBOARD_RESIZE_STEP = 16;\n\ninterface DragHandleProps {\n width: number;\n minWidth: number;\n maxWidth: number;\n /** Live width updates while dragging (not yet persisted). */\n onResize: (width: number) => void;\n /** Final width once the interaction ends — persist here. */\n onCommit: (width: number) => void;\n onDraggingChange: (dragging: boolean) => void;\n}\n\n/**\n * Vertical resize handle docked on the panel's left edge. Pointer-driven\n * (px-based, unlike the percentage-based `Resizable` group primitive) so the\n * panel keeps an absolute width that can be persisted per `id`. Also a\n * keyboard-operable ARIA separator: arrows resize, Home/End jump to min/max.\n */\nfunction DragHandle({ width, minWidth, maxWidth, onResize, onCommit, onDraggingChange }: DragHandleProps) {\n const dragState = React.useRef<{ startX: number; startWidth: number; liveWidth: number } | null>(null);\n const widthRef = React.useRef(width);\n widthRef.current = width;\n\n const handlePointerDown = (e: React.PointerEvent<HTMLDivElement>) => {\n // Primary button / touch only\n if (e.button !== 0) return;\n dragState.current = { startX: e.clientX, startWidth: widthRef.current, liveWidth: widthRef.current };\n try {\n e.currentTarget.setPointerCapture(e.pointerId);\n } catch {\n // Synthetic pointer events (play tests) have no active pointer to\n // capture; move/up still arrive via the handle's own listeners.\n }\n onDraggingChange(true);\n };\n\n const handlePointerMove = (e: React.PointerEvent<HTMLDivElement>) => {\n if (!dragState.current) return;\n // Handle sits on the left edge — dragging left grows the panel.\n const delta = dragState.current.startX - e.clientX;\n const next = clampWidth(dragState.current.startWidth + delta, minWidth, maxWidth);\n dragState.current.liveWidth = next;\n onResize(next);\n };\n\n const endDrag = (e: React.PointerEvent<HTMLDivElement>) => {\n if (!dragState.current) return;\n // Commit the drag state's own width — pointermove renders lazily, so the\n // width prop can be one frame stale when pointerup lands.\n const finalWidth = dragState.current.liveWidth;\n dragState.current = null;\n if (e.currentTarget.hasPointerCapture(e.pointerId)) {\n e.currentTarget.releasePointerCapture(e.pointerId);\n }\n onDraggingChange(false);\n onCommit(finalWidth);\n };\n\n const handleKeyDown = (e: React.KeyboardEvent<HTMLDivElement>) => {\n let next: number | null = null;\n switch (e.key) {\n case \"ArrowLeft\": // handle moves left → panel grows\n next = clampWidth(widthRef.current + KEYBOARD_RESIZE_STEP, minWidth, maxWidth);\n break;\n case \"ArrowRight\":\n next = clampWidth(widthRef.current - KEYBOARD_RESIZE_STEP, minWidth, maxWidth);\n break;\n case \"Home\":\n next = minWidth;\n break;\n case \"End\":\n next = maxWidth;\n break;\n }\n if (next == null) return;\n e.preventDefault();\n onResize(next);\n onCommit(next);\n };\n\n return (\n <div\n data-slot=\"data-app-shell-right-panel-drag-handle\"\n role=\"separator\"\n aria-orientation=\"vertical\"\n aria-label=\"Resize panel\"\n aria-valuemin={minWidth}\n aria-valuemax={maxWidth}\n aria-valuenow={Math.round(width)}\n tabIndex={0}\n className={cn(\n // 1px seam over the panel's left border; wide invisible grab area via ::after\n \"absolute inset-y-0 left-0 z-10 w-px cursor-col-resize touch-none select-none bg-transparent transition-colors\",\n \"after:absolute after:inset-y-0 after:left-1/2 after:w-3 after:-translate-x-1/2\",\n // reveal on hover / drag (border color) and keyboard focus (ring color)\n \"hover:bg-border active:bg-border focus-visible:outline-none focus-visible:bg-ring\",\n // centered grip dots, revealed with the seam\n \"flex items-center justify-center\",\n \"[&>div]:opacity-0 hover:[&>div]:opacity-100 active:[&>div]:opacity-100 focus-visible:[&>div]:opacity-100\",\n )}\n onPointerDown={handlePointerDown}\n onPointerMove={handlePointerMove}\n onPointerUp={endDrag}\n onPointerCancel={endDrag}\n onKeyDown={handleKeyDown}\n >\n <div className=\"z-10 h-6 w-1 shrink-0 rounded-lg bg-muted-foreground/40 transition-opacity\" />\n </div>\n );\n}\n\n// =============================================================================\n// DataAppShellRightPanel\n// =============================================================================\n\nexport type DataAppShellRightPanelVariant = \"docked\" | \"overlay\";\n\nexport interface DataAppShellRightPanelProps extends Omit<React.ComponentProps<\"aside\">, \"id\" | \"title\"> {\n /** Unique panel id — keys the persisted width in localStorage. */\n id: string;\n /** Whether the panel is shown or collapsed to the FAB trigger. */\n open: boolean;\n /** Called with the next open state (close button, Esc, scrim click, FAB). */\n onOpenChange?: (open: boolean) => void;\n /**\n * `docked` (default) — in-flow flex sibling: opening/resizing pushes main narrower.\n * `overlay` — reuses the design-system `Sheet`: slides in over content with a scrim, no reflow.\n */\n variant?: DataAppShellRightPanelVariant;\n /** Show the drag handle and allow resizing. Defaults to `true`. Docked only — the overlay has a fixed width. */\n resizable?: boolean;\n /** Width in px when nothing is persisted yet. */\n defaultWidth?: number;\n /** Minimum width in px the panel can be resized to. */\n minWidth?: number;\n /** Maximum width in px the panel can be resized to. */\n maxWidth?: number;\n /** Persist the width to localStorage. Defaults to `true`. */\n persist?: boolean;\n /** Header title. The header row also carries the close button. */\n title?: React.ReactNode;\n /** Optional element rendered before the title (e.g. an app icon). */\n icon?: React.ReactNode;\n /** Extra elements rendered in the header, before the close button. */\n headerActions?: React.ReactNode;\n /** Render the floating FAB trigger while closed. Defaults to `true`. Set\n * `false` when the trigger lives elsewhere (e.g. an `icon`-variant\n * `DataAppShellRightPanelTrigger` in the shell's `headerActions`). */\n showTrigger?: boolean;\n /** Icon inside the FAB trigger. Defaults to a panel-open icon. */\n triggerIcon?: React.ReactNode;\n /** Accessible label for the FAB trigger. */\n triggerLabel?: string;\n /** Ref to an external trigger (e.g. a top-bar icon trigger) that receives\n * focus when the panel closes and `showTrigger` is `false`. */\n triggerRef?: React.RefObject<HTMLButtonElement | null>;\n /** Panel content — any React node (a chat, history list, inspector, …). */\n children?: React.ReactNode;\n}\n\n/**\n * Right-hand panel for the Data App Shell (SW-2117), in two variants:\n *\n * - `docked` (default) — rendered in normal flow as a flex sibling of the main\n * content, so opening/resizing pushes main narrower. Width is drag-resizable\n * and persisted per `id`.\n * - `overlay` — reuses the design-system `Sheet` (`side=\"right\"`): slides in\n * over the content with a scrim and does not reflow main.\n *\n * In both variants a floating FAB trigger re-opens the panel while it is\n * closed, and the body is a plain slot — a chat, history list, inspector, ….\n * Pass it to the shell's `rightPanel` slot, or place it after the main content\n * inside a `relative` flex row:\n *\n * ```tsx\n * <div className=\"relative flex flex-1 min-h-0\">\n * <main className=\"flex-1 min-w-0\">…</main>\n * <DataAppShellRightPanel id=\"chat\" open={open} onOpenChange={setOpen} title=\"Chat\">\n * …\n * </DataAppShellRightPanel>\n * </div>\n * ```\n */\nfunction DataAppShellRightPanel({\n id,\n open,\n onOpenChange,\n variant = \"docked\",\n resizable = true,\n defaultWidth = 320,\n minWidth = 240,\n maxWidth = 560,\n persist = true,\n title,\n icon,\n headerActions,\n showTrigger = true,\n triggerIcon,\n triggerLabel = \"Open panel\",\n triggerRef,\n children,\n className,\n ref,\n ...props\n}: DataAppShellRightPanelProps) {\n const [width, setWidth] = React.useState<number>(() =>\n persist ? readWidth(id, defaultWidth, minWidth, maxWidth) : clampWidth(defaultWidth, minWidth, maxWidth),\n );\n const [dragging, setDragging] = React.useState(false);\n\n const closeButtonRef = React.useRef<HTMLButtonElement>(null);\n const fabRef = React.useRef<HTMLButtonElement>(null);\n // Focus lands on the built-in FAB when it renders, else on the external trigger.\n const closeFocusRef = showTrigger ? fabRef : triggerRef;\n\n const commitWidth = React.useCallback(\n (next: number) => {\n if (persist) persistWidth(id, next);\n },\n [id, persist],\n );\n\n // Focus follows the open state: into the panel on open, back to the FAB on\n // close — but only on actual transitions, not on mount.\n const mountedRef = React.useRef(false);\n React.useEffect(() => {\n if (!mountedRef.current) {\n mountedRef.current = true;\n return;\n }\n // preventScroll — plain .focus() scrolls the target into view, which\n // jolts any scrollable ancestor (e.g. a Storybook docs page) on toggle.\n if (open) closeButtonRef.current?.focus({ preventScroll: true });\n else closeFocusRef?.current?.focus({ preventScroll: true });\n }, [open, closeFocusRef]);\n\n const accessibleName = typeof title === \"string\" ? title : \"Side panel\";\n\n const fab = showTrigger ? (\n <DataAppShellRightPanelTrigger\n ref={fabRef}\n aria-label={triggerLabel}\n aria-expanded={false}\n onClick={() => onOpenChange?.(true)}\n >\n {triggerIcon}\n </DataAppShellRightPanelTrigger>\n ) : null;\n\n const header = (\n <div\n data-slot=\"data-app-shell-right-panel-header\"\n className=\"flex shrink-0 items-center gap-2 border-b border-border px-3 py-2\"\n >\n {icon != null && <span className=\"flex shrink-0 items-center justify-center\">{icon}</span>}\n {title != null && <span className=\"min-w-0 flex-1 truncate text-sm font-semibold text-foreground\">{title}</span>}\n {title == null && <span className=\"flex-1\" />}\n {headerActions}\n <Button\n ref={closeButtonRef}\n variant=\"ghost\"\n size=\"icon-sm\"\n className=\"text-muted-foreground\"\n aria-label=\"Close panel\"\n onClick={() => onOpenChange?.(false)}\n >\n <X />\n </Button>\n </div>\n );\n\n const content = (\n <div data-slot=\"data-app-shell-right-panel-content\" className=\"flex min-h-0 flex-1 flex-col overflow-auto\">\n {children}\n </div>\n );\n\n // Overlay — reuse the design-system Sheet: scrim, slide-in, Esc/click-out\n // close and focus trapping all come from the primitive. No reflow of main.\n if (variant === \"overlay\") {\n return (\n <>\n <Sheet open={open} onOpenChange={onOpenChange}>\n <SheetContent\n side=\"right\"\n showCloseButton={false}\n data-slot=\"data-app-shell-right-panel\"\n data-variant=\"overlay\"\n // The FAB remounts on close, so radix's default \"restore previous\n // focus\" targets a dead node — send focus to the new FAB instead.\n onCloseAutoFocus={(e) => {\n e.preventDefault();\n closeFocusRef?.current?.focus({ preventScroll: true });\n }}\n style={{ width }}\n className={cn(\"gap-0 data-[side=right]:sm:max-w-none\", className)}\n {...props}\n >\n <SheetTitle className=\"sr-only\">{accessibleName}</SheetTitle>\n <SheetDescription className=\"sr-only\">Side panel overlay</SheetDescription>\n {header}\n {content}\n </SheetContent>\n </Sheet>\n {!open && fab}\n </>\n );\n }\n\n if (!open) return fab;\n\n return (\n <aside\n ref={ref}\n data-slot=\"data-app-shell-right-panel\"\n data-variant=\"docked\"\n aria-label={accessibleName}\n style={{ width }}\n className={cn(\n \"relative flex h-full shrink-0 flex-col overflow-hidden border-l border-border bg-background\",\n \"motion-safe:animate-in motion-safe:fade-in-0 motion-safe:slide-in-from-right-4\",\n !dragging && \"motion-safe:transition-[width] motion-safe:duration-200\",\n className,\n )}\n onKeyDown={(e) => {\n if (e.key === \"Escape\") onOpenChange?.(false);\n }}\n {...props}\n >\n {resizable && (\n <DragHandle\n width={width}\n minWidth={minWidth}\n maxWidth={maxWidth}\n onResize={setWidth}\n onCommit={commitWidth}\n onDraggingChange={setDragging}\n />\n )}\n\n {header}\n {content}\n </aside>\n );\n}\n\nexport { DataAppShellRightPanel, DataAppShellRightPanelTrigger, dataAppShellRightPanelTriggerVariants };\n"],"names":["STORAGE_PREFIX","storageKey","id","clampWidth","width","min","max","readWidth","fallback","v","persistWidth","dataAppShellRightPanelTriggerVariants","cva","DataAppShellRightPanelTrigger","className","variant","size","asChild","children","props","Comp","Slot","jsx","cn","PanelRightOpen","KEYBOARD_RESIZE_STEP","DragHandle","minWidth","maxWidth","onResize","onCommit","onDraggingChange","dragState","React","widthRef","handlePointerDown","e","handlePointerMove","delta","next","endDrag","finalWidth","handleKeyDown","DataAppShellRightPanel","open","onOpenChange","resizable","defaultWidth","persist","title","icon","headerActions","showTrigger","triggerIcon","triggerLabel","triggerRef","ref","setWidth","dragging","setDragging","closeButtonRef","fabRef","closeFocusRef","commitWidth","mountedRef","accessibleName","fab","header","jsxs","Button","X","content","Fragment","Sheet","SheetContent","SheetTitle","SheetDescription"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"RightPanel.cjs","sources":["../../../../src/components/composed/DataAppShell/RightPanel.tsx"],"sourcesContent":["\"use client\";\n\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { PanelRightOpen, X } from \"lucide-react\";\nimport { Slot } from \"radix-ui\";\nimport * as React from \"react\";\n\nimport { Button } from \"@/components/ui/button\";\nimport { Sheet, SheetContent, SheetDescription, SheetTitle } from \"@/components/ui/sheet\";\nimport { cn } from \"@/lib/utils\";\n\n// =============================================================================\n// Width persistence — one localStorage entry per panel `id`\n// =============================================================================\n\nconst STORAGE_PREFIX = \"ts-ui.right-panel\";\n\nfunction storageKey(id: string): string {\n return `${STORAGE_PREFIX}.${id}.width`;\n}\n\nfunction clampWidth(width: number, min: number, max: number): number {\n return Math.min(max, Math.max(min, width));\n}\n\nfunction readWidth(id: string, fallback: number, min: number, max: number): number {\n if (typeof window === \"undefined\") return fallback;\n let v: number;\n try {\n v = Number(window.localStorage.getItem(storageKey(id)));\n } catch {\n // Storage can be blocked (privacy mode, sandboxed iframe) — fall back.\n return fallback;\n }\n if (!Number.isFinite(v) || v <= 0) return fallback;\n return clampWidth(v, min, max);\n}\n\nfunction persistWidth(id: string, width: number) {\n if (typeof window === \"undefined\") return;\n try {\n window.localStorage.setItem(storageKey(id), String(Math.round(width)));\n } catch {\n // Storage blocked or full — resizing still works, the width just isn't persisted.\n }\n}\n\n// =============================================================================\n// Trigger — FAB over the content area, or an icon button for the top bar\n// =============================================================================\n\nconst dataAppShellRightPanelTriggerVariants = cva(\n \"inline-flex items-center justify-center border-none cursor-pointer transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\",\n {\n variants: {\n variant: {\n /** Floating action button, bottom-right of the nearest `relative` container */\n fab: \"absolute bottom-4 right-4 z-40 rounded-full bg-primary text-primary-foreground shadow-elevation-4 hover:bg-primary/90 focus-visible:ring-offset-2 focus-visible:ring-offset-background motion-safe:animate-in motion-safe:fade-in-0 motion-safe:zoom-in-95\",\n /** Ghost icon button matching top-bar actions — place in `headerActions` */\n icon: \"rounded-lg bg-transparent text-muted-foreground hover:bg-accent hover:text-accent-foreground aria-expanded:bg-accent aria-expanded:text-foreground\",\n },\n size: {\n default: \"\",\n lg: \"\",\n },\n },\n compoundVariants: [\n { variant: \"fab\", size: \"default\", class: \"size-10 [&_svg:not([class*='size-'])]:size-4\" },\n { variant: \"fab\", size: \"lg\", class: \"size-12 [&_svg:not([class*='size-'])]:size-5\" },\n { variant: \"icon\", size: \"default\", class: \"size-7 [&_svg:not([class*='size-'])]:size-4\" },\n { variant: \"icon\", size: \"lg\", class: \"size-8 [&_svg:not([class*='size-'])]:size-4\" },\n ],\n defaultVariants: { variant: \"fab\", size: \"default\" },\n },\n);\n\nexport interface DataAppShellRightPanelTriggerProps\n extends React.ComponentProps<\"button\">,\n VariantProps<typeof dataAppShellRightPanelTriggerVariants> {\n /** Merge the trigger styling/props onto the child element instead of\n * rendering a `<button>` — makes anything clickable a panel trigger. */\n asChild?: boolean;\n}\n\n/**\n * Trigger for a `DataAppShellRightPanel`, in two variants:\n *\n * - `fab` (default) — floating action button; what the panel auto-renders\n * while closed. Positioned `absolute` — place inside a `relative` container\n * (normally the shell's content area).\n * - `icon` — ghost icon button sized like the shell's top-bar actions. Place\n * it in the shell's `headerActions`, set `showTrigger={false}` on the panel,\n * and pass the same ref to the panel's `triggerRef` so focus returns here\n * when the panel closes.\n *\n * With `asChild` the trigger renders no element of its own and instead merges\n * onto its child — any clickable element (a link, menu item, custom button)\n * can act as the trigger.\n */\nfunction DataAppShellRightPanelTrigger({\n className,\n variant,\n size,\n asChild = false,\n children,\n ...props\n}: DataAppShellRightPanelTriggerProps) {\n const Comp = asChild ? Slot.Root : \"button\";\n return (\n <Comp\n // `type` only when we own the element — a slotted child may not be a button\n {...(asChild ? {} : { type: \"button\" as const })}\n data-slot=\"data-app-shell-right-panel-trigger\"\n data-variant={variant ?? \"fab\"}\n className={cn(dataAppShellRightPanelTriggerVariants({ variant, size }), className)}\n {...props}\n >\n {asChild ? children : (children ?? <PanelRightOpen />)}\n </Comp>\n );\n}\n\n// =============================================================================\n// DragHandle — pointer + keyboard resize on the panel's left edge\n// =============================================================================\n\n/** Pixels per arrow-key press when resizing with the keyboard. */\nconst KEYBOARD_RESIZE_STEP = 16;\n\ninterface DragHandleProps {\n width: number;\n minWidth: number;\n maxWidth: number;\n /** Live width updates while dragging (not yet persisted). */\n onResize: (width: number) => void;\n /** Final width once the interaction ends — persist here. */\n onCommit: (width: number) => void;\n onDraggingChange: (dragging: boolean) => void;\n}\n\n/**\n * Vertical resize handle docked on the panel's left edge. Pointer-driven\n * (px-based, unlike the percentage-based `Resizable` group primitive) so the\n * panel keeps an absolute width that can be persisted per `id`. Also a\n * keyboard-operable ARIA separator: arrows resize, Home/End jump to min/max.\n */\nfunction DragHandle({ width, minWidth, maxWidth, onResize, onCommit, onDraggingChange }: DragHandleProps) {\n const dragState = React.useRef<{ startX: number; startWidth: number; liveWidth: number } | null>(null);\n const widthRef = React.useRef(width);\n widthRef.current = width;\n\n const handlePointerDown = (e: React.PointerEvent<HTMLDivElement>) => {\n // Primary button / touch only\n if (e.button !== 0) return;\n dragState.current = { startX: e.clientX, startWidth: widthRef.current, liveWidth: widthRef.current };\n try {\n e.currentTarget.setPointerCapture(e.pointerId);\n } catch {\n // Synthetic pointer events (play tests) have no active pointer to\n // capture; move/up still arrive via the handle's own listeners.\n }\n onDraggingChange(true);\n };\n\n const handlePointerMove = (e: React.PointerEvent<HTMLDivElement>) => {\n if (!dragState.current) return;\n // Handle sits on the left edge — dragging left grows the panel.\n const delta = dragState.current.startX - e.clientX;\n const next = clampWidth(dragState.current.startWidth + delta, minWidth, maxWidth);\n dragState.current.liveWidth = next;\n onResize(next);\n };\n\n const endDrag = (e: React.PointerEvent<HTMLDivElement>) => {\n if (!dragState.current) return;\n // Commit the drag state's own width — pointermove renders lazily, so the\n // width prop can be one frame stale when pointerup lands.\n const finalWidth = dragState.current.liveWidth;\n dragState.current = null;\n if (e.currentTarget.hasPointerCapture(e.pointerId)) {\n e.currentTarget.releasePointerCapture(e.pointerId);\n }\n onDraggingChange(false);\n onCommit(finalWidth);\n };\n\n const handleKeyDown = (e: React.KeyboardEvent<HTMLDivElement>) => {\n let next: number | null = null;\n switch (e.key) {\n case \"ArrowLeft\": // handle moves left → panel grows\n next = clampWidth(widthRef.current + KEYBOARD_RESIZE_STEP, minWidth, maxWidth);\n break;\n case \"ArrowRight\":\n next = clampWidth(widthRef.current - KEYBOARD_RESIZE_STEP, minWidth, maxWidth);\n break;\n case \"Home\":\n next = minWidth;\n break;\n case \"End\":\n next = maxWidth;\n break;\n }\n if (next == null) return;\n e.preventDefault();\n onResize(next);\n onCommit(next);\n };\n\n return (\n <div\n data-slot=\"data-app-shell-right-panel-drag-handle\"\n role=\"separator\"\n aria-orientation=\"vertical\"\n aria-label=\"Resize panel\"\n aria-valuemin={minWidth}\n aria-valuemax={maxWidth}\n aria-valuenow={Math.round(width)}\n tabIndex={0}\n className={cn(\n // 1px seam over the panel's left border; wide invisible grab area via ::after\n \"absolute inset-y-0 left-0 z-10 w-px cursor-col-resize touch-none select-none bg-transparent transition-colors\",\n \"after:absolute after:inset-y-0 after:left-1/2 after:w-3 after:-translate-x-1/2\",\n // reveal on hover / drag (border color) and keyboard focus (ring color)\n \"hover:bg-border active:bg-border focus-visible:outline-none focus-visible:bg-ring\",\n // centered grip dots, revealed with the seam\n \"flex items-center justify-center\",\n \"[&>div]:opacity-0 hover:[&>div]:opacity-100 active:[&>div]:opacity-100 focus-visible:[&>div]:opacity-100\",\n )}\n onPointerDown={handlePointerDown}\n onPointerMove={handlePointerMove}\n onPointerUp={endDrag}\n onPointerCancel={endDrag}\n onKeyDown={handleKeyDown}\n >\n <div className=\"z-10 h-6 w-1 shrink-0 rounded-lg bg-muted-foreground/40 transition-opacity\" />\n </div>\n );\n}\n\n// =============================================================================\n// DataAppShellRightPanel\n// =============================================================================\n\nexport type DataAppShellRightPanelVariant = \"docked\" | \"overlay\";\n\nexport interface DataAppShellRightPanelProps extends Omit<React.ComponentProps<\"aside\">, \"id\" | \"title\"> {\n /** Unique panel id — keys the persisted width in localStorage. */\n id: string;\n /** Whether the panel is shown or collapsed to the FAB trigger. */\n open: boolean;\n /** Called with the next open state (close button, Esc, scrim click, FAB). */\n onOpenChange?: (open: boolean) => void;\n /**\n * `docked` (default) — in-flow flex sibling: opening/resizing pushes main narrower.\n * `overlay` — reuses the design-system `Sheet`: slides in over content with a scrim, no reflow.\n */\n variant?: DataAppShellRightPanelVariant;\n /**\n * Panel surface (SW-2592):\n * - `raised` (default) — a `bg-card` surface distinct from the page ground, with\n * a tinted (`bg-accent`) header cap. Reads as a surface *on* the page, not a\n * column *of* it. `bg-card` is the only surface token that stays raised in both\n * light and dark (`bg-sidebar` collapses to the body colour in dark).\n * - `flat` — the legacy look: `bg-background` body and a plain bordered header,\n * for a panel that should read as part of the page ground.\n */\n surface?: \"raised\" | \"flat\";\n /** Show the drag handle and allow resizing. Defaults to `true`. Docked only — the overlay has a fixed width. */\n resizable?: boolean;\n /** Width in px when nothing is persisted yet. */\n defaultWidth?: number;\n /** Minimum width in px the panel can be resized to. */\n minWidth?: number;\n /** Maximum width in px the panel can be resized to. */\n maxWidth?: number;\n /** Persist the width to localStorage. Defaults to `true`. */\n persist?: boolean;\n /** Header title. The header row also carries the close button. */\n title?: React.ReactNode;\n /** Optional element rendered before the title (e.g. an app icon). */\n icon?: React.ReactNode;\n /** Extra elements rendered in the header, before the close button. */\n headerActions?: React.ReactNode;\n /** Render the floating FAB trigger while closed. Defaults to `true`. Set\n * `false` when the trigger lives elsewhere (e.g. an `icon`-variant\n * `DataAppShellRightPanelTrigger` in the shell's `headerActions`). */\n showTrigger?: boolean;\n /** Icon inside the FAB trigger. Defaults to a panel-open icon. */\n triggerIcon?: React.ReactNode;\n /** Accessible label for the FAB trigger. */\n triggerLabel?: string;\n /** Ref to an external trigger (e.g. a top-bar icon trigger) that receives\n * focus when the panel closes and `showTrigger` is `false`. */\n triggerRef?: React.RefObject<HTMLButtonElement | null>;\n /** Panel content — any React node (a chat, history list, inspector, …). */\n children?: React.ReactNode;\n}\n\n/**\n * Right-hand panel for the Data App Shell (SW-2117), in two variants:\n *\n * - `docked` (default) — rendered in normal flow as a flex sibling of the main\n * content, so opening/resizing pushes main narrower. Width is drag-resizable\n * and persisted per `id`.\n * - `overlay` — reuses the design-system `Sheet` (`side=\"right\"`): slides in\n * over the content with a scrim and does not reflow main.\n *\n * In both variants a floating FAB trigger re-opens the panel while it is\n * closed, and the body is a plain slot — a chat, history list, inspector, ….\n * Pass it to the shell's `rightPanel` slot, or place it after the main content\n * inside a `relative` flex row:\n *\n * ```tsx\n * <div className=\"relative flex flex-1 min-h-0\">\n * <main className=\"flex-1 min-w-0\">…</main>\n * <DataAppShellRightPanel id=\"chat\" open={open} onOpenChange={setOpen} title=\"Chat\">\n * …\n * </DataAppShellRightPanel>\n * </div>\n * ```\n */\nfunction DataAppShellRightPanel({\n id,\n open,\n onOpenChange,\n variant = \"docked\",\n surface = \"raised\",\n resizable = true,\n defaultWidth = 320,\n minWidth = 240,\n maxWidth = 560,\n persist = true,\n title,\n icon,\n headerActions,\n showTrigger = true,\n triggerIcon,\n triggerLabel = \"Open panel\",\n triggerRef,\n children,\n className,\n ref,\n ...props\n}: DataAppShellRightPanelProps) {\n const [width, setWidth] = React.useState<number>(() =>\n persist ? readWidth(id, defaultWidth, minWidth, maxWidth) : clampWidth(defaultWidth, minWidth, maxWidth),\n );\n const [dragging, setDragging] = React.useState(false);\n\n const closeButtonRef = React.useRef<HTMLButtonElement>(null);\n const fabRef = React.useRef<HTMLButtonElement>(null);\n // Focus lands on the built-in FAB when it renders, else on the external trigger.\n const closeFocusRef = showTrigger ? fabRef : triggerRef;\n\n const commitWidth = React.useCallback(\n (next: number) => {\n if (persist) persistWidth(id, next);\n },\n [id, persist],\n );\n\n // Focus follows the open state: into the panel on open, back to the FAB on\n // close — but only on actual transitions, not on mount.\n const mountedRef = React.useRef(false);\n React.useEffect(() => {\n if (!mountedRef.current) {\n mountedRef.current = true;\n return;\n }\n // preventScroll — plain .focus() scrolls the target into view, which\n // jolts any scrollable ancestor (e.g. a Storybook docs page) on toggle.\n if (open) closeButtonRef.current?.focus({ preventScroll: true });\n else closeFocusRef?.current?.focus({ preventScroll: true });\n }, [open, closeFocusRef]);\n\n const accessibleName = typeof title === \"string\" ? title : \"Side panel\";\n\n const raised = surface === \"raised\";\n // `bg-card` is raised in both themes (`--surface-bright`); `bg-background` is\n // the page ground (the legacy, indistinct look).\n const surfaceClass = raised ? \"bg-card\" : \"bg-background\";\n // Raised panels get a tinted header cap so the top of the panel brands it;\n // flat panels keep the plain bordered header.\n const headerClass = raised ? \"border-b border-primary/15 bg-accent\" : \"border-b border-border\";\n\n const fab = showTrigger ? (\n <DataAppShellRightPanelTrigger\n ref={fabRef}\n aria-label={triggerLabel}\n aria-expanded={false}\n onClick={() => onOpenChange?.(true)}\n >\n {triggerIcon}\n </DataAppShellRightPanelTrigger>\n ) : null;\n\n const header = (\n <div\n data-slot=\"data-app-shell-right-panel-header\"\n className={cn(\"flex shrink-0 items-center gap-2 px-3 py-2\", headerClass)}\n >\n {icon != null && <span className=\"flex shrink-0 items-center justify-center\">{icon}</span>}\n {title != null && <span className=\"min-w-0 flex-1 truncate text-sm font-semibold text-foreground\">{title}</span>}\n {title == null && <span className=\"flex-1\" />}\n {headerActions}\n <Button\n ref={closeButtonRef}\n variant=\"ghost\"\n size=\"icon-sm\"\n className=\"text-muted-foreground\"\n aria-label=\"Close panel\"\n onClick={() => onOpenChange?.(false)}\n >\n <X />\n </Button>\n </div>\n );\n\n const content = (\n <div data-slot=\"data-app-shell-right-panel-content\" className=\"flex min-h-0 flex-1 flex-col overflow-auto\">\n {children}\n </div>\n );\n\n // Overlay — reuse the design-system Sheet: scrim, slide-in, Esc/click-out\n // close and focus trapping all come from the primitive. No reflow of main.\n if (variant === \"overlay\") {\n return (\n <>\n <Sheet open={open} onOpenChange={onOpenChange}>\n <SheetContent\n side=\"right\"\n showCloseButton={false}\n data-slot=\"data-app-shell-right-panel\"\n data-variant=\"overlay\"\n // The FAB remounts on close, so radix's default \"restore previous\n // focus\" targets a dead node — send focus to the new FAB instead.\n onCloseAutoFocus={(e) => {\n e.preventDefault();\n closeFocusRef?.current?.focus({ preventScroll: true });\n }}\n style={{ width }}\n // Sheet defaults to bg-background — override so the overlay variant\n // matches the docked variant's surface (SW-2592).\n className={cn(\"gap-0 data-[side=right]:sm:max-w-none\", surfaceClass, className)}\n {...props}\n >\n <SheetTitle className=\"sr-only\">{accessibleName}</SheetTitle>\n <SheetDescription className=\"sr-only\">Side panel overlay</SheetDescription>\n {header}\n {content}\n </SheetContent>\n </Sheet>\n {!open && fab}\n </>\n );\n }\n\n if (!open) return fab;\n\n return (\n <aside\n ref={ref}\n data-slot=\"data-app-shell-right-panel\"\n data-variant=\"docked\"\n aria-label={accessibleName}\n style={{ width }}\n className={cn(\n \"relative flex h-full shrink-0 flex-col overflow-hidden border-l border-border\",\n surfaceClass,\n \"motion-safe:animate-in motion-safe:fade-in-0 motion-safe:slide-in-from-right-4\",\n !dragging && \"motion-safe:transition-[width] motion-safe:duration-200\",\n className,\n )}\n onKeyDown={(e) => {\n if (e.key === \"Escape\") onOpenChange?.(false);\n }}\n {...props}\n >\n {resizable && (\n <DragHandle\n width={width}\n minWidth={minWidth}\n maxWidth={maxWidth}\n onResize={setWidth}\n onCommit={commitWidth}\n onDraggingChange={setDragging}\n />\n )}\n\n {header}\n {content}\n </aside>\n );\n}\n\nexport { DataAppShellRightPanel, DataAppShellRightPanelTrigger, dataAppShellRightPanelTriggerVariants };\n"],"names":["STORAGE_PREFIX","storageKey","id","clampWidth","width","min","max","readWidth","fallback","v","persistWidth","dataAppShellRightPanelTriggerVariants","cva","DataAppShellRightPanelTrigger","className","variant","size","asChild","children","props","Comp","Slot","jsx","cn","PanelRightOpen","KEYBOARD_RESIZE_STEP","DragHandle","minWidth","maxWidth","onResize","onCommit","onDraggingChange","dragState","React","widthRef","handlePointerDown","e","handlePointerMove","delta","next","endDrag","finalWidth","handleKeyDown","DataAppShellRightPanel","open","onOpenChange","surface","resizable","defaultWidth","persist","title","icon","headerActions","showTrigger","triggerIcon","triggerLabel","triggerRef","ref","setWidth","dragging","setDragging","closeButtonRef","fabRef","closeFocusRef","commitWidth","mountedRef","accessibleName","raised","surfaceClass","headerClass","fab","header","jsxs","Button","X","content","Fragment","Sheet","SheetContent","SheetTitle","SheetDescription"],"mappings":"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"}
|
|
@@ -38,6 +38,16 @@ export interface DataAppShellRightPanelProps extends Omit<React.ComponentProps<"
|
|
|
38
38
|
* `overlay` — reuses the design-system `Sheet`: slides in over content with a scrim, no reflow.
|
|
39
39
|
*/
|
|
40
40
|
variant?: DataAppShellRightPanelVariant;
|
|
41
|
+
/**
|
|
42
|
+
* Panel surface (SW-2592):
|
|
43
|
+
* - `raised` (default) — a `bg-card` surface distinct from the page ground, with
|
|
44
|
+
* a tinted (`bg-accent`) header cap. Reads as a surface *on* the page, not a
|
|
45
|
+
* column *of* it. `bg-card` is the only surface token that stays raised in both
|
|
46
|
+
* light and dark (`bg-sidebar` collapses to the body colour in dark).
|
|
47
|
+
* - `flat` — the legacy look: `bg-background` body and a plain bordered header,
|
|
48
|
+
* for a panel that should read as part of the page ground.
|
|
49
|
+
*/
|
|
50
|
+
surface?: "raised" | "flat";
|
|
41
51
|
/** Show the drag handle and allow resizing. Defaults to `true`. Docked only — the overlay has a fixed width. */
|
|
42
52
|
resizable?: boolean;
|
|
43
53
|
/** Width in px when nothing is persisted yet. */
|
|
@@ -91,5 +101,5 @@ export interface DataAppShellRightPanelProps extends Omit<React.ComponentProps<"
|
|
|
91
101
|
* </div>
|
|
92
102
|
* ```
|
|
93
103
|
*/
|
|
94
|
-
declare function DataAppShellRightPanel({ id, open, onOpenChange, variant, resizable, defaultWidth, minWidth, maxWidth, persist, title, icon, headerActions, showTrigger, triggerIcon, triggerLabel, triggerRef, children, className, ref, ...props }: DataAppShellRightPanelProps): import("react/jsx-runtime").JSX.Element | null;
|
|
104
|
+
declare function DataAppShellRightPanel({ id, open, onOpenChange, variant, surface, resizable, defaultWidth, minWidth, maxWidth, persist, title, icon, headerActions, showTrigger, triggerIcon, triggerLabel, triggerRef, children, className, ref, ...props }: DataAppShellRightPanelProps): import("react/jsx-runtime").JSX.Element | null;
|
|
95
105
|
export { DataAppShellRightPanel, DataAppShellRightPanelTrigger, dataAppShellRightPanelTriggerVariants };
|
|
@@ -1,36 +1,36 @@
|
|
|
1
|
-
import { jsxs as
|
|
2
|
-
import { cva as
|
|
3
|
-
import {
|
|
4
|
-
import { Slot as
|
|
1
|
+
import { jsxs as w, jsx as n, Fragment as L } from "react/jsx-runtime";
|
|
2
|
+
import { cva as O } from "class-variance-authority";
|
|
3
|
+
import { X as U, PanelRightOpen as Y } from "lucide-react";
|
|
4
|
+
import { Slot as Z } from "radix-ui";
|
|
5
5
|
import * as u from "react";
|
|
6
|
-
import { Button as
|
|
7
|
-
import { Sheet as
|
|
8
|
-
import { cn as
|
|
9
|
-
const
|
|
10
|
-
function
|
|
11
|
-
return `${
|
|
6
|
+
import { Button as q } from "../../../ui/button.js";
|
|
7
|
+
import { Sheet as J, SheetContent as Q, SheetTitle as W, SheetDescription as ee } from "../../../ui/sheet.js";
|
|
8
|
+
import { cn as m } from "../../../lib/utils.js";
|
|
9
|
+
const te = "ts-ui.right-panel";
|
|
10
|
+
function M(t) {
|
|
11
|
+
return `${te}.${t}.width`;
|
|
12
12
|
}
|
|
13
|
-
function
|
|
14
|
-
return Math.min(
|
|
13
|
+
function b(t, e, r) {
|
|
14
|
+
return Math.min(r, Math.max(e, t));
|
|
15
15
|
}
|
|
16
|
-
function
|
|
16
|
+
function re(t, e, r, l) {
|
|
17
17
|
if (typeof window > "u") return e;
|
|
18
|
-
let
|
|
18
|
+
let i;
|
|
19
19
|
try {
|
|
20
|
-
|
|
20
|
+
i = Number(window.localStorage.getItem(M(t)));
|
|
21
21
|
} catch {
|
|
22
22
|
return e;
|
|
23
23
|
}
|
|
24
|
-
return !Number.isFinite(
|
|
24
|
+
return !Number.isFinite(i) || i <= 0 ? e : b(i, r, l);
|
|
25
25
|
}
|
|
26
|
-
function
|
|
26
|
+
function ae(t, e) {
|
|
27
27
|
if (!(typeof window > "u"))
|
|
28
28
|
try {
|
|
29
|
-
window.localStorage.setItem(
|
|
29
|
+
window.localStorage.setItem(M(t), String(Math.round(e)));
|
|
30
30
|
} catch {
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
|
-
const
|
|
33
|
+
const ne = O(
|
|
34
34
|
"inline-flex items-center justify-center border-none cursor-pointer transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
35
35
|
{
|
|
36
36
|
variants: {
|
|
@@ -54,67 +54,67 @@ const ee = H(
|
|
|
54
54
|
defaultVariants: { variant: "fab", size: "default" }
|
|
55
55
|
}
|
|
56
56
|
);
|
|
57
|
-
function
|
|
57
|
+
function oe({
|
|
58
58
|
className: t,
|
|
59
59
|
variant: e,
|
|
60
|
-
size:
|
|
60
|
+
size: r,
|
|
61
61
|
asChild: l = !1,
|
|
62
|
-
children:
|
|
63
|
-
...
|
|
62
|
+
children: i,
|
|
63
|
+
...d
|
|
64
64
|
}) {
|
|
65
|
-
const
|
|
66
|
-
return /* @__PURE__ */
|
|
67
|
-
|
|
65
|
+
const s = l ? Z.Root : "button";
|
|
66
|
+
return /* @__PURE__ */ n(
|
|
67
|
+
s,
|
|
68
68
|
{
|
|
69
69
|
...l ? {} : { type: "button" },
|
|
70
70
|
"data-slot": "data-app-shell-right-panel-trigger",
|
|
71
71
|
"data-variant": e ?? "fab",
|
|
72
|
-
className:
|
|
73
|
-
...
|
|
74
|
-
children: l ?
|
|
72
|
+
className: m(ne({ variant: e, size: r }), t),
|
|
73
|
+
...d,
|
|
74
|
+
children: l ? i : i ?? /* @__PURE__ */ n(Y, {})
|
|
75
75
|
}
|
|
76
76
|
);
|
|
77
77
|
}
|
|
78
|
-
const
|
|
79
|
-
function
|
|
80
|
-
const
|
|
78
|
+
const _ = 16;
|
|
79
|
+
function se({ width: t, minWidth: e, maxWidth: r, onResize: l, onCommit: i, onDraggingChange: d }) {
|
|
80
|
+
const s = u.useRef(null), c = u.useRef(t);
|
|
81
81
|
c.current = t;
|
|
82
|
-
const g = (
|
|
83
|
-
if (
|
|
84
|
-
|
|
82
|
+
const g = (a) => {
|
|
83
|
+
if (a.button === 0) {
|
|
84
|
+
s.current = { startX: a.clientX, startWidth: c.current, liveWidth: c.current };
|
|
85
85
|
try {
|
|
86
|
-
|
|
86
|
+
a.currentTarget.setPointerCapture(a.pointerId);
|
|
87
87
|
} catch {
|
|
88
88
|
}
|
|
89
|
-
|
|
89
|
+
d(!0);
|
|
90
90
|
}
|
|
91
|
-
},
|
|
92
|
-
if (!
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
},
|
|
96
|
-
if (!
|
|
97
|
-
const
|
|
98
|
-
|
|
99
|
-
},
|
|
100
|
-
let
|
|
101
|
-
switch (
|
|
91
|
+
}, p = (a) => {
|
|
92
|
+
if (!s.current) return;
|
|
93
|
+
const o = s.current.startX - a.clientX, y = b(s.current.startWidth + o, e, r);
|
|
94
|
+
s.current.liveWidth = y, l(y);
|
|
95
|
+
}, f = (a) => {
|
|
96
|
+
if (!s.current) return;
|
|
97
|
+
const o = s.current.liveWidth;
|
|
98
|
+
s.current = null, a.currentTarget.hasPointerCapture(a.pointerId) && a.currentTarget.releasePointerCapture(a.pointerId), d(!1), i(o);
|
|
99
|
+
}, v = (a) => {
|
|
100
|
+
let o = null;
|
|
101
|
+
switch (a.key) {
|
|
102
102
|
case "ArrowLeft":
|
|
103
|
-
|
|
103
|
+
o = b(c.current + _, e, r);
|
|
104
104
|
break;
|
|
105
105
|
case "ArrowRight":
|
|
106
|
-
|
|
106
|
+
o = b(c.current - _, e, r);
|
|
107
107
|
break;
|
|
108
108
|
case "Home":
|
|
109
|
-
|
|
109
|
+
o = e;
|
|
110
110
|
break;
|
|
111
111
|
case "End":
|
|
112
|
-
|
|
112
|
+
o = r;
|
|
113
113
|
break;
|
|
114
114
|
}
|
|
115
|
-
|
|
115
|
+
o != null && (a.preventDefault(), l(o), i(o));
|
|
116
116
|
};
|
|
117
|
-
return /* @__PURE__ */
|
|
117
|
+
return /* @__PURE__ */ n(
|
|
118
118
|
"div",
|
|
119
119
|
{
|
|
120
120
|
"data-slot": "data-app-shell-right-panel-drag-handle",
|
|
@@ -122,10 +122,10 @@ function re({ width: t, minWidth: e, maxWidth: n, onResize: l, onCommit: s, onDr
|
|
|
122
122
|
"aria-orientation": "vertical",
|
|
123
123
|
"aria-label": "Resize panel",
|
|
124
124
|
"aria-valuemin": e,
|
|
125
|
-
"aria-valuemax":
|
|
125
|
+
"aria-valuemax": r,
|
|
126
126
|
"aria-valuenow": Math.round(t),
|
|
127
127
|
tabIndex: 0,
|
|
128
|
-
className:
|
|
128
|
+
className: m(
|
|
129
129
|
// 1px seam over the panel's left border; wide invisible grab area via ::after
|
|
130
130
|
"absolute inset-y-0 left-0 z-10 w-px cursor-col-resize touch-none select-none bg-transparent transition-colors",
|
|
131
131
|
"after:absolute after:inset-y-0 after:left-1/2 after:w-3 after:-translate-x-1/2",
|
|
@@ -136,43 +136,44 @@ function re({ width: t, minWidth: e, maxWidth: n, onResize: l, onCommit: s, onDr
|
|
|
136
136
|
"[&>div]:opacity-0 hover:[&>div]:opacity-100 active:[&>div]:opacity-100 focus-visible:[&>div]:opacity-100"
|
|
137
137
|
),
|
|
138
138
|
onPointerDown: g,
|
|
139
|
-
onPointerMove:
|
|
140
|
-
onPointerUp:
|
|
141
|
-
onPointerCancel:
|
|
142
|
-
onKeyDown:
|
|
143
|
-
children: /* @__PURE__ */
|
|
139
|
+
onPointerMove: p,
|
|
140
|
+
onPointerUp: f,
|
|
141
|
+
onPointerCancel: f,
|
|
142
|
+
onKeyDown: v,
|
|
143
|
+
children: /* @__PURE__ */ n("div", { className: "z-10 h-6 w-1 shrink-0 rounded-lg bg-muted-foreground/40 transition-opacity" })
|
|
144
144
|
}
|
|
145
145
|
);
|
|
146
146
|
}
|
|
147
|
-
function
|
|
147
|
+
function pe({
|
|
148
148
|
id: t,
|
|
149
149
|
open: e,
|
|
150
|
-
onOpenChange:
|
|
150
|
+
onOpenChange: r,
|
|
151
151
|
variant: l = "docked",
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
152
|
+
surface: i = "raised",
|
|
153
|
+
resizable: d = !0,
|
|
154
|
+
defaultWidth: s = 320,
|
|
155
|
+
minWidth: c = 240,
|
|
156
|
+
maxWidth: g = 560,
|
|
157
|
+
persist: p = !0,
|
|
158
|
+
title: f,
|
|
159
|
+
icon: v,
|
|
160
|
+
headerActions: a,
|
|
161
|
+
showTrigger: o = !0,
|
|
162
|
+
triggerIcon: y,
|
|
163
|
+
triggerLabel: X = "Open panel",
|
|
164
|
+
triggerRef: j,
|
|
165
|
+
children: F,
|
|
165
166
|
className: R,
|
|
166
|
-
ref:
|
|
167
|
+
ref: K,
|
|
167
168
|
...S
|
|
168
169
|
}) {
|
|
169
|
-
const [x,
|
|
170
|
-
() =>
|
|
171
|
-
), [
|
|
170
|
+
const [x, B] = u.useState(
|
|
171
|
+
() => p ? re(t, s, c, g) : b(s, c, g)
|
|
172
|
+
), [V, H] = u.useState(!1), k = u.useRef(null), N = u.useRef(null), z = o ? N : j, $ = u.useCallback(
|
|
172
173
|
(h) => {
|
|
173
|
-
|
|
174
|
+
p && ae(t, h);
|
|
174
175
|
},
|
|
175
|
-
[t,
|
|
176
|
+
[t, p]
|
|
176
177
|
), P = u.useRef(!1);
|
|
177
178
|
u.useEffect(() => {
|
|
178
179
|
if (!P.current) {
|
|
@@ -181,43 +182,43 @@ function ue({
|
|
|
181
182
|
}
|
|
182
183
|
e ? k.current?.focus({ preventScroll: !0 }) : z?.current?.focus({ preventScroll: !0 });
|
|
183
184
|
}, [e, z]);
|
|
184
|
-
const D = typeof
|
|
185
|
-
|
|
185
|
+
const D = typeof f == "string" ? f : "Side panel", C = i === "raised", E = C ? "bg-card" : "bg-background", G = C ? "border-b border-primary/15 bg-accent" : "border-b border-border", A = o ? /* @__PURE__ */ n(
|
|
186
|
+
oe,
|
|
186
187
|
{
|
|
187
188
|
ref: N,
|
|
188
|
-
"aria-label":
|
|
189
|
+
"aria-label": X,
|
|
189
190
|
"aria-expanded": !1,
|
|
190
|
-
onClick: () =>
|
|
191
|
-
children:
|
|
191
|
+
onClick: () => r?.(!0),
|
|
192
|
+
children: y
|
|
192
193
|
}
|
|
193
|
-
) : null,
|
|
194
|
+
) : null, I = /* @__PURE__ */ w(
|
|
194
195
|
"div",
|
|
195
196
|
{
|
|
196
197
|
"data-slot": "data-app-shell-right-panel-header",
|
|
197
|
-
className: "flex shrink-0 items-center gap-2
|
|
198
|
+
className: m("flex shrink-0 items-center gap-2 px-3 py-2", G),
|
|
198
199
|
children: [
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
/* @__PURE__ */
|
|
204
|
-
|
|
200
|
+
v != null && /* @__PURE__ */ n("span", { className: "flex shrink-0 items-center justify-center", children: v }),
|
|
201
|
+
f != null && /* @__PURE__ */ n("span", { className: "min-w-0 flex-1 truncate text-sm font-semibold text-foreground", children: f }),
|
|
202
|
+
f == null && /* @__PURE__ */ n("span", { className: "flex-1" }),
|
|
203
|
+
a,
|
|
204
|
+
/* @__PURE__ */ n(
|
|
205
|
+
q,
|
|
205
206
|
{
|
|
206
207
|
ref: k,
|
|
207
208
|
variant: "ghost",
|
|
208
209
|
size: "icon-sm",
|
|
209
210
|
className: "text-muted-foreground",
|
|
210
211
|
"aria-label": "Close panel",
|
|
211
|
-
onClick: () =>
|
|
212
|
-
children: /* @__PURE__ */
|
|
212
|
+
onClick: () => r?.(!1),
|
|
213
|
+
children: /* @__PURE__ */ n(U, {})
|
|
213
214
|
}
|
|
214
215
|
)
|
|
215
216
|
]
|
|
216
217
|
}
|
|
217
|
-
),
|
|
218
|
-
return l === "overlay" ? /* @__PURE__ */
|
|
219
|
-
/* @__PURE__ */
|
|
220
|
-
|
|
218
|
+
), T = /* @__PURE__ */ n("div", { "data-slot": "data-app-shell-right-panel-content", className: "flex min-h-0 flex-1 flex-col overflow-auto", children: F });
|
|
219
|
+
return l === "overlay" ? /* @__PURE__ */ w(L, { children: [
|
|
220
|
+
/* @__PURE__ */ n(J, { open: e, onOpenChange: r, children: /* @__PURE__ */ w(
|
|
221
|
+
Q,
|
|
221
222
|
{
|
|
222
223
|
side: "right",
|
|
223
224
|
showCloseButton: !1,
|
|
@@ -227,56 +228,57 @@ function ue({
|
|
|
227
228
|
h.preventDefault(), z?.current?.focus({ preventScroll: !0 });
|
|
228
229
|
},
|
|
229
230
|
style: { width: x },
|
|
230
|
-
className:
|
|
231
|
+
className: m("gap-0 data-[side=right]:sm:max-w-none", E, R),
|
|
231
232
|
...S,
|
|
232
233
|
children: [
|
|
233
|
-
/* @__PURE__ */
|
|
234
|
-
/* @__PURE__ */
|
|
235
|
-
|
|
236
|
-
|
|
234
|
+
/* @__PURE__ */ n(W, { className: "sr-only", children: D }),
|
|
235
|
+
/* @__PURE__ */ n(ee, { className: "sr-only", children: "Side panel overlay" }),
|
|
236
|
+
I,
|
|
237
|
+
T
|
|
237
238
|
]
|
|
238
239
|
}
|
|
239
240
|
) }),
|
|
240
|
-
!e &&
|
|
241
|
-
] }) : e ? /* @__PURE__ */
|
|
241
|
+
!e && A
|
|
242
|
+
] }) : e ? /* @__PURE__ */ w(
|
|
242
243
|
"aside",
|
|
243
244
|
{
|
|
244
|
-
ref:
|
|
245
|
+
ref: K,
|
|
245
246
|
"data-slot": "data-app-shell-right-panel",
|
|
246
247
|
"data-variant": "docked",
|
|
247
248
|
"aria-label": D,
|
|
248
249
|
style: { width: x },
|
|
249
|
-
className:
|
|
250
|
-
"relative flex h-full shrink-0 flex-col overflow-hidden border-l border-border
|
|
250
|
+
className: m(
|
|
251
|
+
"relative flex h-full shrink-0 flex-col overflow-hidden border-l border-border",
|
|
252
|
+
E,
|
|
251
253
|
"motion-safe:animate-in motion-safe:fade-in-0 motion-safe:slide-in-from-right-4",
|
|
252
|
-
!
|
|
254
|
+
!V && "motion-safe:transition-[width] motion-safe:duration-200",
|
|
253
255
|
R
|
|
254
256
|
),
|
|
255
257
|
onKeyDown: (h) => {
|
|
256
|
-
h.key === "Escape" &&
|
|
258
|
+
h.key === "Escape" && r?.(!1);
|
|
257
259
|
},
|
|
258
260
|
...S,
|
|
259
261
|
children: [
|
|
260
|
-
|
|
261
|
-
|
|
262
|
+
d && /* @__PURE__ */ n(
|
|
263
|
+
se,
|
|
262
264
|
{
|
|
263
265
|
width: x,
|
|
264
|
-
minWidth:
|
|
265
|
-
maxWidth:
|
|
266
|
-
onResize:
|
|
267
|
-
onCommit:
|
|
268
|
-
onDraggingChange:
|
|
266
|
+
minWidth: c,
|
|
267
|
+
maxWidth: g,
|
|
268
|
+
onResize: B,
|
|
269
|
+
onCommit: $,
|
|
270
|
+
onDraggingChange: H
|
|
269
271
|
}
|
|
270
272
|
),
|
|
271
|
-
|
|
272
|
-
|
|
273
|
+
I,
|
|
274
|
+
T
|
|
273
275
|
]
|
|
274
276
|
}
|
|
275
|
-
) :
|
|
277
|
+
) : A;
|
|
276
278
|
}
|
|
277
279
|
export {
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
280
|
+
pe as DataAppShellRightPanel,
|
|
281
|
+
oe as DataAppShellRightPanelTrigger,
|
|
282
|
+
ne as dataAppShellRightPanelTriggerVariants
|
|
281
283
|
};
|
|
282
284
|
//# sourceMappingURL=RightPanel.js.map
|