@nocoo/basalt 3.2.0 → 3.2.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/ai/DESIGN.md +20 -9
- package/ai/INTEGRATION.md +9 -9
- package/ai/USAGE.md +1 -1
- package/ai/registry.json +73 -73
- package/dist/charts/frame.js +2 -2
- package/dist/charts/frame.js.map +1 -1
- package/dist/charts/heatmap-calendar.js +4 -4
- package/dist/charts/heatmap-calendar.js.map +1 -1
- package/dist/charts/heatmap-matrix.js +3 -3
- package/dist/charts/heatmap-matrix.js.map +1 -1
- package/dist/components/app-header.js +1 -1
- package/dist/components/app-header.js.map +1 -1
- package/dist/components/app-shell.js +1 -1
- package/dist/components/app-shell.js.map +1 -1
- package/dist/components/chat-composer.js +1 -1
- package/dist/components/chat-composer.js.map +1 -1
- package/dist/components/chat-message.js +1 -1
- package/dist/components/chat-message.js.map +1 -1
- package/dist/components/code.js +1 -1
- package/dist/components/code.js.map +1 -1
- package/dist/components/command-palette.js +2 -2
- package/dist/components/command-palette.js.map +1 -1
- package/dist/components/context-cards.js +1 -1
- package/dist/components/context-cards.js.map +1 -1
- package/dist/components/context-menu.js +1 -1
- package/dist/components/context-menu.js.map +1 -1
- package/dist/components/data-table.js +127 -124
- package/dist/components/data-table.js.map +1 -1
- package/dist/components/diff-table.js +1 -1
- package/dist/components/diff-table.js.map +1 -1
- package/dist/components/dropdown-menu.js +1 -1
- package/dist/components/dropdown-menu.js.map +1 -1
- package/dist/components/editable-nav-item.js +2 -2
- package/dist/components/editable-nav-item.js.map +1 -1
- package/dist/components/file-dropzone.js +1 -1
- package/dist/components/file-dropzone.js.map +1 -1
- package/dist/components/filter-bar.js +1 -1
- package/dist/components/filter-bar.js.map +1 -1
- package/dist/components/icon-picker.js +3 -3
- package/dist/components/icon-picker.js.map +1 -1
- package/dist/components/inline-editable.js +1 -1
- package/dist/components/inline-editable.js.map +1 -1
- package/dist/components/input-group.js +2 -2
- package/dist/components/input-group.js.map +1 -1
- package/dist/components/layer-card.js +2 -1
- package/dist/components/layer-card.js.map +1 -1
- package/dist/components/link.js +1 -1
- package/dist/components/link.js.map +1 -1
- package/dist/components/menu-bar.js +2 -2
- package/dist/components/menu-bar.js.map +1 -1
- package/dist/components/multi-select.js +1 -1
- package/dist/components/multi-select.js.map +1 -1
- package/dist/components/overlay.d.ts +3 -6
- package/dist/components/overlay.js +3 -3
- package/dist/components/overlay.js.map +1 -1
- package/dist/components/responsive-master-detail.js +2 -2
- package/dist/components/responsive-master-detail.js.map +1 -1
- package/dist/components/scroll-area.js +1 -1
- package/dist/components/scroll-area.js.map +1 -1
- package/dist/components/segment-control.js +1 -1
- package/dist/components/segment-control.js.map +1 -1
- package/dist/components/select.js +1 -1
- package/dist/components/select.js.map +1 -1
- package/dist/components/sensitive-input.js +1 -1
- package/dist/components/sensitive-input.js.map +1 -1
- package/dist/components/sidebar.js +1 -1
- package/dist/components/sidebar.js.map +1 -1
- package/dist/components/table.js +1 -1
- package/dist/components/table.js.map +1 -1
- package/dist/components/tabs.js +1 -1
- package/dist/components/tabs.js.map +1 -1
- package/dist/components/tag-color-picker.js +2 -2
- package/dist/components/tag-color-picker.js.map +1 -1
- package/dist/components/toast.js +1 -1
- package/dist/components/toast.js.map +1 -1
- package/dist/components/toolbar.js +8 -8
- package/dist/components/toolbar.js.map +1 -1
- package/dist/styles/base.css +71 -0
- package/dist/styles/standalone.css +72 -87
- package/dist/styles/tailwind.css +8 -2
- package/dist/styles/tokens.css +4 -1
- package/dist/utils/navigation.d.ts +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sidebar.js","names":["DialogPrimitive","SidebarContext","createContext","useSidebar","context","useContext","SidebarProvider","uncontrolled","setUncontrolled","useState","defaultCollapsed","peeking","setPeeking","width","setWidthState","clampSidebarWidth","defaultWidth","setWidth","useCallback","next","lastFocusRef","useRef","prevCollapsed","collapsed","prevOverlay","overlay","resolved","setCollapsed","onCollapsedChange","SidebarResize","cn","side","event","startX","startWidth","target","onMove","delta","move","onUp","dir","Sidebar","collapsedProp","props","body","SkeletonLine","children","resize","frameClass","BASALT_UI_CLASS","OVERLAY_MOTION","className","Dialog","open","DialogPortal","DialogOverlay","node","from","OVERLAY_LAYER","style","onMouseEnter","onMouseLeave","SIDEBAR_ROW_CLASS","SidebarHeader","SidebarSearch","NAV_ROW_CLASS","Search","shortcut","SidebarNav","highlightRef","useHoverHighlight","NAV_LIST_CLASS","SidebarPartition","SidebarItem","active","NAV_ITEM_CLASS","SidebarIconItem","SidebarGroup","setOpen","defaultOpen","Collapsible","CollapsibleTrigger","FOCUS_INSET","label","ChevronUp","CollapsibleContent","SidebarFooter","SidebarUser","avatar","name","email","action","ContentIsland","mobileSurface"],"sources":["../../src/components/sidebar.tsx"],"sourcesContent":["import * as DialogPrimitive from \"@radix-ui/react-dialog\";\nimport { ChevronUp, Search } from \"lucide-react\";\nimport {\n\ttype ButtonHTMLAttributes,\n\tcreateContext,\n\ttype HTMLAttributes,\n\ttype ReactNode,\n\ttype PointerEvent as ReactPointerEvent,\n\ttype RefObject,\n\tuseCallback,\n\tuseContext,\n\tuseLayoutEffect,\n\tuseRef,\n\tuseState,\n} from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { BASALT_UI_CLASS } from \"../utils/control-surface\";\nimport { NAV_ITEM_CLASS, NAV_LIST_CLASS, NAV_ROW_CLASS } from \"../utils/navigation\";\nimport { useHoverHighlight } from \"../utils/use-hover-highlight\";\nimport { Collapsible, CollapsibleContent, CollapsibleTrigger } from \"./collapsible\";\nimport { Dialog, DialogOverlay, DialogPortal } from \"./dialog\";\nimport { FOCUS_INSET, OVERLAY_LAYER, OVERLAY_MOTION } from \"./overlay\";\nimport { SkeletonLine } from \"./skeleton-line\";\n\nexport type SidebarSide = \"left\" | \"right\";\n\nexport interface SidebarContextValue {\n\t/**\n\t * Whether the sidebar is currently collapsed.\n\t */\n\tcollapsed: boolean;\n\t/**\n\t * Callback to update the collapsed state.\n\t */\n\tsetCollapsed: (next: boolean) => void;\n\t/**\n\t * Which edge the sidebar occupies.\n\t */\n\tside: SidebarSide;\n\t/**\n\t * Whether the sidebar is currently displaying a loading skeleton.\n\t */\n\tloading: boolean;\n\t/**\n\t * Whether the sidebar rail expands on pointer hover.\n\t */\n\tpeek: boolean;\n\t/**\n\t * Whether the sidebar is actively hovering in peek preview mode.\n\t */\n\tpeeking: boolean;\n\t/**\n\t * Callback to update the peek preview state.\n\t */\n\tsetPeeking: (next: boolean) => void;\n\t/**\n\t * Whether the sidebar is rendering as a modal overlay drawer instead of in-flow layout chrome.\n\t */\n\toverlay: boolean;\n\t/**\n\t * Current expanded width in pixels, clamped between 180 and 400.\n\t */\n\twidth: number;\n\t/**\n\t * Callback to update the sidebar width. Value is clamped between 180 and 400 pixels.\n\t */\n\tsetWidth: (next: number) => void;\n\t/**\n\t * Reference to the last active element that held focus before opening the sidebar drawer.\n\t */\n\tlastFocusRef: RefObject<HTMLElement | null>;\n}\n\nconst SidebarContext = createContext<SidebarContextValue | null>(null);\n\n/**\n * Accesses the sidebar context value. Must be used within a `SidebarProvider`; throws an error if called outside.\n * Returns the active sidebar state and control callbacks.\n */\nexport function useSidebar(): SidebarContextValue {\n\tconst context = useContext(SidebarContext);\n\tif (!context) {\n\t\tthrow new Error(\"useSidebar must be used within SidebarProvider\");\n\t}\n\treturn context;\n}\n\nexport type SidebarProviderProps = {\n\t/**\n\t * The controlled collapsed state.\n\t */\n\tcollapsed?: boolean;\n\t/**\n\t * The uncontrolled initial collapsed state.\n\t * @default false\n\t */\n\tdefaultCollapsed?: boolean;\n\t/**\n\t * Called when the collapsed state changes.\n\t */\n\tonCollapsedChange?: (collapsed: boolean) => void;\n\t/**\n\t * Which edge the sidebar occupies.\n\t * @default left\n\t */\n\tside?: SidebarSide;\n\t/**\n\t * Replace the nav with a loading skeleton.\n\t * @default false\n\t */\n\tloading?: boolean;\n\t/**\n\t * Expand the collapsed rail on hover.\n\t * @default false\n\t */\n\tpeek?: boolean;\n\t/**\n\t * Render as an overlay instead of in-flow chrome.\n\t * @default false\n\t */\n\toverlay?: boolean;\n\t/**\n\t * Initial expanded width in pixels, clamped between 180 and 400.\n\t * @default 260\n\t */\n\tdefaultWidth?: number;\n\t/**\n\t * Sidebar chrome and page content.\n\t */\n\tchildren: ReactNode;\n};\n\nexport function SidebarProvider({\n\tcollapsed,\n\tdefaultCollapsed = false,\n\tonCollapsedChange,\n\tside = \"left\",\n\tloading = false,\n\tpeek = false,\n\toverlay = false,\n\tdefaultWidth = 260,\n\tchildren,\n}: SidebarProviderProps) {\n\tconst [uncontrolled, setUncontrolled] = useState(defaultCollapsed);\n\tconst [peeking, setPeeking] = useState(false);\n\tconst [width, setWidthState] = useState(() => clampSidebarWidth(defaultWidth));\n\tconst setWidth = useCallback((next: number) => {\n\t\tsetWidthState(clampSidebarWidth(next));\n\t}, []);\n\tconst lastFocusRef = useRef<HTMLElement | null>(null);\n\tconst prevCollapsed = useRef(collapsed ?? defaultCollapsed);\n\tconst prevOverlay = useRef(overlay);\n\tconst resolved = collapsed ?? uncontrolled;\n\tuseLayoutEffect(() => {\n\t\tif (\n\t\t\toverlay &&\n\t\t\t!resolved &&\n\t\t\t(prevCollapsed.current || !prevOverlay.current) &&\n\t\t\tdocument.activeElement instanceof HTMLElement\n\t\t) {\n\t\t\tlastFocusRef.current = document.activeElement;\n\t\t}\n\t\tprevCollapsed.current = resolved;\n\t\tprevOverlay.current = overlay;\n\t});\n\tconst setCollapsed = useCallback(\n\t\t(next: boolean) => {\n\t\t\tif (!next && document.activeElement instanceof HTMLElement) {\n\t\t\t\tlastFocusRef.current = document.activeElement;\n\t\t\t}\n\t\t\tif (collapsed === undefined) {\n\t\t\t\tsetUncontrolled(next);\n\t\t\t}\n\t\t\tonCollapsedChange?.(next);\n\t\t},\n\t\t[collapsed, onCollapsedChange],\n\t);\n\treturn (\n\t\t<SidebarContext.Provider\n\t\t\tvalue={{\n\t\t\t\tcollapsed: resolved,\n\t\t\t\tsetCollapsed,\n\t\t\t\tside,\n\t\t\t\tloading,\n\t\t\t\tpeek,\n\t\t\t\tpeeking,\n\t\t\t\tsetPeeking,\n\t\t\t\toverlay,\n\t\t\t\twidth,\n\t\t\t\tsetWidth,\n\t\t\t\tlastFocusRef,\n\t\t\t}}\n\t\t>\n\t\t\t{children}\n\t\t</SidebarContext.Provider>\n\t);\n}\n\nexport type SidebarProps = HTMLAttributes<HTMLElement> & {\n\t/**\n\t * Collapse the rail when no provider is present.\n\t * @default false\n\t */\n\tcollapsed?: boolean;\n};\n\nfunction clampSidebarWidth(next: number) {\n\treturn Math.min(400, Math.max(180, next));\n}\n\nfunction SidebarResize({\n\tside,\n\twidth,\n\tonWidth,\n}: {\n\tside: SidebarSide;\n\twidth: number;\n\tonWidth: (next: number) => void;\n}) {\n\tconst onPointerDown = (event: ReactPointerEvent<HTMLDivElement>) => {\n\t\tevent.preventDefault();\n\t\tevent.currentTarget.setPointerCapture(event.pointerId);\n\t\tconst startX = event.clientX;\n\t\tconst startWidth = width;\n\t\tconst target = event.currentTarget;\n\t\tconst onMove = (move: PointerEvent) => {\n\t\t\tconst delta = side === \"right\" ? startX - move.clientX : move.clientX - startX;\n\t\t\tonWidth(clampSidebarWidth(startWidth + delta));\n\t\t};\n\t\tconst onUp = () => {\n\t\t\ttarget.removeEventListener(\"pointermove\", onMove);\n\t\t\ttarget.removeEventListener(\"pointerup\", onUp);\n\t\t\ttarget.removeEventListener(\"pointercancel\", onUp);\n\t\t};\n\t\ttarget.addEventListener(\"pointermove\", onMove);\n\t\ttarget.addEventListener(\"pointerup\", onUp);\n\t\ttarget.addEventListener(\"pointercancel\", onUp);\n\t};\n\treturn (\n\t\t<div\n\t\t\trole=\"separator\"\n\t\t\taria-orientation=\"vertical\"\n\t\t\taria-valuenow={width}\n\t\t\taria-valuemin={180}\n\t\t\taria-valuemax={400}\n\t\t\taria-label=\"Resize sidebar\"\n\t\t\ttabIndex={0}\n\t\t\tclassName={cn(\n\t\t\t\t\"absolute top-0 h-full w-basalt-1 cursor-col-resize bg-transparent\",\n\t\t\t\tside === \"right\" ? \"left-0\" : \"right-0\",\n\t\t\t)}\n\t\t\tonPointerDown={onPointerDown}\n\t\t\tonKeyDown={(event) => {\n\t\t\t\tif (event.key !== \"ArrowLeft\" && event.key !== \"ArrowRight\") {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tevent.preventDefault();\n\t\t\t\tconst dir = event.key === \"ArrowRight\" ? 1 : -1;\n\t\t\t\tconst delta = side === \"right\" ? -dir * 8 : dir * 8;\n\t\t\t\tonWidth(clampSidebarWidth(width + delta));\n\t\t\t}}\n\t\t/>\n\t);\n}\n\nexport function Sidebar({\n\tcollapsed: collapsedProp,\n\tclassName,\n\tchildren,\n\tonMouseEnter,\n\tonMouseLeave,\n\tstyle,\n\t...props\n}: SidebarProps) {\n\tconst context = useContext(SidebarContext);\n\tconst collapsed = context\n\t\t? context.collapsed && !(context.peek && context.peeking)\n\t\t: (collapsedProp ?? false);\n\tconst side = context?.side ?? \"left\";\n\tconst overlay = context?.overlay ?? false;\n\tconst width = context?.width ?? 260;\n\tconst body = context?.loading ? (\n\t\t<div\n\t\t\tclassName=\"flex flex-col gap-basalt-space-lg p-basalt-space-lg\"\n\t\t\trole=\"status\"\n\t\t\taria-live=\"polite\"\n\t\t>\n\t\t\t<SkeletonLine />\n\t\t\t<SkeletonLine />\n\t\t\t<SkeletonLine />\n\t\t</div>\n\t) : (\n\t\tchildren\n\t);\n\tconst resize =\n\t\tcontext && !collapsed ? (\n\t\t\t<SidebarResize side={side} width={context.width} onWidth={context.setWidth} />\n\t\t) : null;\n\tconst frameClass = cn(\n\t\tBASALT_UI_CLASS,\n\t\t\"relative flex shrink-0 flex-col bg-basalt-background text-basalt-base text-basalt-foreground\",\n\t\tOVERLAY_MOTION,\n\t\tclassName,\n\t);\n\tif (overlay && context) {\n\t\treturn (\n\t\t\t<Dialog open={!context.collapsed} onOpenChange={(open) => context.setCollapsed(!open)}>\n\t\t\t\t<DialogPortal>\n\t\t\t\t\t<DialogOverlay />\n\t\t\t\t\t<DialogPrimitive.Content\n\t\t\t\t\t\tdata-basalt-sidebar=\"\"\n\t\t\t\t\t\taria-label=\"Sidebar\"\n\t\t\t\t\t\tdata-overlay=\"\"\n\t\t\t\t\t\tdata-side={side}\n\t\t\t\t\t\taria-busy={context.loading || undefined}\n\t\t\t\t\t\tonMouseEnter={onMouseEnter}\n\t\t\t\t\t\tonMouseLeave={onMouseLeave}\n\t\t\t\t\t\tref={(node) => {\n\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\tnode &&\n\t\t\t\t\t\t\t\tdocument.activeElement instanceof HTMLElement &&\n\t\t\t\t\t\t\t\t!node.contains(document.activeElement)\n\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\tcontext.lastFocusRef.current = document.activeElement;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}}\n\t\t\t\t\t\tonOpenAutoFocus={(event) => {\n\t\t\t\t\t\t\tconst from = \"relatedTarget\" in event ? event.relatedTarget : null;\n\t\t\t\t\t\t\tif (from instanceof HTMLElement) {\n\t\t\t\t\t\t\t\tcontext.lastFocusRef.current = from;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}}\n\t\t\t\t\t\tonCloseAutoFocus={(event) => {\n\t\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\t\tcontext.lastFocusRef.current?.focus();\n\t\t\t\t\t\t}}\n\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\tframeClass,\n\t\t\t\t\t\t\tOVERLAY_LAYER,\n\t\t\t\t\t\t\t\"fixed inset-y-0 overflow-hidden shadow-md\",\n\t\t\t\t\t\t\tside === \"right\" ? \"right-0\" : \"left-0\",\n\t\t\t\t\t\t)}\n\t\t\t\t\t\tstyle={{ width, ...style }}\n\t\t\t\t\t\t{...props}\n\t\t\t\t\t>\n\t\t\t\t\t\t{body}\n\t\t\t\t\t\t{resize}\n\t\t\t\t\t</DialogPrimitive.Content>\n\t\t\t\t</DialogPortal>\n\t\t\t</Dialog>\n\t\t);\n\t}\n\treturn (\n\t\t<aside\n\t\t\tdata-basalt-sidebar=\"\"\n\t\t\tdata-collapsed={collapsed ? \"\" : undefined}\n\t\t\tdata-side={side}\n\t\t\taria-busy={context?.loading || undefined}\n\t\t\tonMouseEnter={(event) => {\n\t\t\t\tif (context?.peek && context.collapsed) {\n\t\t\t\t\tcontext.setPeeking(true);\n\t\t\t\t}\n\t\t\t\tonMouseEnter?.(event);\n\t\t\t}}\n\t\t\tonMouseLeave={(event) => {\n\t\t\t\tif (context?.peek) {\n\t\t\t\t\tcontext.setPeeking(false);\n\t\t\t\t}\n\t\t\t\tonMouseLeave?.(event);\n\t\t\t}}\n\t\t\tclassName={cn(\n\t\t\t\tframeClass,\n\t\t\t\t\"sticky overflow-hidden transition-[width] basalt-motion duration-basalt-normal ease-basalt\",\n\t\t\t\tside === \"right\" ? \"order-last\" : undefined,\n\t\t\t\tcollapsed && \"w-basalt-rail\",\n\t\t\t)}\n\t\t\tstyle={!collapsed ? { width, ...style } : style}\n\t\t\t{...props}\n\t\t>\n\t\t\t{body}\n\t\t\t{resize}\n\t\t</aside>\n\t);\n}\n\nconst SIDEBAR_ROW_CLASS =\n\t\"min-h-[calc(var(--basalt-line-row)+2*var(--basalt-space-lg))] py-basalt-space-lg\";\n\nexport interface SidebarHeaderProps extends HTMLAttributes<HTMLDivElement> {}\n\nexport function SidebarHeader({ className, ...props }: SidebarHeaderProps) {\n\treturn (\n\t\t<div\n\t\t\tdata-slot=\"sidebar-header\"\n\t\t\tclassName={cn(\n\t\t\t\t\"flex h-basalt-14 shrink-0 items-center gap-basalt-row-gap px-basalt-nav-inset\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t/>\n\t);\n}\n\n/**\n * Props for `SidebarSearch`. Renders a native `<button>` element and accepts all standard button HTML attributes and click handlers.\n */\nexport interface SidebarSearchProps extends ButtonHTMLAttributes<HTMLButtonElement> {\n\t/**\n\t * Shortcut key display label rendered inside the trailing kbd tag. Note: this is a visual label only and does not register a global keyboard shortcut.\n\t * @default \"⌘K\"\n\t */\n\tshortcut?: string;\n}\n\nexport function SidebarSearch({\n\tshortcut = \"⌘K\",\n\tclassName,\n\tchildren,\n\t...props\n}: SidebarSearchProps) {\n\treturn (\n\t\t<button\n\t\t\ttype=\"button\"\n\t\t\tclassName={cn(\n\t\t\t\tBASALT_UI_CLASS,\n\t\t\t\tNAV_ROW_CLASS,\n\t\t\t\tSIDEBAR_ROW_CLASS,\n\t\t\t\t\"w-full cursor-pointer bg-basalt-secondary transition-colors basalt-motion hover:bg-basalt-hover\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t>\n\t\t\t<Search className=\"h-basalt-4 w-basalt-4 text-basalt-muted-foreground\" strokeWidth={1.5} />\n\t\t\t<span className=\"flex-1 text-left text-basalt-base text-basalt-muted-foreground\">\n\t\t\t\t{children}\n\t\t\t</span>\n\t\t\t<kbd className=\"pointer-events-none hidden rounded-basalt-sm border border-basalt-border bg-basalt-card px-basalt-space-md py-basalt-space-xs text-basalt-sm font-medium text-basalt-muted-foreground sm:inline-block\">\n\t\t\t\t{shortcut}\n\t\t\t</kbd>\n\t\t</button>\n\t);\n}\n\nexport interface SidebarNavProps extends HTMLAttributes<HTMLElement> {}\n\nexport function SidebarNav({ className, ...props }: SidebarNavProps) {\n\tconst highlightRef = useHoverHighlight(undefined, { restoreOnPointerLeave: false });\n\treturn (\n\t\t<nav\n\t\t\tref={highlightRef}\n\t\t\tdata-slot=\"sidebar-nav\"\n\t\t\tclassName={cn(\n\t\t\t\tNAV_LIST_CLASS,\n\t\t\t\t\"min-h-0 flex-1 flex-col overflow-y-auto overscroll-y-contain\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t/>\n\t);\n}\n\nexport interface SidebarPartitionProps extends HTMLAttributes<HTMLParagraphElement> {}\n\nexport function SidebarPartition({ className, ...props }: SidebarPartitionProps) {\n\treturn (\n\t\t<p\n\t\t\tdata-slot=\"sidebar-partition\"\n\t\t\tclassName={cn(\n\t\t\t\t\"shrink-0 px-basalt-row-x pt-basalt-layout pb-basalt-space-lg text-basalt-sm font-semibold tracking-wide text-basalt-foreground uppercase\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t/>\n\t);\n}\n\nexport type SidebarItemProps = ButtonHTMLAttributes<HTMLButtonElement> & {\n\t/**\n\t * Mark the item as the current page.\n\t * @default false\n\t */\n\tactive?: boolean;\n};\n\nexport function SidebarItem({ active = false, className, ...props }: SidebarItemProps) {\n\treturn (\n\t\t<button\n\t\t\ttype=\"button\"\n\t\t\taria-current={active ? \"page\" : undefined}\n\t\t\tdata-basalt-hover-item=\"\"\n\t\t\tdata-sidebar-row=\"\"\n\t\t\tdata-hover-selected={active}\n\t\t\tclassName={cn(NAV_ITEM_CLASS, SIDEBAR_ROW_CLASS, \"w-full\", className)}\n\t\t\t{...props}\n\t\t/>\n\t);\n}\n\n/**\n * Props for `SidebarIconItem`. Accepts standard button HTML attributes. The caller is responsible for providing accessible labeling via `aria-label` or `aria-labelledby` as icon buttons do not automatically generate accessible names.\n */\nexport interface SidebarIconItemProps extends ButtonHTMLAttributes<HTMLButtonElement> {\n\t/**\n\t * Mark the icon button as active page item.\n\t * @default false\n\t */\n\tactive?: boolean;\n}\n\nexport function SidebarIconItem({ active = false, className, ...props }: SidebarIconItemProps) {\n\treturn (\n\t\t<button\n\t\t\ttype=\"button\"\n\t\t\taria-current={active ? \"page\" : undefined}\n\t\t\tdata-basalt-hover-item=\"\"\n\t\t\tdata-sidebar-row=\"\"\n\t\t\tdata-hover-selected={active}\n\t\t\tclassName={cn(\n\t\t\t\tNAV_ITEM_CLASS,\n\t\t\t\tSIDEBAR_ROW_CLASS,\n\t\t\t\t\"relative w-basalt-control justify-center\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t/>\n\t);\n}\n\n/**\n * Props for `SidebarGroup`. Uncontrolled collapsible section that accepts only the documented properties. It does not accept controlled open props or arbitrary DOM attributes.\n */\nexport interface SidebarGroupProps {\n\t/**\n\t * Section label displayed on the group trigger.\n\t */\n\tlabel: ReactNode;\n\t/**\n\t * Uncontrolled initial open state for the collapsible group.\n\t * @default true\n\t */\n\tdefaultOpen?: boolean;\n\t/**\n\t * Navigation items rendered inside the group.\n\t */\n\tchildren: ReactNode;\n}\n\nexport function SidebarGroup({ label, defaultOpen = true, children }: SidebarGroupProps) {\n\tconst [open, setOpen] = useState(defaultOpen);\n\treturn (\n\t\t<Collapsible\n\t\t\topen={open}\n\t\t\tonOpenChange={setOpen}\n\t\t\tdata-slot=\"sidebar-group\"\n\t\t\tclassName=\"shrink-0 pt-basalt-layout-sm\"\n\t\t>\n\t\t\t<CollapsibleTrigger asChild>\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tdata-slot=\"sidebar-group-label\"\n\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\"flex w-full cursor-pointer items-center justify-between gap-basalt-row-gap rounded-basalt-md px-basalt-row-x py-basalt-space-lg text-left text-basalt-sm font-semibold leading-basalt-row tracking-wide text-basalt-muted-foreground uppercase transition-colors basalt-motion hover:text-basalt-foreground\",\n\t\t\t\t\t\tFOCUS_INSET,\n\t\t\t\t\t)}\n\t\t\t\t>\n\t\t\t\t\t<span className=\"min-w-0 truncate\">{label}</span>\n\t\t\t\t\t<ChevronUp\n\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\"h-basalt-4 w-basalt-4 text-basalt-muted-foreground transition-transform basalt-motion duration-basalt-normal\",\n\t\t\t\t\t\t\tOVERLAY_MOTION,\n\t\t\t\t\t\t\t!open && \"rotate-180\",\n\t\t\t\t\t\t)}\n\t\t\t\t\t\tstrokeWidth={1.5}\n\t\t\t\t\t/>\n\t\t\t\t</button>\n\t\t\t</CollapsibleTrigger>\n\t\t\t<CollapsibleContent unstyled>\n\t\t\t\t<div className=\"flex flex-col gap-basalt-nav-gap pt-basalt-nav-gap\">{children}</div>\n\t\t\t</CollapsibleContent>\n\t\t</Collapsible>\n\t);\n}\n\nexport interface SidebarFooterProps extends HTMLAttributes<HTMLDivElement> {}\n\nexport function SidebarFooter({ className, ...props }: SidebarFooterProps) {\n\treturn (\n\t\t<div\n\t\t\tdata-slot=\"sidebar-footer\"\n\t\t\tclassName={cn(\n\t\t\t\t\"flex shrink-0 flex-col gap-basalt-content-gap px-basalt-nav-inset py-basalt-nav-inset\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t/>\n\t);\n}\n\nexport interface SidebarUserProps {\n\t/**\n\t * User display name.\n\t */\n\tname: ReactNode;\n\t/**\n\t * Optional user email or secondary text.\n\t */\n\temail?: ReactNode;\n\t/**\n\t * Avatar element slot.\n\t */\n\tavatar?: ReactNode;\n\t/**\n\t * Trailing action slot (e.g. settings or logout button).\n\t */\n\taction?: ReactNode;\n\t/**\n\t * Additional CSS class name.\n\t */\n\tclassName?: string;\n}\n\nexport function SidebarUser({ name, email, avatar, action, className }: SidebarUserProps) {\n\treturn (\n\t\t<div className={cn(\"flex items-center gap-basalt-space-lg\", className)}>\n\t\t\t{avatar}\n\t\t\t<div className=\"min-w-0 flex-1\">\n\t\t\t\t<p className=\"truncate text-basalt-base font-medium text-basalt-foreground\">{name}</p>\n\t\t\t\t{email ? (\n\t\t\t\t\t<p className=\"truncate text-basalt-sm text-basalt-muted-foreground\">{email}</p>\n\t\t\t\t) : null}\n\t\t\t</div>\n\t\t\t{action}\n\t\t</div>\n\t);\n}\n\nexport interface ContentIslandProps extends HTMLAttributes<HTMLDivElement> {\n\t/** Mobile surface treatment; desktop remains an inset L1 island. @default \"inset\" */\n\tmobileSurface?: \"inset\" | \"edge-to-edge\";\n}\n\nexport function ContentIsland({\n\tmobileSurface = \"inset\",\n\tclassName,\n\t...props\n}: ContentIslandProps) {\n\treturn (\n\t\t<div\n\t\t\tdata-basalt-surface-root=\"\"\n\t\t\tdata-basalt-island={mobileSurface}\n\t\t\tclassName={cn(\n\t\t\t\t\"min-h-0 min-w-0 flex-1 bg-basalt-card text-basalt-card-foreground md:rounded-basalt-island md:p-basalt-layout-lg lg:px-basalt-layout-xl\",\n\t\t\t\tmobileSurface === \"inset\"\n\t\t\t\t\t? \"rounded-basalt-lg p-basalt-layout shadow-sm ring-1 ring-basalt-border/40\"\n\t\t\t\t\t: \"md:shadow-sm md:ring-1 md:ring-basalt-border/40\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t/>\n\t);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"sidebar.js","names":["DialogPrimitive","SidebarContext","createContext","useSidebar","context","useContext","SidebarProvider","uncontrolled","setUncontrolled","useState","defaultCollapsed","peeking","setPeeking","width","setWidthState","clampSidebarWidth","defaultWidth","setWidth","useCallback","next","lastFocusRef","useRef","prevCollapsed","collapsed","prevOverlay","overlay","resolved","setCollapsed","onCollapsedChange","SidebarResize","cn","side","event","startX","startWidth","target","onMove","delta","move","onUp","dir","Sidebar","collapsedProp","props","body","SkeletonLine","children","resize","frameClass","BASALT_UI_CLASS","OVERLAY_MOTION","className","Dialog","open","DialogPortal","DialogOverlay","node","from","OVERLAY_LAYER","style","onMouseEnter","onMouseLeave","SIDEBAR_ROW_CLASS","SidebarHeader","SidebarSearch","NAV_ROW_CLASS","Search","shortcut","SidebarNav","highlightRef","useHoverHighlight","NAV_LIST_CLASS","SidebarPartition","SidebarItem","active","NAV_ITEM_CLASS","SidebarIconItem","SidebarGroup","setOpen","defaultOpen","Collapsible","CollapsibleTrigger","FOCUS_INSET","label","ChevronUp","CollapsibleContent","SidebarFooter","SidebarUser","avatar","name","email","action","ContentIsland","mobileSurface"],"sources":["../../src/components/sidebar.tsx"],"sourcesContent":["import * as DialogPrimitive from \"@radix-ui/react-dialog\";\nimport { ChevronUp, Search } from \"lucide-react\";\nimport {\n\ttype ButtonHTMLAttributes,\n\tcreateContext,\n\ttype HTMLAttributes,\n\ttype ReactNode,\n\ttype PointerEvent as ReactPointerEvent,\n\ttype RefObject,\n\tuseCallback,\n\tuseContext,\n\tuseLayoutEffect,\n\tuseRef,\n\tuseState,\n} from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { BASALT_UI_CLASS } from \"../utils/control-surface\";\nimport { NAV_ITEM_CLASS, NAV_LIST_CLASS, NAV_ROW_CLASS } from \"../utils/navigation\";\nimport { useHoverHighlight } from \"../utils/use-hover-highlight\";\nimport { Collapsible, CollapsibleContent, CollapsibleTrigger } from \"./collapsible\";\nimport { Dialog, DialogOverlay, DialogPortal } from \"./dialog\";\nimport { FOCUS_INSET, OVERLAY_LAYER, OVERLAY_MOTION } from \"./overlay\";\nimport { SkeletonLine } from \"./skeleton-line\";\n\nexport type SidebarSide = \"left\" | \"right\";\n\nexport interface SidebarContextValue {\n\t/**\n\t * Whether the sidebar is currently collapsed.\n\t */\n\tcollapsed: boolean;\n\t/**\n\t * Callback to update the collapsed state.\n\t */\n\tsetCollapsed: (next: boolean) => void;\n\t/**\n\t * Which edge the sidebar occupies.\n\t */\n\tside: SidebarSide;\n\t/**\n\t * Whether the sidebar is currently displaying a loading skeleton.\n\t */\n\tloading: boolean;\n\t/**\n\t * Whether the sidebar rail expands on pointer hover.\n\t */\n\tpeek: boolean;\n\t/**\n\t * Whether the sidebar is actively hovering in peek preview mode.\n\t */\n\tpeeking: boolean;\n\t/**\n\t * Callback to update the peek preview state.\n\t */\n\tsetPeeking: (next: boolean) => void;\n\t/**\n\t * Whether the sidebar is rendering as a modal overlay drawer instead of in-flow layout chrome.\n\t */\n\toverlay: boolean;\n\t/**\n\t * Current expanded width in pixels, clamped between 180 and 400.\n\t */\n\twidth: number;\n\t/**\n\t * Callback to update the sidebar width. Value is clamped between 180 and 400 pixels.\n\t */\n\tsetWidth: (next: number) => void;\n\t/**\n\t * Reference to the last active element that held focus before opening the sidebar drawer.\n\t */\n\tlastFocusRef: RefObject<HTMLElement | null>;\n}\n\nconst SidebarContext = createContext<SidebarContextValue | null>(null);\n\n/**\n * Accesses the sidebar context value. Must be used within a `SidebarProvider`; throws an error if called outside.\n * Returns the active sidebar state and control callbacks.\n */\nexport function useSidebar(): SidebarContextValue {\n\tconst context = useContext(SidebarContext);\n\tif (!context) {\n\t\tthrow new Error(\"useSidebar must be used within SidebarProvider\");\n\t}\n\treturn context;\n}\n\nexport type SidebarProviderProps = {\n\t/**\n\t * The controlled collapsed state.\n\t */\n\tcollapsed?: boolean;\n\t/**\n\t * The uncontrolled initial collapsed state.\n\t * @default false\n\t */\n\tdefaultCollapsed?: boolean;\n\t/**\n\t * Called when the collapsed state changes.\n\t */\n\tonCollapsedChange?: (collapsed: boolean) => void;\n\t/**\n\t * Which edge the sidebar occupies.\n\t * @default left\n\t */\n\tside?: SidebarSide;\n\t/**\n\t * Replace the nav with a loading skeleton.\n\t * @default false\n\t */\n\tloading?: boolean;\n\t/**\n\t * Expand the collapsed rail on hover.\n\t * @default false\n\t */\n\tpeek?: boolean;\n\t/**\n\t * Render as an overlay instead of in-flow chrome.\n\t * @default false\n\t */\n\toverlay?: boolean;\n\t/**\n\t * Initial expanded width in pixels, clamped between 180 and 400.\n\t * @default 260\n\t */\n\tdefaultWidth?: number;\n\t/**\n\t * Sidebar chrome and page content.\n\t */\n\tchildren: ReactNode;\n};\n\nexport function SidebarProvider({\n\tcollapsed,\n\tdefaultCollapsed = false,\n\tonCollapsedChange,\n\tside = \"left\",\n\tloading = false,\n\tpeek = false,\n\toverlay = false,\n\tdefaultWidth = 260,\n\tchildren,\n}: SidebarProviderProps) {\n\tconst [uncontrolled, setUncontrolled] = useState(defaultCollapsed);\n\tconst [peeking, setPeeking] = useState(false);\n\tconst [width, setWidthState] = useState(() => clampSidebarWidth(defaultWidth));\n\tconst setWidth = useCallback((next: number) => {\n\t\tsetWidthState(clampSidebarWidth(next));\n\t}, []);\n\tconst lastFocusRef = useRef<HTMLElement | null>(null);\n\tconst prevCollapsed = useRef(collapsed ?? defaultCollapsed);\n\tconst prevOverlay = useRef(overlay);\n\tconst resolved = collapsed ?? uncontrolled;\n\tuseLayoutEffect(() => {\n\t\tif (\n\t\t\toverlay &&\n\t\t\t!resolved &&\n\t\t\t(prevCollapsed.current || !prevOverlay.current) &&\n\t\t\tdocument.activeElement instanceof HTMLElement\n\t\t) {\n\t\t\tlastFocusRef.current = document.activeElement;\n\t\t}\n\t\tprevCollapsed.current = resolved;\n\t\tprevOverlay.current = overlay;\n\t});\n\tconst setCollapsed = useCallback(\n\t\t(next: boolean) => {\n\t\t\tif (!next && document.activeElement instanceof HTMLElement) {\n\t\t\t\tlastFocusRef.current = document.activeElement;\n\t\t\t}\n\t\t\tif (collapsed === undefined) {\n\t\t\t\tsetUncontrolled(next);\n\t\t\t}\n\t\t\tonCollapsedChange?.(next);\n\t\t},\n\t\t[collapsed, onCollapsedChange],\n\t);\n\treturn (\n\t\t<SidebarContext.Provider\n\t\t\tvalue={{\n\t\t\t\tcollapsed: resolved,\n\t\t\t\tsetCollapsed,\n\t\t\t\tside,\n\t\t\t\tloading,\n\t\t\t\tpeek,\n\t\t\t\tpeeking,\n\t\t\t\tsetPeeking,\n\t\t\t\toverlay,\n\t\t\t\twidth,\n\t\t\t\tsetWidth,\n\t\t\t\tlastFocusRef,\n\t\t\t}}\n\t\t>\n\t\t\t{children}\n\t\t</SidebarContext.Provider>\n\t);\n}\n\nexport type SidebarProps = HTMLAttributes<HTMLElement> & {\n\t/**\n\t * Collapse the rail when no provider is present.\n\t * @default false\n\t */\n\tcollapsed?: boolean;\n};\n\nfunction clampSidebarWidth(next: number) {\n\treturn Math.min(400, Math.max(180, next));\n}\n\nfunction SidebarResize({\n\tside,\n\twidth,\n\tonWidth,\n}: {\n\tside: SidebarSide;\n\twidth: number;\n\tonWidth: (next: number) => void;\n}) {\n\tconst onPointerDown = (event: ReactPointerEvent<HTMLDivElement>) => {\n\t\tevent.preventDefault();\n\t\tevent.currentTarget.setPointerCapture(event.pointerId);\n\t\tconst startX = event.clientX;\n\t\tconst startWidth = width;\n\t\tconst target = event.currentTarget;\n\t\tconst onMove = (move: PointerEvent) => {\n\t\t\tconst delta = side === \"right\" ? startX - move.clientX : move.clientX - startX;\n\t\t\tonWidth(clampSidebarWidth(startWidth + delta));\n\t\t};\n\t\tconst onUp = () => {\n\t\t\ttarget.removeEventListener(\"pointermove\", onMove);\n\t\t\ttarget.removeEventListener(\"pointerup\", onUp);\n\t\t\ttarget.removeEventListener(\"pointercancel\", onUp);\n\t\t};\n\t\ttarget.addEventListener(\"pointermove\", onMove);\n\t\ttarget.addEventListener(\"pointerup\", onUp);\n\t\ttarget.addEventListener(\"pointercancel\", onUp);\n\t};\n\treturn (\n\t\t<div\n\t\t\trole=\"separator\"\n\t\t\taria-orientation=\"vertical\"\n\t\t\taria-valuenow={width}\n\t\t\taria-valuemin={180}\n\t\t\taria-valuemax={400}\n\t\t\taria-label=\"Resize sidebar\"\n\t\t\ttabIndex={0}\n\t\t\tclassName={cn(\n\t\t\t\t\"absolute top-0 h-full w-basalt-1 cursor-col-resize bg-transparent\",\n\t\t\t\tside === \"right\" ? \"left-0\" : \"right-0\",\n\t\t\t)}\n\t\t\tonPointerDown={onPointerDown}\n\t\t\tonKeyDown={(event) => {\n\t\t\t\tif (event.key !== \"ArrowLeft\" && event.key !== \"ArrowRight\") {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tevent.preventDefault();\n\t\t\t\tconst dir = event.key === \"ArrowRight\" ? 1 : -1;\n\t\t\t\tconst delta = side === \"right\" ? -dir * 8 : dir * 8;\n\t\t\t\tonWidth(clampSidebarWidth(width + delta));\n\t\t\t}}\n\t\t/>\n\t);\n}\n\nexport function Sidebar({\n\tcollapsed: collapsedProp,\n\tclassName,\n\tchildren,\n\tonMouseEnter,\n\tonMouseLeave,\n\tstyle,\n\t...props\n}: SidebarProps) {\n\tconst context = useContext(SidebarContext);\n\tconst collapsed = context\n\t\t? context.collapsed && !(context.peek && context.peeking)\n\t\t: (collapsedProp ?? false);\n\tconst side = context?.side ?? \"left\";\n\tconst overlay = context?.overlay ?? false;\n\tconst width = context?.width ?? 260;\n\tconst body = context?.loading ? (\n\t\t<div\n\t\t\tclassName=\"flex flex-col gap-basalt-space-lg p-basalt-space-lg\"\n\t\t\trole=\"status\"\n\t\t\taria-live=\"polite\"\n\t\t>\n\t\t\t<SkeletonLine />\n\t\t\t<SkeletonLine />\n\t\t\t<SkeletonLine />\n\t\t</div>\n\t) : (\n\t\tchildren\n\t);\n\tconst resize =\n\t\tcontext && !collapsed ? (\n\t\t\t<SidebarResize side={side} width={context.width} onWidth={context.setWidth} />\n\t\t) : null;\n\tconst frameClass = cn(\n\t\tBASALT_UI_CLASS,\n\t\t\"relative flex shrink-0 flex-col bg-basalt-background text-basalt-base text-basalt-foreground\",\n\t\tOVERLAY_MOTION,\n\t\tclassName,\n\t);\n\tif (overlay && context) {\n\t\treturn (\n\t\t\t<Dialog open={!context.collapsed} onOpenChange={(open) => context.setCollapsed(!open)}>\n\t\t\t\t<DialogPortal>\n\t\t\t\t\t<DialogOverlay />\n\t\t\t\t\t<DialogPrimitive.Content\n\t\t\t\t\t\tdata-basalt-sidebar=\"\"\n\t\t\t\t\t\taria-label=\"Sidebar\"\n\t\t\t\t\t\tdata-overlay=\"\"\n\t\t\t\t\t\tdata-side={side}\n\t\t\t\t\t\taria-busy={context.loading || undefined}\n\t\t\t\t\t\tonMouseEnter={onMouseEnter}\n\t\t\t\t\t\tonMouseLeave={onMouseLeave}\n\t\t\t\t\t\tref={(node) => {\n\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\tnode &&\n\t\t\t\t\t\t\t\tdocument.activeElement instanceof HTMLElement &&\n\t\t\t\t\t\t\t\t!node.contains(document.activeElement)\n\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\tcontext.lastFocusRef.current = document.activeElement;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}}\n\t\t\t\t\t\tonOpenAutoFocus={(event) => {\n\t\t\t\t\t\t\tconst from = \"relatedTarget\" in event ? event.relatedTarget : null;\n\t\t\t\t\t\t\tif (from instanceof HTMLElement) {\n\t\t\t\t\t\t\t\tcontext.lastFocusRef.current = from;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}}\n\t\t\t\t\t\tonCloseAutoFocus={(event) => {\n\t\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\t\tcontext.lastFocusRef.current?.focus();\n\t\t\t\t\t\t}}\n\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\tframeClass,\n\t\t\t\t\t\t\tOVERLAY_LAYER,\n\t\t\t\t\t\t\t\"fixed inset-y-0 overflow-hidden shadow-md\",\n\t\t\t\t\t\t\tside === \"right\" ? \"right-0\" : \"left-0\",\n\t\t\t\t\t\t)}\n\t\t\t\t\t\tstyle={{ width, ...style }}\n\t\t\t\t\t\t{...props}\n\t\t\t\t\t>\n\t\t\t\t\t\t{body}\n\t\t\t\t\t\t{resize}\n\t\t\t\t\t</DialogPrimitive.Content>\n\t\t\t\t</DialogPortal>\n\t\t\t</Dialog>\n\t\t);\n\t}\n\treturn (\n\t\t<aside\n\t\t\tdata-basalt-sidebar=\"\"\n\t\t\tdata-collapsed={collapsed ? \"\" : undefined}\n\t\t\tdata-side={side}\n\t\t\taria-busy={context?.loading || undefined}\n\t\t\tonMouseEnter={(event) => {\n\t\t\t\tif (context?.peek && context.collapsed) {\n\t\t\t\t\tcontext.setPeeking(true);\n\t\t\t\t}\n\t\t\t\tonMouseEnter?.(event);\n\t\t\t}}\n\t\t\tonMouseLeave={(event) => {\n\t\t\t\tif (context?.peek) {\n\t\t\t\t\tcontext.setPeeking(false);\n\t\t\t\t}\n\t\t\t\tonMouseLeave?.(event);\n\t\t\t}}\n\t\t\tclassName={cn(\n\t\t\t\tframeClass,\n\t\t\t\t\"sticky overflow-hidden transition-[width] basalt-motion duration-basalt-normal ease-basalt\",\n\t\t\t\tside === \"right\" ? \"order-last\" : undefined,\n\t\t\t\tcollapsed && \"w-basalt-rail\",\n\t\t\t)}\n\t\t\tstyle={!collapsed ? { width, ...style } : style}\n\t\t\t{...props}\n\t\t>\n\t\t\t{body}\n\t\t\t{resize}\n\t\t</aside>\n\t);\n}\n\nconst SIDEBAR_ROW_CLASS =\n\t\"min-h-[calc(var(--basalt-line-row)+2*var(--basalt-space-lg))] py-basalt-space-lg\";\n\nexport interface SidebarHeaderProps extends HTMLAttributes<HTMLDivElement> {}\n\nexport function SidebarHeader({ className, ...props }: SidebarHeaderProps) {\n\treturn (\n\t\t<div\n\t\t\tdata-slot=\"sidebar-header\"\n\t\t\tclassName={cn(\n\t\t\t\t\"flex h-basalt-14 shrink-0 items-center gap-basalt-row-gap px-basalt-nav-inset\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t/>\n\t);\n}\n\n/**\n * Props for `SidebarSearch`. Renders a native `<button>` element and accepts all standard button HTML attributes and click handlers.\n */\nexport interface SidebarSearchProps extends ButtonHTMLAttributes<HTMLButtonElement> {\n\t/**\n\t * Shortcut key display label rendered inside the trailing kbd tag. Note: this is a visual label only and does not register a global keyboard shortcut.\n\t * @default \"⌘K\"\n\t */\n\tshortcut?: string;\n}\n\nexport function SidebarSearch({\n\tshortcut = \"⌘K\",\n\tclassName,\n\tchildren,\n\t...props\n}: SidebarSearchProps) {\n\treturn (\n\t\t<button\n\t\t\ttype=\"button\"\n\t\t\tclassName={cn(\n\t\t\t\tBASALT_UI_CLASS,\n\t\t\t\tNAV_ROW_CLASS,\n\t\t\t\tSIDEBAR_ROW_CLASS,\n\t\t\t\t\"w-full cursor-pointer bg-basalt-secondary transition-colors basalt-motion hover:bg-basalt-hover\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t>\n\t\t\t<Search className=\"h-basalt-4 w-basalt-4 text-basalt-muted-foreground\" strokeWidth={1.5} />\n\t\t\t<span className=\"flex-1 text-left text-basalt-base text-basalt-muted-foreground\">\n\t\t\t\t{children}\n\t\t\t</span>\n\t\t\t<kbd className=\"pointer-events-none hidden rounded-basalt-sm border border-basalt-border bg-basalt-card px-basalt-space-md py-basalt-space-xs text-basalt-sm font-medium text-basalt-muted-foreground sm:inline-block\">\n\t\t\t\t{shortcut}\n\t\t\t</kbd>\n\t\t</button>\n\t);\n}\n\nexport interface SidebarNavProps extends HTMLAttributes<HTMLElement> {}\n\nexport function SidebarNav({ className, ...props }: SidebarNavProps) {\n\tconst highlightRef = useHoverHighlight(undefined, { restoreOnPointerLeave: false });\n\treturn (\n\t\t<nav\n\t\t\tref={highlightRef}\n\t\t\tdata-slot=\"sidebar-nav\"\n\t\t\tclassName={cn(\n\t\t\t\tNAV_LIST_CLASS,\n\t\t\t\t\"min-h-0 flex-1 flex-col overflow-y-auto overscroll-y-contain\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t/>\n\t);\n}\n\nexport interface SidebarPartitionProps extends HTMLAttributes<HTMLParagraphElement> {}\n\nexport function SidebarPartition({ className, ...props }: SidebarPartitionProps) {\n\treturn (\n\t\t<p\n\t\t\tdata-slot=\"sidebar-partition\"\n\t\t\tclassName={cn(\n\t\t\t\t\"shrink-0 px-basalt-row-x pt-basalt-layout pb-basalt-space-lg text-basalt-sm font-semibold tracking-wide text-basalt-foreground uppercase\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t/>\n\t);\n}\n\nexport type SidebarItemProps = ButtonHTMLAttributes<HTMLButtonElement> & {\n\t/**\n\t * Mark the item as the current page.\n\t * @default false\n\t */\n\tactive?: boolean;\n};\n\nexport function SidebarItem({ active = false, className, ...props }: SidebarItemProps) {\n\treturn (\n\t\t<button\n\t\t\ttype=\"button\"\n\t\t\taria-current={active ? \"page\" : undefined}\n\t\t\tdata-basalt-hover-item=\"\"\n\t\t\tdata-sidebar-row=\"\"\n\t\t\tdata-hover-selected={active}\n\t\t\tclassName={cn(NAV_ITEM_CLASS, SIDEBAR_ROW_CLASS, \"w-full\", className)}\n\t\t\t{...props}\n\t\t/>\n\t);\n}\n\n/**\n * Props for `SidebarIconItem`. Accepts standard button HTML attributes. The caller is responsible for providing accessible labeling via `aria-label` or `aria-labelledby` as icon buttons do not automatically generate accessible names.\n */\nexport interface SidebarIconItemProps extends ButtonHTMLAttributes<HTMLButtonElement> {\n\t/**\n\t * Mark the icon button as active page item.\n\t * @default false\n\t */\n\tactive?: boolean;\n}\n\nexport function SidebarIconItem({ active = false, className, ...props }: SidebarIconItemProps) {\n\treturn (\n\t\t<button\n\t\t\ttype=\"button\"\n\t\t\taria-current={active ? \"page\" : undefined}\n\t\t\tdata-basalt-hover-item=\"\"\n\t\t\tdata-sidebar-row=\"\"\n\t\t\tdata-hover-selected={active}\n\t\t\tclassName={cn(\n\t\t\t\tNAV_ITEM_CLASS,\n\t\t\t\tSIDEBAR_ROW_CLASS,\n\t\t\t\t\"relative w-basalt-control justify-center\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t/>\n\t);\n}\n\n/**\n * Props for `SidebarGroup`. Uncontrolled collapsible section that accepts only the documented properties. It does not accept controlled open props or arbitrary DOM attributes.\n */\nexport interface SidebarGroupProps {\n\t/**\n\t * Section label displayed on the group trigger.\n\t */\n\tlabel: ReactNode;\n\t/**\n\t * Uncontrolled initial open state for the collapsible group.\n\t * @default true\n\t */\n\tdefaultOpen?: boolean;\n\t/**\n\t * Navigation items rendered inside the group.\n\t */\n\tchildren: ReactNode;\n}\n\nexport function SidebarGroup({ label, defaultOpen = true, children }: SidebarGroupProps) {\n\tconst [open, setOpen] = useState(defaultOpen);\n\treturn (\n\t\t<Collapsible\n\t\t\topen={open}\n\t\t\tonOpenChange={setOpen}\n\t\t\tdata-slot=\"sidebar-group\"\n\t\t\tclassName=\"shrink-0 pt-basalt-layout-sm\"\n\t\t>\n\t\t\t<CollapsibleTrigger asChild>\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tdata-slot=\"sidebar-group-label\"\n\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\"flex w-full cursor-pointer items-center justify-between gap-basalt-row-gap rounded-basalt-md px-basalt-row-x py-basalt-space-lg text-left text-basalt-sm font-semibold leading-basalt-row tracking-wide text-basalt-muted-foreground uppercase transition-colors basalt-motion hover:text-basalt-foreground\",\n\t\t\t\t\t\tFOCUS_INSET,\n\t\t\t\t\t)}\n\t\t\t\t>\n\t\t\t\t\t<span className=\"min-w-0 truncate\">{label}</span>\n\t\t\t\t\t<ChevronUp\n\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\"h-basalt-4 w-basalt-4 text-basalt-muted-foreground transition-transform basalt-motion duration-basalt-normal\",\n\t\t\t\t\t\t\tOVERLAY_MOTION,\n\t\t\t\t\t\t\t!open && \"rotate-180\",\n\t\t\t\t\t\t)}\n\t\t\t\t\t\tstrokeWidth={1.5}\n\t\t\t\t\t/>\n\t\t\t\t</button>\n\t\t\t</CollapsibleTrigger>\n\t\t\t<CollapsibleContent unstyled>\n\t\t\t\t<div className=\"flex flex-col gap-basalt-nav-gap pt-basalt-nav-gap\">{children}</div>\n\t\t\t</CollapsibleContent>\n\t\t</Collapsible>\n\t);\n}\n\nexport interface SidebarFooterProps extends HTMLAttributes<HTMLDivElement> {}\n\nexport function SidebarFooter({ className, ...props }: SidebarFooterProps) {\n\treturn (\n\t\t<div\n\t\t\tdata-slot=\"sidebar-footer\"\n\t\t\tclassName={cn(\n\t\t\t\t\"flex shrink-0 flex-col gap-basalt-content-gap px-basalt-layout pt-basalt-space-lg pb-basalt-layout\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t/>\n\t);\n}\n\nexport interface SidebarUserProps {\n\t/**\n\t * User display name.\n\t */\n\tname: ReactNode;\n\t/**\n\t * Optional user email or secondary text.\n\t */\n\temail?: ReactNode;\n\t/**\n\t * Avatar element slot.\n\t */\n\tavatar?: ReactNode;\n\t/**\n\t * Trailing action slot (e.g. settings or logout button).\n\t */\n\taction?: ReactNode;\n\t/**\n\t * Additional CSS class name.\n\t */\n\tclassName?: string;\n}\n\nexport function SidebarUser({ name, email, avatar, action, className }: SidebarUserProps) {\n\treturn (\n\t\t<div className={cn(\"flex items-center gap-basalt-space-lg\", className)}>\n\t\t\t{avatar}\n\t\t\t<div className=\"min-w-0 flex-1\">\n\t\t\t\t<p className=\"truncate text-basalt-base font-medium text-basalt-foreground\">{name}</p>\n\t\t\t\t{email ? (\n\t\t\t\t\t<p className=\"truncate text-basalt-sm text-basalt-muted-foreground\">{email}</p>\n\t\t\t\t) : null}\n\t\t\t</div>\n\t\t\t{action}\n\t\t</div>\n\t);\n}\n\nexport interface ContentIslandProps extends HTMLAttributes<HTMLDivElement> {\n\t/** Mobile surface treatment; desktop remains an inset L1 island. @default \"inset\" */\n\tmobileSurface?: \"inset\" | \"edge-to-edge\";\n}\n\nexport function ContentIsland({\n\tmobileSurface = \"inset\",\n\tclassName,\n\t...props\n}: ContentIslandProps) {\n\treturn (\n\t\t<div\n\t\t\tdata-basalt-surface-root=\"\"\n\t\t\tdata-basalt-island={mobileSurface}\n\t\t\tclassName={cn(\n\t\t\t\t\"min-h-0 min-w-0 flex-1 bg-basalt-card text-basalt-card-foreground md:rounded-basalt-island md:p-basalt-layout-lg lg:px-basalt-layout-xl\",\n\t\t\t\tmobileSurface === \"inset\"\n\t\t\t\t\t? \"rounded-basalt-lg p-basalt-layout shadow-sm ring-1 ring-basalt-border/40\"\n\t\t\t\t\t: \"md:shadow-sm md:ring-1 md:ring-basalt-border/40\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t/>\n\t);\n}\n"],"mappings":"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"}
|
package/dist/components/table.js
CHANGED
|
@@ -51,7 +51,7 @@ var y = n.forwardRef(({ children: t, textAlign: n = "start", sorted: r, classNam
|
|
|
51
51
|
return /* @__PURE__ */ s("button", {
|
|
52
52
|
type: "button",
|
|
53
53
|
ref: l,
|
|
54
|
-
className: e("group flex w-full cursor-pointer items-center gap-basalt-space-sm rounded-basalt-sm border-0 bg-transparent p-0 font-inherit text-inherit font-medium
|
|
54
|
+
className: e("basalt-focus group flex w-full cursor-pointer items-center gap-basalt-space-sm rounded-basalt-sm border-0 bg-transparent p-0 font-inherit text-inherit font-medium", n === "end" ? "justify-end text-end" : "text-start", i),
|
|
55
55
|
...a,
|
|
56
56
|
children: n === "end" ? /* @__PURE__ */ c(o, { children: [d, u] }) : /* @__PURE__ */ c(o, { children: [u, d] })
|
|
57
57
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"table.js","names":["_Fragment","React","Fragment$1","Table","props","striped","cn","BASALT_UI_CLASS","className","TableHeader","TableBody","TableFooter","TableRow","variant","textAlignClass","textAlign","TableHead","align","TableCell","TableCaption","SortIcon","sorted","ArrowUp","ArrowDown","ArrowUpDown","TableSortableHeader","label","icon"],"sources":["../../src/components/table.tsx"],"sourcesContent":["import { ArrowDown, ArrowUp, ArrowUpDown } from \"lucide-react\";\nimport * as React from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { BASALT_UI_CLASS } from \"../utils/control-surface\";\n\n/** Logical inline alignment. Maps to CSS `text-align: start | end`. */\nexport type TableTextAlign = \"start\" | \"end\";\nexport type TableSortDirection = \"asc\" | \"desc\";\n\nexport type TableProps = {\n\t/** Paint alternating rows. @default false */\n\tstriped?: boolean;\n\t/**\n\t * Additional classes for the table.\n\t */\n\tclassName?: string;\n};\n\nexport const Table = React.forwardRef<\n\tHTMLTableElement,\n\tTableProps & React.HTMLAttributes<HTMLTableElement>\n>(({ className, striped = false, ...props }, ref) => (\n\t<table\n\t\tref={ref}\n\t\tdata-basalt-table=\"\"\n\t\tdata-striped={striped ? \"true\" : undefined}\n\t\tclassName={cn(\n\t\t\tBASALT_UI_CLASS,\n\t\t\t\"w-full border-separate border-spacing-0 caption-bottom text-start text-basalt-base leading-[var(--basalt-line-body)] text-basalt-foreground\",\n\t\t\tclassName,\n\t\t)}\n\t\t{...props}\n\t/>\n));\nTable.displayName = \"Table\";\n\nexport interface TableHeaderProps extends React.HTMLAttributes<HTMLTableSectionElement> {}\n\nexport const TableHeader = (props: TableHeaderProps) => <thead {...props} />;\n\nexport interface TableBodyProps extends React.HTMLAttributes<HTMLTableSectionElement> {}\n\nexport const TableBody = (props: TableBodyProps) => <tbody {...props} />;\n\nexport interface TableFooterProps extends React.HTMLAttributes<HTMLTableSectionElement> {}\n\nexport const TableFooter = (props: TableFooterProps) => <tfoot {...props} />;\n\nexport type TableRowVariant = \"default\" | \"selected\";\n\nexport type TableRowProps = {\n\t/**\n\t * Highlight the row as selected.\n\t * @default \"default\"\n\t */\n\tvariant?: TableRowVariant;\n\t/**\n\t * Additional classes for the row.\n\t */\n\tclassName?: string;\n};\n\nexport const TableRow = ({\n\tclassName,\n\tvariant = \"default\",\n\t...props\n}: TableRowProps & React.HTMLAttributes<HTMLTableRowElement>) => (\n\t<tr\n\t\t{...props}\n\t\taria-selected={variant === \"selected\" ? true : props[\"aria-selected\"]}\n\t\tclassName={className}\n\t/>\n);\n\nfunction textAlignClass(textAlign?: TableTextAlign) {\n\tif (textAlign === \"end\") return \"text-end tabular-nums\";\n\tif (textAlign === \"start\") return \"text-start\";\n}\n\nexport type TableHeadProps = {\n\t/**\n\t * Additional classes for the header cell.\n\t */\n\tclassName?: string;\n\t/**\n\t * Logical inline alignment. Omitted headers keep `text-start` unless native `align` is set.\n\t */\n\ttextAlign?: TableTextAlign;\n};\n\nexport const TableHead = ({\n\tclassName,\n\ttextAlign,\n\talign,\n\t...props\n}: TableHeadProps & React.ThHTMLAttributes<HTMLTableCellElement>) => (\n\t<th\n\t\tclassName={cn(\n\t\t\t\"relative h-basalt-table-row whitespace-nowrap border-b border-basalt-border ps-basalt-table-x pe-basalt-table-x py-basalt-table-y align-middle text-basalt-sm font-medium tracking-[0.04em] text-basalt-muted-foreground\",\n\t\t\ttextAlignClass(textAlign) ?? (align == null ? \"text-start\" : undefined),\n\t\t\tclassName,\n\t\t)}\n\t\talign={align}\n\t\t{...props}\n\t/>\n);\n\nexport type TableCellProps = {\n\t/**\n\t * Additional classes for the cell.\n\t */\n\tclassName?: string;\n\t/**\n\t * Logical inline alignment. Omitted cells inherit from the table or row. Native HTML `align` is unchanged.\n\t */\n\ttextAlign?: TableTextAlign;\n};\n\nexport const TableCell = ({\n\tclassName,\n\ttextAlign,\n\t...props\n}: TableCellProps & React.TdHTMLAttributes<HTMLTableCellElement>) => (\n\t<td\n\t\tclassName={cn(\n\t\t\t\"relative h-basalt-table-row ps-basalt-table-x pe-basalt-table-x py-basalt-table-y align-middle\",\n\t\t\ttextAlignClass(textAlign),\n\t\t\tclassName,\n\t\t)}\n\t\t{...props}\n\t/>\n);\n\nexport type TableCaptionProps = {\n\t/**\n\t * Additional classes for the caption.\n\t */\n\tclassName?: string;\n};\n\nexport function TableCaption({\n\tclassName,\n\t...props\n}: TableCaptionProps & React.HTMLAttributes<HTMLTableCaptionElement>) {\n\treturn (\n\t\t<caption\n\t\t\tclassName={cn(\n\t\t\t\t\"px-basalt-panel-x py-basalt-panel-y text-basalt-base text-basalt-muted-foreground\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t/>\n\t);\n}\n\nexport type TableSortableHeaderProps = {\n\tchildren: React.ReactNode;\n\t/**\n\t * Logical control layout. `end` places the sort icon inward of the label.\n\t * @default \"start\"\n\t */\n\ttextAlign?: TableTextAlign;\n\t/**\n\t * Current sort direction when this column is sorted.\n\t */\n\tsorted?: TableSortDirection;\n\tclassName?: string;\n} & Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, \"type\" | \"children\" | \"className\">;\n\nfunction SortIcon({ sorted }: { sorted?: TableSortDirection }) {\n\tconst Icon = sorted === \"asc\" ? ArrowUp : sorted === \"desc\" ? ArrowDown : ArrowUpDown;\n\treturn (\n\t\t<Icon\n\t\t\taria-hidden=\"true\"\n\t\t\tclassName={cn(\n\t\t\t\t\"size-basalt-icon-sm shrink-0\",\n\t\t\t\t!sorted &&\n\t\t\t\t\t\"opacity-0 transition-opacity basalt-motion group-hover:opacity-60 group-focus-visible:opacity-60 motion-reduce:transition-none\",\n\t\t\t)}\n\t\t\tstrokeWidth={1.5}\n\t\t/>\n\t);\n}\n\nexport const TableSortableHeader = React.forwardRef<HTMLButtonElement, TableSortableHeaderProps>(\n\t({ children, textAlign = \"start\", sorted, className, ...props }, ref) => {\n\t\tconst label = (\n\t\t\t<span className=\"flex min-w-0 items-center gap-basalt-control-gap truncate\">{children}</span>\n\t\t);\n\t\tconst icon = <SortIcon sorted={sorted} />;\n\t\treturn (\n\t\t\t<button\n\t\t\t\ttype=\"button\"\n\t\t\t\tref={ref}\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"group flex w-full cursor-pointer items-center gap-basalt-space-sm rounded-basalt-sm border-0 bg-transparent p-0 font-inherit text-inherit font-medium
|
|
1
|
+
{"version":3,"file":"table.js","names":["_Fragment","React","Fragment$1","Table","props","striped","cn","BASALT_UI_CLASS","className","TableHeader","TableBody","TableFooter","TableRow","variant","textAlignClass","textAlign","TableHead","align","TableCell","TableCaption","SortIcon","sorted","ArrowUp","ArrowDown","ArrowUpDown","TableSortableHeader","label","icon"],"sources":["../../src/components/table.tsx"],"sourcesContent":["import { ArrowDown, ArrowUp, ArrowUpDown } from \"lucide-react\";\nimport * as React from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { BASALT_UI_CLASS } from \"../utils/control-surface\";\n\n/** Logical inline alignment. Maps to CSS `text-align: start | end`. */\nexport type TableTextAlign = \"start\" | \"end\";\nexport type TableSortDirection = \"asc\" | \"desc\";\n\nexport type TableProps = {\n\t/** Paint alternating rows. @default false */\n\tstriped?: boolean;\n\t/**\n\t * Additional classes for the table.\n\t */\n\tclassName?: string;\n};\n\nexport const Table = React.forwardRef<\n\tHTMLTableElement,\n\tTableProps & React.HTMLAttributes<HTMLTableElement>\n>(({ className, striped = false, ...props }, ref) => (\n\t<table\n\t\tref={ref}\n\t\tdata-basalt-table=\"\"\n\t\tdata-striped={striped ? \"true\" : undefined}\n\t\tclassName={cn(\n\t\t\tBASALT_UI_CLASS,\n\t\t\t\"w-full border-separate border-spacing-0 caption-bottom text-start text-basalt-base leading-[var(--basalt-line-body)] text-basalt-foreground\",\n\t\t\tclassName,\n\t\t)}\n\t\t{...props}\n\t/>\n));\nTable.displayName = \"Table\";\n\nexport interface TableHeaderProps extends React.HTMLAttributes<HTMLTableSectionElement> {}\n\nexport const TableHeader = (props: TableHeaderProps) => <thead {...props} />;\n\nexport interface TableBodyProps extends React.HTMLAttributes<HTMLTableSectionElement> {}\n\nexport const TableBody = (props: TableBodyProps) => <tbody {...props} />;\n\nexport interface TableFooterProps extends React.HTMLAttributes<HTMLTableSectionElement> {}\n\nexport const TableFooter = (props: TableFooterProps) => <tfoot {...props} />;\n\nexport type TableRowVariant = \"default\" | \"selected\";\n\nexport type TableRowProps = {\n\t/**\n\t * Highlight the row as selected.\n\t * @default \"default\"\n\t */\n\tvariant?: TableRowVariant;\n\t/**\n\t * Additional classes for the row.\n\t */\n\tclassName?: string;\n};\n\nexport const TableRow = ({\n\tclassName,\n\tvariant = \"default\",\n\t...props\n}: TableRowProps & React.HTMLAttributes<HTMLTableRowElement>) => (\n\t<tr\n\t\t{...props}\n\t\taria-selected={variant === \"selected\" ? true : props[\"aria-selected\"]}\n\t\tclassName={className}\n\t/>\n);\n\nfunction textAlignClass(textAlign?: TableTextAlign) {\n\tif (textAlign === \"end\") return \"text-end tabular-nums\";\n\tif (textAlign === \"start\") return \"text-start\";\n}\n\nexport type TableHeadProps = {\n\t/**\n\t * Additional classes for the header cell.\n\t */\n\tclassName?: string;\n\t/**\n\t * Logical inline alignment. Omitted headers keep `text-start` unless native `align` is set.\n\t */\n\ttextAlign?: TableTextAlign;\n};\n\nexport const TableHead = ({\n\tclassName,\n\ttextAlign,\n\talign,\n\t...props\n}: TableHeadProps & React.ThHTMLAttributes<HTMLTableCellElement>) => (\n\t<th\n\t\tclassName={cn(\n\t\t\t\"relative h-basalt-table-row whitespace-nowrap border-b border-basalt-border ps-basalt-table-x pe-basalt-table-x py-basalt-table-y align-middle text-basalt-sm font-medium tracking-[0.04em] text-basalt-muted-foreground\",\n\t\t\ttextAlignClass(textAlign) ?? (align == null ? \"text-start\" : undefined),\n\t\t\tclassName,\n\t\t)}\n\t\talign={align}\n\t\t{...props}\n\t/>\n);\n\nexport type TableCellProps = {\n\t/**\n\t * Additional classes for the cell.\n\t */\n\tclassName?: string;\n\t/**\n\t * Logical inline alignment. Omitted cells inherit from the table or row. Native HTML `align` is unchanged.\n\t */\n\ttextAlign?: TableTextAlign;\n};\n\nexport const TableCell = ({\n\tclassName,\n\ttextAlign,\n\t...props\n}: TableCellProps & React.TdHTMLAttributes<HTMLTableCellElement>) => (\n\t<td\n\t\tclassName={cn(\n\t\t\t\"relative h-basalt-table-row ps-basalt-table-x pe-basalt-table-x py-basalt-table-y align-middle\",\n\t\t\ttextAlignClass(textAlign),\n\t\t\tclassName,\n\t\t)}\n\t\t{...props}\n\t/>\n);\n\nexport type TableCaptionProps = {\n\t/**\n\t * Additional classes for the caption.\n\t */\n\tclassName?: string;\n};\n\nexport function TableCaption({\n\tclassName,\n\t...props\n}: TableCaptionProps & React.HTMLAttributes<HTMLTableCaptionElement>) {\n\treturn (\n\t\t<caption\n\t\t\tclassName={cn(\n\t\t\t\t\"px-basalt-panel-x py-basalt-panel-y text-basalt-base text-basalt-muted-foreground\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t/>\n\t);\n}\n\nexport type TableSortableHeaderProps = {\n\tchildren: React.ReactNode;\n\t/**\n\t * Logical control layout. `end` places the sort icon inward of the label.\n\t * @default \"start\"\n\t */\n\ttextAlign?: TableTextAlign;\n\t/**\n\t * Current sort direction when this column is sorted.\n\t */\n\tsorted?: TableSortDirection;\n\tclassName?: string;\n} & Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, \"type\" | \"children\" | \"className\">;\n\nfunction SortIcon({ sorted }: { sorted?: TableSortDirection }) {\n\tconst Icon = sorted === \"asc\" ? ArrowUp : sorted === \"desc\" ? ArrowDown : ArrowUpDown;\n\treturn (\n\t\t<Icon\n\t\t\taria-hidden=\"true\"\n\t\t\tclassName={cn(\n\t\t\t\t\"size-basalt-icon-sm shrink-0\",\n\t\t\t\t!sorted &&\n\t\t\t\t\t\"opacity-0 transition-opacity basalt-motion group-hover:opacity-60 group-focus-visible:opacity-60 motion-reduce:transition-none\",\n\t\t\t)}\n\t\t\tstrokeWidth={1.5}\n\t\t/>\n\t);\n}\n\nexport const TableSortableHeader = React.forwardRef<HTMLButtonElement, TableSortableHeaderProps>(\n\t({ children, textAlign = \"start\", sorted, className, ...props }, ref) => {\n\t\tconst label = (\n\t\t\t<span className=\"flex min-w-0 items-center gap-basalt-control-gap truncate\">{children}</span>\n\t\t);\n\t\tconst icon = <SortIcon sorted={sorted} />;\n\t\treturn (\n\t\t\t<button\n\t\t\t\ttype=\"button\"\n\t\t\t\tref={ref}\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"basalt-focus group flex w-full cursor-pointer items-center gap-basalt-space-sm rounded-basalt-sm border-0 bg-transparent p-0 font-inherit text-inherit font-medium\",\n\t\t\t\t\ttextAlign === \"end\" ? \"justify-end text-end\" : \"text-start\",\n\t\t\t\t\tclassName,\n\t\t\t\t)}\n\t\t\t\t{...props}\n\t\t\t>\n\t\t\t\t{textAlign === \"end\" ? (\n\t\t\t\t\t<>\n\t\t\t\t\t\t{icon}\n\t\t\t\t\t\t{label}\n\t\t\t\t\t</>\n\t\t\t\t) : (\n\t\t\t\t\t<>\n\t\t\t\t\t\t{label}\n\t\t\t\t\t\t{icon}\n\t\t\t\t\t</>\n\t\t\t\t)}\n\t\t\t</button>\n\t\t);\n\t},\n);\nTableSortableHeader.displayName = \"TableSortableHeader\";\n"],"mappings":";;;;;;;AAkBA,IAAaG,IAAQF,EAAM,YAGxB,EAAE,cAAW,aAAU,IAAO,GAAGG,KAAS,MAC5C,kBAAC,SAAD;CACM;CACL,qBAAkB;CAClB,gBAAcC,IAAU,SAAS,KAAA;CACjC,WAAWC,EACVC,GACA,+IACAC,CACD;CACA,GAAIJ;AACJ,CAAA,CACD;AACD,EAAM,cAAc;AAIpB,IAAaK,KAAe,MAA4B,kBAAC,SAAD,EAAO,GAAIL,EAAQ,CAAA,GAI9DM,KAAa,MAA0B,kBAAC,SAAD,EAAO,GAAIN,EAAQ,CAAA,GAI1DO,KAAe,MAA4B,kBAAC,SAAD,EAAO,GAAIP,EAAQ,CAAA,GAgB9DQ,KAAY,EACxB,cACA,aAAU,WACV,GAAGR,QAEH,kBAAC,MAAD;CACC,GAAIA;CACJ,iBAAeS,MAAY,cAAoBT,EAAM;CAC1C;AACX,CAAA;AAGF,SAASU,EAAe,GAA4B;CACnD,IAAIC,MAAc,OAAO,OAAO;CAChC,IAAIA,MAAc,SAAS,OAAO;AACnC;AAaA,IAAaC,KAAa,EACzB,cACA,cACA,UACA,GAAGZ,QAEH,kBAAC,MAAD;CACC,WAAWE,EACV,4NACAQ,EAAeC,CAAS,MAAME,KAAS,OAAO,eAAe,KAAA,IAC7DT,CACD;CACO;CACP,GAAIJ;AACJ,CAAA,GAcWc,KAAa,EACzB,cACA,cACA,GAAGd,QAEH,kBAAC,MAAD;CACC,WAAWE,EACV,kGACAQ,EAAeC,CAAS,GACxBP,CACD;CACA,GAAIJ;AACJ,CAAA;AAUF,SAAgBe,EAAa,EAC5B,cACA,GAAGf,KACkE;CACrE,OACC,kBAAC,WAAD;EACC,WAAWE,EACV,qFACAE,CACD;EACA,GAAIJ;CACJ,CAAA;AAEH;AAgBA,SAASgB,EAAS,EAAE,aAA2C;CAE9D,OACC,kBAFYC,MAAW,QAAQC,IAAUD,MAAW,SAASE,IAAYC,GAEzE;EACC,eAAY;EACZ,WAAWlB,EACV,gCACA,CAACe,KACA,gIACF;EACA,aAAa;CACb,CAAA;AAEH;AAEA,IAAaI,IAAsBxB,EAAM,YACvC,EAAE,aAAU,eAAY,SAAS,WAAQ,cAAW,GAAGG,KAAS,MAAQ;CACxE,IAAMsB,IACL,kBAAC,QAAD;EAAM,WAAU;EAA6D;CAAe,CAAA,GAEvFC,IAAO,kBAACP,GAAD,EAAkB,UAAS,CAAA;CACxC,OACC,kBAAC,UAAD;EACC,MAAK;EACA;EACL,WAAWd,EACV,sKACAS,MAAc,QAAQ,yBAAyB,cAC/CP,CACD;EACA,GAAIJ;EAEH,UAAAW,MAAc,QACd,kBAAAf,GAAA,EAAA,UAAA,CACE2B,GACAD,CACA,EAAA,CAAA,IAEF,kBAAA1B,GAAA,EAAA,UAAA,CACE0B,GACAC,CACA,EAAA,CAAA;CAEI,CAAA;AAEV,CACD;AACA,EAAoB,cAAc"}
|
package/dist/components/tabs.js
CHANGED
|
@@ -54,7 +54,7 @@ var d = i.forwardRef(({ className: t, ...r }, i) => /* @__PURE__ */ a(s.Trigger,
|
|
|
54
54
|
d.displayName = s.Trigger.displayName;
|
|
55
55
|
var f = i.forwardRef(({ className: t, ...r }, i) => /* @__PURE__ */ a(s.Content, {
|
|
56
56
|
ref: i,
|
|
57
|
-
className: e("mt-basalt-space-lg text-basalt-base text-basalt-foreground data-[state=active]:animate-basalt-tab-in", n, t),
|
|
57
|
+
className: e("basalt-focus basalt-focus-inset mt-basalt-space-lg text-basalt-base text-basalt-foreground data-[state=active]:animate-basalt-tab-in", n, t),
|
|
58
58
|
...r
|
|
59
59
|
}));
|
|
60
60
|
f.displayName = s.Content.displayName;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tabs.js","names":["React","TabsPrimitive","measureTabUnderline","item","Tabs","props","cn","BASALT_UI_CLASS","className","TabsList","listRef","useSelectionIndicator","showIndicator","children","motionClassName","state","TabsTrigger","OVERLAY_MOTION","TabsContent"],"sources":["../../src/components/tabs.tsx"],"sourcesContent":["import * as TabsPrimitive from \"@radix-ui/react-tabs\";\nimport * as React from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { BASALT_UI_CLASS } from \"../utils/control-surface\";\nimport { useSelectionIndicator } from \"../utils/selection-indicator\";\nimport { OVERLAY_MOTION } from \"./overlay\";\n\nfunction measureTabUnderline(item: HTMLElement): {\n\tleft: number;\n\twidth: number;\n\ttop: number;\n\theight: number;\n} {\n\treturn {\n\t\tleft: item.offsetLeft,\n\t\twidth: item.offsetWidth,\n\t\ttop: item.offsetTop + item.offsetHeight,\n\t\theight: 0,\n\t};\n}\n\nexport type TabsProps = Omit<\n\tReact.ComponentPropsWithoutRef<typeof TabsPrimitive.Root>,\n\t\"value\" | \"defaultValue\" | \"onValueChange\"\n> & {\n\t/**\n\t * The controlled selected tab.\n\t */\n\tvalue?: string;\n\t/**\n\t * The uncontrolled initial tab.\n\t */\n\tdefaultValue?: string;\n\t/**\n\t * Called when the selected tab changes.\n\t */\n\tonValueChange?: (value: string) => void;\n};\nexport const Tabs: React.FC<TabsProps> = React.forwardRef<\n\tReact.ElementRef<typeof TabsPrimitive.Root>,\n\tTabsProps\n>(({ className, ...props }, ref) => (\n\t<TabsPrimitive.Root ref={ref} className={cn(BASALT_UI_CLASS, className)} {...props} />\n));\nTabs.displayName = TabsPrimitive.Root.displayName;\n\nexport type TabsListProps = React.ComponentPropsWithoutRef<typeof TabsPrimitive.List> & {\n\t/**\n\t * Show the sliding active underline.\n\t * @default true\n\t */\n\tshowIndicator?: boolean;\n};\n\nexport const TabsList = React.forwardRef<\n\tReact.ElementRef<typeof TabsPrimitive.List>,\n\tTabsListProps\n>(({ className, children, showIndicator = true, ...props }, ref) => {\n\tconst {\n\t\tref: listRef,\n\t\tstate,\n\t\tmotionClassName,\n\t} = useSelectionIndicator({\n\t\titemSelector: '[role=\"tab\"][data-state=\"active\"]',\n\t\tenabled: showIndicator,\n\t\tmapGeometry: measureTabUnderline,\n\t\tref,\n\t});\n\n\treturn (\n\t\t<TabsPrimitive.List\n\t\t\tref={listRef}\n\t\t\tclassName={cn(\n\t\t\t\t\"relative flex flex-wrap items-center gap-basalt-space-sm border-b border-basalt-border\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t>\n\t\t\t{children}\n\t\t\t{showIndicator ? (\n\t\t\t\t<span\n\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\tdata-slot=\"selection-indicator\"\n\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\"pointer-events-none absolute h-basalt-0_5 bg-basalt-primary\",\n\t\t\t\t\t\tmotionClassName,\n\t\t\t\t\t)}\n\t\t\t\t\tstyle={{\n\t\t\t\t\t\tleft: 0,\n\t\t\t\t\t\ttransform: `translate(${state.left}px, ${state.top}px)`,\n\t\t\t\t\t\twidth: state.visible ? state.width : 0,\n\t\t\t\t\t\ttop: 0,\n\t\t\t\t\t}}\n\t\t\t\t/>\n\t\t\t) : null}\n\t\t</TabsPrimitive.List>\n\t);\n});\nTabsList.displayName = TabsPrimitive.List.displayName;\n\nexport type TabsTriggerProps = Omit<\n\tReact.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>,\n\t\"disabled\" | \"value\"\n> & {\n\t/**\n\t * The tab value.\n\t */\n\tvalue: string;\n\t/**\n\t * Disable the tab trigger.\n\t * @default false\n\t */\n\tdisabled?: boolean;\n};\n\nexport const TabsTrigger = React.forwardRef<\n\tReact.ElementRef<typeof TabsPrimitive.Trigger>,\n\tTabsTriggerProps\n>(({ className, ...props }, ref) => (\n\t<TabsPrimitive.Trigger\n\t\tref={ref}\n\t\tclassName={cn(\n\t\t\t\"basalt-action inline-flex items-center justify-center font-medium text-basalt-muted-foreground transition-colors basalt-motion hover:text-basalt-foreground data-[state=active]:text-basalt-selected-foreground\",\n\t\t\tOVERLAY_MOTION,\n\t\t\tclassName,\n\t\t)}\n\t\t{...props}\n\t/>\n));\nTabsTrigger.displayName = TabsPrimitive.Trigger.displayName;\n\nexport type TabsContentProps = Omit<\n\tReact.ComponentPropsWithoutRef<typeof TabsPrimitive.Content>,\n\t\"value\"\n> & {\n\t/**\n\t * The tab value this panel belongs to.\n\t */\n\tvalue: string;\n};\n\nexport const TabsContent = React.forwardRef<\n\tReact.ElementRef<typeof TabsPrimitive.Content>,\n\tTabsContentProps\n>(({ className, ...props }, ref) => (\n\t<TabsPrimitive.Content\n\t\tref={ref}\n\t\tclassName={cn(\n\t\t\t\"mt-basalt-space-lg text-basalt-base text-basalt-foreground data-[state=active]:animate-basalt-tab-in\",\n\t\t\tOVERLAY_MOTION,\n\t\t\tclassName,\n\t\t)}\n\t\t{...props}\n\t/>\n));\nTabsContent.displayName = TabsPrimitive.Content.displayName;\n"],"mappings":";;;;;;;;;AAOA,SAASE,EAAoB,GAK3B;CACD,OAAO;EACN,MAAMC,EAAK;EACX,OAAOA,EAAK;EACZ,KAAKA,EAAK,YAAYA,EAAK;EAC3B,QAAQ;CACT;AACD;AAmBA,IAAaC,IAA4BJ,EAAM,YAG5C,EAAE,cAAW,GAAGK,KAAS,MAC3B,kBAACJ,EAAc,MAAf;CAAyB;CAAK,WAAWK,EAAGC,GAAiBC,CAAS;CAAG,GAAIH;AAAQ,CAAA,CACrF;AACD,EAAK,cAAcJ,EAAc,KAAK;AAUtC,IAAaQ,IAAWT,EAAM,YAG3B,EAAE,cAAW,aAAU,mBAAgB,IAAM,GAAGK,KAAS,MAAQ;CACnE,IAAM,EACL,KAAKK,GACL,UACA,uBACGC,EAAsB;EACzB,cAAc;EACd,SAASC;EACT,aAAaV;EACb;CACD,CAAC;CAED,OACC,kBAACD,EAAc,MAAf;EACC,KAAKS;EACL,WAAWJ,EACV,0FACAE,CACD;EACA,GAAIH;EANL,UAAA,CAQEQ,GACAD,IACA,kBAAC,QAAD;GACC,eAAY;GACZ,aAAU;GACV,WAAWN,EACV,+DACAQ,CACD;GACA,OAAO;IACN,MAAM;IACN,WAAW,aAAaC,EAAM,KAAK,MAAMA,EAAM,IAAI;IACnD,OAAOA,EAAM,UAAUA,EAAM,QAAQ;IACrC,KAAK;GACN;EACA,CAAA,IACE,IACe;;AAEtB,CAAC;AACD,EAAS,cAAcd,EAAc,KAAK;AAiB1C,IAAae,IAAchB,EAAM,YAG9B,EAAE,cAAW,GAAGK,KAAS,MAC3B,kBAACJ,EAAc,SAAf;CACM;CACL,WAAWK,EACV,mNACAW,GACAT,CACD;CACA,GAAIH;AACJ,CAAA,CACD;AACD,EAAY,cAAcJ,EAAc,QAAQ;AAYhD,IAAaiB,IAAclB,EAAM,YAG9B,EAAE,cAAW,GAAGK,KAAS,MAC3B,kBAACJ,EAAc,SAAf;CACM;CACL,WAAWK,EACV,
|
|
1
|
+
{"version":3,"file":"tabs.js","names":["React","TabsPrimitive","measureTabUnderline","item","Tabs","props","cn","BASALT_UI_CLASS","className","TabsList","listRef","useSelectionIndicator","showIndicator","children","motionClassName","state","TabsTrigger","OVERLAY_MOTION","TabsContent"],"sources":["../../src/components/tabs.tsx"],"sourcesContent":["import * as TabsPrimitive from \"@radix-ui/react-tabs\";\nimport * as React from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { BASALT_UI_CLASS } from \"../utils/control-surface\";\nimport { useSelectionIndicator } from \"../utils/selection-indicator\";\nimport { OVERLAY_MOTION } from \"./overlay\";\n\nfunction measureTabUnderline(item: HTMLElement): {\n\tleft: number;\n\twidth: number;\n\ttop: number;\n\theight: number;\n} {\n\treturn {\n\t\tleft: item.offsetLeft,\n\t\twidth: item.offsetWidth,\n\t\ttop: item.offsetTop + item.offsetHeight,\n\t\theight: 0,\n\t};\n}\n\nexport type TabsProps = Omit<\n\tReact.ComponentPropsWithoutRef<typeof TabsPrimitive.Root>,\n\t\"value\" | \"defaultValue\" | \"onValueChange\"\n> & {\n\t/**\n\t * The controlled selected tab.\n\t */\n\tvalue?: string;\n\t/**\n\t * The uncontrolled initial tab.\n\t */\n\tdefaultValue?: string;\n\t/**\n\t * Called when the selected tab changes.\n\t */\n\tonValueChange?: (value: string) => void;\n};\nexport const Tabs: React.FC<TabsProps> = React.forwardRef<\n\tReact.ElementRef<typeof TabsPrimitive.Root>,\n\tTabsProps\n>(({ className, ...props }, ref) => (\n\t<TabsPrimitive.Root ref={ref} className={cn(BASALT_UI_CLASS, className)} {...props} />\n));\nTabs.displayName = TabsPrimitive.Root.displayName;\n\nexport type TabsListProps = React.ComponentPropsWithoutRef<typeof TabsPrimitive.List> & {\n\t/**\n\t * Show the sliding active underline.\n\t * @default true\n\t */\n\tshowIndicator?: boolean;\n};\n\nexport const TabsList = React.forwardRef<\n\tReact.ElementRef<typeof TabsPrimitive.List>,\n\tTabsListProps\n>(({ className, children, showIndicator = true, ...props }, ref) => {\n\tconst {\n\t\tref: listRef,\n\t\tstate,\n\t\tmotionClassName,\n\t} = useSelectionIndicator({\n\t\titemSelector: '[role=\"tab\"][data-state=\"active\"]',\n\t\tenabled: showIndicator,\n\t\tmapGeometry: measureTabUnderline,\n\t\tref,\n\t});\n\n\treturn (\n\t\t<TabsPrimitive.List\n\t\t\tref={listRef}\n\t\t\tclassName={cn(\n\t\t\t\t\"relative flex flex-wrap items-center gap-basalt-space-sm border-b border-basalt-border\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t>\n\t\t\t{children}\n\t\t\t{showIndicator ? (\n\t\t\t\t<span\n\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\tdata-slot=\"selection-indicator\"\n\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\"pointer-events-none absolute h-basalt-0_5 bg-basalt-primary\",\n\t\t\t\t\t\tmotionClassName,\n\t\t\t\t\t)}\n\t\t\t\t\tstyle={{\n\t\t\t\t\t\tleft: 0,\n\t\t\t\t\t\ttransform: `translate(${state.left}px, ${state.top}px)`,\n\t\t\t\t\t\twidth: state.visible ? state.width : 0,\n\t\t\t\t\t\ttop: 0,\n\t\t\t\t\t}}\n\t\t\t\t/>\n\t\t\t) : null}\n\t\t</TabsPrimitive.List>\n\t);\n});\nTabsList.displayName = TabsPrimitive.List.displayName;\n\nexport type TabsTriggerProps = Omit<\n\tReact.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>,\n\t\"disabled\" | \"value\"\n> & {\n\t/**\n\t * The tab value.\n\t */\n\tvalue: string;\n\t/**\n\t * Disable the tab trigger.\n\t * @default false\n\t */\n\tdisabled?: boolean;\n};\n\nexport const TabsTrigger = React.forwardRef<\n\tReact.ElementRef<typeof TabsPrimitive.Trigger>,\n\tTabsTriggerProps\n>(({ className, ...props }, ref) => (\n\t<TabsPrimitive.Trigger\n\t\tref={ref}\n\t\tclassName={cn(\n\t\t\t\"basalt-action inline-flex items-center justify-center font-medium text-basalt-muted-foreground transition-colors basalt-motion hover:text-basalt-foreground data-[state=active]:text-basalt-selected-foreground\",\n\t\t\tOVERLAY_MOTION,\n\t\t\tclassName,\n\t\t)}\n\t\t{...props}\n\t/>\n));\nTabsTrigger.displayName = TabsPrimitive.Trigger.displayName;\n\nexport type TabsContentProps = Omit<\n\tReact.ComponentPropsWithoutRef<typeof TabsPrimitive.Content>,\n\t\"value\"\n> & {\n\t/**\n\t * The tab value this panel belongs to.\n\t */\n\tvalue: string;\n};\n\nexport const TabsContent = React.forwardRef<\n\tReact.ElementRef<typeof TabsPrimitive.Content>,\n\tTabsContentProps\n>(({ className, ...props }, ref) => (\n\t<TabsPrimitive.Content\n\t\tref={ref}\n\t\tclassName={cn(\n\t\t\t\"basalt-focus basalt-focus-inset mt-basalt-space-lg text-basalt-base text-basalt-foreground data-[state=active]:animate-basalt-tab-in\",\n\t\t\tOVERLAY_MOTION,\n\t\t\tclassName,\n\t\t)}\n\t\t{...props}\n\t/>\n));\nTabsContent.displayName = TabsPrimitive.Content.displayName;\n"],"mappings":";;;;;;;;;AAOA,SAASE,EAAoB,GAK3B;CACD,OAAO;EACN,MAAMC,EAAK;EACX,OAAOA,EAAK;EACZ,KAAKA,EAAK,YAAYA,EAAK;EAC3B,QAAQ;CACT;AACD;AAmBA,IAAaC,IAA4BJ,EAAM,YAG5C,EAAE,cAAW,GAAGK,KAAS,MAC3B,kBAACJ,EAAc,MAAf;CAAyB;CAAK,WAAWK,EAAGC,GAAiBC,CAAS;CAAG,GAAIH;AAAQ,CAAA,CACrF;AACD,EAAK,cAAcJ,EAAc,KAAK;AAUtC,IAAaQ,IAAWT,EAAM,YAG3B,EAAE,cAAW,aAAU,mBAAgB,IAAM,GAAGK,KAAS,MAAQ;CACnE,IAAM,EACL,KAAKK,GACL,UACA,uBACGC,EAAsB;EACzB,cAAc;EACd,SAASC;EACT,aAAaV;EACb;CACD,CAAC;CAED,OACC,kBAACD,EAAc,MAAf;EACC,KAAKS;EACL,WAAWJ,EACV,0FACAE,CACD;EACA,GAAIH;EANL,UAAA,CAQEQ,GACAD,IACA,kBAAC,QAAD;GACC,eAAY;GACZ,aAAU;GACV,WAAWN,EACV,+DACAQ,CACD;GACA,OAAO;IACN,MAAM;IACN,WAAW,aAAaC,EAAM,KAAK,MAAMA,EAAM,IAAI;IACnD,OAAOA,EAAM,UAAUA,EAAM,QAAQ;IACrC,KAAK;GACN;EACA,CAAA,IACE,IACe;;AAEtB,CAAC;AACD,EAAS,cAAcd,EAAc,KAAK;AAiB1C,IAAae,IAAchB,EAAM,YAG9B,EAAE,cAAW,GAAGK,KAAS,MAC3B,kBAACJ,EAAc,SAAf;CACM;CACL,WAAWK,EACV,mNACAW,GACAT,CACD;CACA,GAAIH;AACJ,CAAA,CACD;AACD,EAAY,cAAcJ,EAAc,QAAQ;AAYhD,IAAaiB,IAAclB,EAAM,YAG9B,EAAE,cAAW,GAAGK,KAAS,MAC3B,kBAACJ,EAAc,SAAf;CACM;CACL,WAAWK,EACV,wIACAW,GACAT,CACD;CACA,GAAIH;AACJ,CAAA,CACD;AACD,EAAY,cAAcJ,EAAc,QAAQ"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { cn as e } from "../utils/cn.js";
|
|
3
3
|
import { BASALT_UI_CLASS as t } from "../utils/control-surface.js";
|
|
4
|
-
import {
|
|
4
|
+
import { FOCUS_RING as n } from "./overlay.js";
|
|
5
5
|
import { TAG_COLORS as r } from "./tag-badge.js";
|
|
6
6
|
import { useState as i } from "react";
|
|
7
7
|
import { Check as a } from "lucide-react";
|
|
@@ -26,7 +26,7 @@ function u({ label: u, value: d, defaultValue: f = "slate", onValueChange: p, co
|
|
|
26
26
|
children: m.map((t) => /* @__PURE__ */ s(c.Item, {
|
|
27
27
|
value: t,
|
|
28
28
|
"aria-label": h?.[t] ?? r[t].label,
|
|
29
|
-
className: e("group flex min-w-0 items-center gap-basalt-space-lg rounded-basalt-md p-basalt-space-lg text-left text-basalt-foreground transition-colors hover:bg-basalt-hover data-[state=checked]:bg-basalt-primary data-[state=checked]:text-basalt-primary-foreground disabled:cursor-not-allowed disabled:opacity-50", n
|
|
29
|
+
className: e("group flex min-w-0 items-center gap-basalt-space-lg rounded-basalt-md p-basalt-space-lg text-left text-basalt-foreground transition-colors hover:bg-basalt-hover data-[state=checked]:bg-basalt-primary data-[state=checked]:text-basalt-primary-foreground disabled:cursor-not-allowed disabled:opacity-50", n),
|
|
30
30
|
children: [
|
|
31
31
|
/* @__PURE__ */ o("span", {
|
|
32
32
|
"aria-hidden": "true",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tag-color-picker.js","names":["RadioGroupPrimitive","ALL_COLORS","TAG_COLORS","TagColorPicker","ariaInvalid","describedBy","localValue","setLocalValue","useState","defaultValue","selected","value","label","cn","BASALT_UI_CLASS","className","color","next","onValueChange","colors","labels","
|
|
1
|
+
{"version":3,"file":"tag-color-picker.js","names":["RadioGroupPrimitive","ALL_COLORS","TAG_COLORS","TagColorPicker","ariaInvalid","describedBy","localValue","setLocalValue","useState","defaultValue","selected","value","label","cn","BASALT_UI_CLASS","className","color","next","onValueChange","colors","labels","FOCUS_RING","Check"],"sources":["../../src/components/tag-color-picker.tsx"],"sourcesContent":["import * as RadioGroupPrimitive from \"@radix-ui/react-radio-group\";\nimport { Check } from \"lucide-react\";\nimport { type AriaAttributes, useState } from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { BASALT_UI_CLASS } from \"../utils/control-surface\";\nimport { FOCUS_RING } from \"./overlay\";\nimport { TAG_COLORS, type TagColor } from \"./tag-badge\";\n\nexport interface TagColorPickerProps {\n\t/** Accessible group name. */\n\tlabel: string;\n\t/** Controlled named color. */\n\tvalue?: TagColor;\n\t/** Initial uncontrolled color. @default \"slate\" */\n\tdefaultValue?: TagColor;\n\t/** Color selection request. */\n\tonValueChange?: (value: TagColor) => void;\n\t/** Allowed color subset, in caller-defined order. */\n\tcolors?: readonly TagColor[];\n\t/** Localized visible and accessible color names. */\n\tlabels?: Partial<Record<TagColor, string>>;\n\t/** Disable the picker. @default false */\n\tdisabled?: boolean;\n\t/** Forwarded to the radio group so Field and Label can own it. */\n\tid?: string;\n\t/** Forwarded to the radio group; Field sets it while the value is invalid. */\n\t\"aria-invalid\"?: AriaAttributes[\"aria-invalid\"];\n\t/** Forwarded to the radio group; Field points it at the hint or error. */\n\t\"aria-describedby\"?: string;\n\t/** Additional root classes. */\n\tclassName?: string;\n}\nconst ALL_COLORS = Object.keys(TAG_COLORS) as TagColor[];\nexport function TagColorPicker({\n\tlabel,\n\tvalue,\n\tdefaultValue = \"slate\",\n\tonValueChange,\n\tcolors = ALL_COLORS,\n\tlabels,\n\tdisabled = false,\n\tid,\n\t\"aria-invalid\": ariaInvalid,\n\t\"aria-describedby\": describedBy,\n\tclassName,\n}: TagColorPickerProps) {\n\tconst [localValue, setLocalValue] = useState(defaultValue);\n\tconst selected = value ?? localValue;\n\treturn (\n\t\t<RadioGroupPrimitive.Root\n\t\t\tvalue={selected}\n\t\t\tid={id}\n\t\t\taria-label={label}\n\t\t\taria-invalid={ariaInvalid}\n\t\t\taria-describedby={describedBy}\n\t\t\tdisabled={disabled}\n\t\t\tclassName={cn(\n\t\t\t\tBASALT_UI_CLASS,\n\t\t\t\t\"grid w-full min-w-0 max-w-3xl grid-cols-[repeat(auto-fit,minmax(min(100%,9rem),1fr))] gap-basalt-space-lg\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\tonValueChange={(next) => {\n\t\t\t\tconst color = next as TagColor;\n\t\t\t\tif (value === undefined) setLocalValue(color);\n\t\t\t\tonValueChange?.(color);\n\t\t\t}}\n\t\t>\n\t\t\t{colors.map((color) => (\n\t\t\t\t<RadioGroupPrimitive.Item\n\t\t\t\t\tkey={color}\n\t\t\t\t\tvalue={color}\n\t\t\t\t\taria-label={labels?.[color] ?? TAG_COLORS[color].label}\n\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t// Accent choice grid: the selected tile owns the primary fill and its\n\t\t\t\t\t\t// contrast-corrected foreground, not a control fill inside a frame.\n\t\t\t\t\t\t\"group flex min-w-0 items-center gap-basalt-space-lg rounded-basalt-md p-basalt-space-lg text-left text-basalt-foreground transition-colors hover:bg-basalt-hover data-[state=checked]:bg-basalt-primary data-[state=checked]:text-basalt-primary-foreground disabled:cursor-not-allowed disabled:opacity-50\",\n\t\t\t\t\t\tFOCUS_RING,\n\t\t\t\t\t)}\n\t\t\t\t>\n\t\t\t\t\t<span\n\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\"size-basalt-7 shrink-0 rounded-basalt-md border\",\n\t\t\t\t\t\t\tTAG_COLORS[color].className,\n\t\t\t\t\t\t)}\n\t\t\t\t\t/>\n\t\t\t\t\t<span className=\"min-w-0 flex-1 break-words text-basalt-sm font-medium\">\n\t\t\t\t\t\t{labels?.[color] ?? TAG_COLORS[color].label}\n\t\t\t\t\t</span>\n\t\t\t\t\t<Check\n\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t\tclassName=\"size-basalt-icon shrink-0 opacity-0 group-data-[state=checked]:opacity-100\"\n\t\t\t\t\t/>\n\t\t\t\t</RadioGroupPrimitive.Item>\n\t\t\t))}\n\t\t</RadioGroupPrimitive.Root>\n\t);\n}\n"],"mappings":";;;;;;;;;;AAgCA,IAAMC,IAAa,OAAO,KAAKC,CAAU;AACzC,SAAgBC,EAAe,EAC9B,UACA,UACA,kBAAe,SACf,kBACA,YAASF,GACT,WACA,cAAW,IACX,OACA,gBAAgBG,GAChB,oBAAoBC,GACpB,gBACuB;CACvB,IAAM,CAACC,GAAYC,KAAiBC,EAASC,CAAY,GACnDC,IAAWC,KAASL;CAC1B,OACC,kBAACN,EAAoB,MAArB;EACC,OAAOU;EACH;EACJ,cAAYE;EACZ,gBAAcR;EACd,oBAAkBC;EACR;EACV,WAAWQ,EACVC,GACA,6GACAC,CACD;EACA,gBAAgB,MAAS;GACxB,IAAMC,IAAQC;GAEd,AADIN,MAAU,KAAA,KAAWJ,EAAcS,CAAK,GAC5CE,IAAgBF,CAAK;EACtB;EAEC,UAAAG,EAAO,KAAK,MACZ,kBAACnB,EAAoB,MAArB;GAEC,OAAOgB;GACP,cAAYI,IAASJ,MAAUd,EAAWc,EAAM,CAAC;GACjD,WAAWH,EAGV,+SACAQ,CACD;GATD,UAAA;IAWC,kBAAC,QAAD;KACC,eAAY;KACZ,WAAWR,EACV,mDACAX,EAAWc,EAAM,CAAC,SACnB;IACA,CAAA;IACD,kBAAC,QAAD;KAAM,WAAU;KACd,UAAAI,IAASJ,MAAUd,EAAWc,EAAM,CAAC;IACjC,CAAA;IACN,kBAACM,GAAD;KACC,eAAY;KACZ,WAAU;IACV,CAAA;GACwB;EAxBpB,GAAAN,CAwBoB,CAC1B;CACwB,CAAA;AAE5B"}
|
package/dist/components/toast.js
CHANGED
|
@@ -63,7 +63,7 @@ function p({ closeButton: s = !0, ...l }) {
|
|
|
63
63
|
toast: "basalt-ui basalt-toast flex w-full items-center gap-basalt-space-lg rounded-basalt-md bg-basalt-popover px-basalt-card-lg py-basalt-card text-basalt-base leading-[var(--basalt-leading-banner)] text-basalt-foreground shadow-lg [&_[data-content]]:min-w-0 [&_[data-content]]:flex-1",
|
|
64
64
|
title: "font-medium",
|
|
65
65
|
description: "text-basalt-sm leading-[var(--basalt-line-relaxed)] text-basalt-muted-foreground",
|
|
66
|
-
closeButton: "basalt-action basalt-action-icon order-last inline-flex shrink-0 cursor-pointer items-center justify-center rounded-basalt-sm text-basalt-muted-foreground hover:bg-basalt-hover hover:text-basalt-foreground
|
|
66
|
+
closeButton: "basalt-action basalt-action-icon order-last inline-flex shrink-0 cursor-pointer items-center justify-center rounded-basalt-sm text-basalt-muted-foreground hover:bg-basalt-hover hover:text-basalt-foreground",
|
|
67
67
|
actionButton: "basalt-action shrink-0 cursor-pointer rounded-basalt-sm bg-basalt-primary text-basalt-primary-foreground hover:bg-basalt-primary-hover",
|
|
68
68
|
cancelButton: "basalt-action shrink-0 cursor-pointer rounded-basalt-sm bg-basalt-control hover:bg-basalt-hover",
|
|
69
69
|
icon: "flex size-basalt-icon-lg shrink-0 items-center justify-center",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"toast.js","names":["sonnerToast","Sonner","Toaster$1","toast$1","VARIANT_CLASS","VARIANT_ICON","Check","CircleAlert","TriangleAlert","Info","resolveIcon","icon","variant","show","rest","options","payload","close","message","toast","Toaster","props","X","Toast"],"sources":["../../src/components/toast.tsx"],"sourcesContent":["import { Check, CircleAlert, Info, TriangleAlert, X } from \"lucide-react\";\nimport type { ComponentProps, ReactNode } from \"react\";\nimport { Toaster as Sonner, toast as sonnerToast } from \"sonner\";\n\nexport type ToastVariant = \"default\" | \"success\" | \"error\" | \"warning\" | \"info\";\n\nexport type ToastOptions = {\n\t/**\n\t * Secondary supporting text or node displayed below the main message.\n\t */\n\tdescription?: ReactNode;\n\t/**\n\t * Custom icon override. When set to `false`, suppresses default status or notification icons.\n\t */\n\ticon?: ReactNode | false;\n\t/**\n\t * Whether a close button is displayed on this individual toast notification.\n\t * @default true\n\t */\n\tclose?: boolean;\n\t/**\n\t * Visibility duration in milliseconds before auto-dismissal. Resolved as `toast.duration || (Toaster.toastOptions.duration ?? Toaster.duration) || 4000`. Infinity disables auto-closing. Setting to 0 treats it as falsy and falls back through container duration before defaulting to 4000ms.\n\t * @default \"inherited from container, finally 4000ms\"\n\t */\n\tduration?: number;\n\t/**\n\t * Unique identifier for this toast notification. Can be used with `toast.dismiss(id)` to manually dismiss this specific toast.\n\t */\n\tid?: string | number;\n\t/**\n\t * Optional action button configuration with label and onClick handler.\n\t */\n\taction?: {\n\t\tlabel: string;\n\t\tonClick: () => void;\n\t};\n};\n\n/**\n * Options accepted by the root `toast(message, options)` dispatch function, extending `ToastOptions` with an optional `variant`.\n */\nexport type ToastCallOptions = ToastOptions & {\n\t/**\n\t * Visual status variant style for this toast.\n\t * @default \"default\"\n\t */\n\tvariant?: ToastVariant;\n};\n\nconst VARIANT_CLASS: Record<ToastVariant, string> = {\n\tdefault: \"bg-basalt-popover\",\n\tsuccess:\n\t\t\"bg-basalt-heatmap-green-1 [&_[data-icon]]:text-basalt-heatmap-green-4 [&_[data-title]]:text-basalt-heatmap-green-4\",\n\terror:\n\t\t\"bg-basalt-danger-tint [&_[data-icon]]:text-basalt-danger [&_[data-title]]:text-basalt-danger\",\n\twarning:\n\t\t\"bg-basalt-warning-tint [&_[data-icon]]:text-basalt-warning [&_[data-title]]:text-basalt-warning\",\n\tinfo: \"bg-basalt-info-tint [&_[data-icon]]:text-basalt-info [&_[data-title]]:text-basalt-info\",\n};\n\nconst VARIANT_ICON: Record<ToastVariant, ReactNode> = {\n\tdefault: null,\n\tsuccess: <Check className=\"size-basalt-icon-lg\" />,\n\terror: <CircleAlert className=\"size-basalt-icon-lg\" />,\n\twarning: <TriangleAlert className=\"size-basalt-icon-lg\" />,\n\tinfo: <Info className=\"size-basalt-icon-lg\" />,\n};\n\nfunction resolveIcon(variant: ToastVariant, icon: ToastOptions[\"icon\"]) {\n\tif (icon === false) {\n\t\treturn null;\n\t}\n\tif (icon != null) {\n\t\treturn icon;\n\t}\n\treturn VARIANT_ICON[variant] ?? undefined;\n}\n\n/**\n * Dispatches a toast notification with the given message and options.\n * @param message Main notification content or React node.\n * @param options Notification customization options including optional variant.\n * @returns The unique toast identifier (string or number).\n */\nfunction show(message: ReactNode, options: ToastCallOptions = {}) {\n\tconst { variant = \"default\", icon, close = true, ...rest } = options;\n\tconst payload = {\n\t\t...rest,\n\t\tcloseButton: close,\n\t\tclassName: VARIANT_CLASS[variant],\n\t\ticon: resolveIcon(variant, icon),\n\t};\n\tif (variant === \"success\") {\n\t\treturn sonnerToast.success(message, payload);\n\t}\n\tif (variant === \"error\") {\n\t\treturn sonnerToast.error(message, payload);\n\t}\n\tif (variant === \"warning\") {\n\t\treturn sonnerToast.warning(message, payload);\n\t}\n\tif (variant === \"info\") {\n\t\treturn sonnerToast.info(message, payload);\n\t}\n\treturn sonnerToast(message, payload);\n}\n\n/**\n * Imperative notification dispatcher. Directly callable as `toast(message, options)` to display a default notification, with helper methods for status variants (`success`, `error`, `warning`, `info`) and dismissal (`dismiss`).\n */\nexport const toast = Object.assign(show, {\n\t/**\n\t * Dispatches a success status toast notification.\n\t * @param message Main notification content or React node.\n\t * @param options Notification customization options.\n\t * @returns The unique toast identifier (string or number).\n\t */\n\tsuccess: (message: ReactNode, options?: ToastOptions) =>\n\t\tshow(message, { ...options, variant: \"success\" }),\n\t/**\n\t * Dispatches an error status toast notification.\n\t * @param message Main notification content or React node.\n\t * @param options Notification customization options.\n\t * @returns The unique toast identifier (string or number).\n\t */\n\terror: (message: ReactNode, options?: ToastOptions) =>\n\t\tshow(message, { ...options, variant: \"error\" }),\n\t/**\n\t * Dispatches a warning status toast notification.\n\t * @param message Main notification content or React node.\n\t * @param options Notification customization options.\n\t * @returns The unique toast identifier (string or number).\n\t */\n\twarning: (message: ReactNode, options?: ToastOptions) =>\n\t\tshow(message, { ...options, variant: \"warning\" }),\n\t/**\n\t * Dispatches an info status toast notification.\n\t * @param message Main notification content or React node.\n\t * @param options Notification customization options.\n\t * @returns The unique toast identifier (string or number).\n\t */\n\tinfo: (message: ReactNode, options?: ToastOptions) =>\n\t\tshow(message, { ...options, variant: \"info\" }),\n\t/**\n\t * Dismisses an active toast by its identifier, or dismisses all toasts when called without arguments. Note: Calling without arguments returns `undefined` at runtime; calling with `id` returns the dismissed `id`.\n\t * @param id Optional identifier of the toast to dismiss. When omitted, all toasts are dismissed.\n\t * @returns The dismissed toast identifier if provided, or undefined if dismissed without arguments.\n\t */\n\tdismiss: sonnerToast.dismiss,\n});\n\ntype SonnerComponentProps = ComponentProps<typeof Sonner>;\n\nexport type ToasterToastOptions = NonNullable<SonnerComponentProps[\"toastOptions\"]>;\nexport type ToasterIcons = NonNullable<SonnerComponentProps[\"icons\"]>;\nexport type ToasterSwipeDirection = NonNullable<SonnerComponentProps[\"swipeDirections\"]>[number];\n\nexport interface ToasterProps\n\textends Omit<\n\t\tSonnerComponentProps,\n\t\t| \"id\"\n\t\t| \"invert\"\n\t\t| \"theme\"\n\t\t| \"position\"\n\t\t| \"hotkey\"\n\t\t| \"richColors\"\n\t\t| \"expand\"\n\t\t| \"duration\"\n\t\t| \"gap\"\n\t\t| \"visibleToasts\"\n\t\t| \"closeButton\"\n\t\t| \"toastOptions\"\n\t\t| \"className\"\n\t\t| \"style\"\n\t\t| \"offset\"\n\t\t| \"mobileOffset\"\n\t\t| \"dir\"\n\t\t| \"swipeDirections\"\n\t\t| \"icons\"\n\t\t| \"containerAriaLabel\"\n\t\t| \"customAriaLabel\"\n\t> {\n\t/**\n\t * Unique identifier for this toaster instance. When set, only toasts dispatched with a matching toasterId will display here. Basalt standard toast options do not expose toasterId, so global un-identified mounting is recommended.\n\t */\n\tid?: SonnerComponentProps[\"id\"];\n\t/**\n\t * Invert toast foreground and background colors.\n\t * @default false\n\t */\n\tinvert?: SonnerComponentProps[\"invert\"];\n\t/**\n\t * Color scheme theme override for toast notifications.\n\t * @default \"light\"\n\t */\n\ttheme?: SonnerComponentProps[\"theme\"];\n\t/**\n\t * Screen positioning for the toast viewport stack.\n\t * @default \"bottom-right\"\n\t */\n\tposition?: SonnerComponentProps[\"position\"];\n\t/**\n\t * Keyboard hotkey combination to expand and focus the toast viewport.\n\t * @default [\"altKey\", \"KeyT\"]\n\t */\n\thotkey?: SonnerComponentProps[\"hotkey\"];\n\t/**\n\t * Whether rich semantic colors should be applied to default notification styles.\n\t * @default false\n\t */\n\trichColors?: SonnerComponentProps[\"richColors\"];\n\t/**\n\t * Whether toasts should be expanded by default rather than collapsed into a stacked pile.\n\t * @default false\n\t */\n\texpand?: SonnerComponentProps[\"expand\"];\n\t/**\n\t * Default visibility duration in milliseconds before auto-dismissal. Resolved as `toast.duration || (Toaster.toastOptions.duration ?? Toaster.duration) || 4000`. Passing Infinity prevents auto-closing. When `toastOptions.duration === 0`, it is treated as falsy and bypasses `Toaster.duration`, falling back to 4000.\n\t * @default 4000\n\t */\n\tduration?: SonnerComponentProps[\"duration\"];\n\t/**\n\t * Pixel gap between stacked toasts.\n\t * @default 14\n\t */\n\tgap?: SonnerComponentProps[\"gap\"];\n\t/**\n\t * Maximum number of toasts visible simultaneously in the stack.\n\t * @default 3\n\t */\n\tvisibleToasts?: SonnerComponentProps[\"visibleToasts\"];\n\t/**\n\t * Whether a close button is displayed on each toast notification. Basalt enables this by default (`closeButton = true`), and Basalt single-toast calls also default to `close: true`, overriding `Toaster.closeButton = false`. To hide the close button on an individual toast, pass `close: false` in the dispatch options.\n\t * @default true\n\t */\n\tcloseButton?: SonnerComponentProps[\"closeButton\"];\n\t/**\n\t * Default options and custom class names applied to all rendered toasts. Passing a custom `toastOptions` object will override Basalt default styling rather than deep-merging.\n\t */\n\ttoastOptions?: ToasterToastOptions;\n\t/**\n\t * Additional CSS class name applied to each rendered ordered list (`ol`) toast viewport.\n\t */\n\tclassName?: SonnerComponentProps[\"className\"];\n\t/**\n\t * Inline style properties applied to each rendered ordered list (`ol`) toast viewport.\n\t */\n\tstyle?: SonnerComponentProps[\"style\"];\n\t/**\n\t * Viewport offset margin from screen edges on desktop screens.\n\t * @default \"24px\"\n\t */\n\toffset?: SonnerComponentProps[\"offset\"];\n\t/**\n\t * Viewport offset margin from screen edges on mobile devices.\n\t * @default \"16px\"\n\t */\n\tmobileOffset?: SonnerComponentProps[\"mobileOffset\"];\n\t/**\n\t * Layout direction of the notification viewport ('ltr', 'rtl', or document direction when unspecified).\n\t * @default document direction\n\t */\n\tdir?: SonnerComponentProps[\"dir\"];\n\t/**\n\t * Allowed swipe directions to dismiss toasts. Defaults based on position orientation (e.g. ['bottom', 'right'] for bottom-right).\n\t */\n\tswipeDirections?: ToasterSwipeDirection[];\n\t/**\n\t * Custom icon overrides for toast status variants. Basalt preconfigures Lucide icons; passing an `icons` object replaces defaults rather than deep-merging. Basalt status variant dispatches (`toast.success`, `error`, `warning`, `info`) supply default status icons directly, which take precedence over `Toaster.icons`; custom individual toast icons should be passed via `options.icon`.\n\t */\n\ticons?: ToasterIcons;\n\t/**\n\t * Accessible label for the notification region container.\n\t * @default \"Notifications\"\n\t */\n\tcontainerAriaLabel?: SonnerComponentProps[\"containerAriaLabel\"];\n\t/**\n\t * Custom accessible label overriding both containerAriaLabel and hotkey text on the section wrapper.\n\t */\n\tcustomAriaLabel?: SonnerComponentProps[\"customAriaLabel\"];\n}\n\nexport function Toaster({ closeButton = true, ...props }: ToasterProps) {\n\treturn (\n\t\t<Sonner\n\t\t\tcloseButton={closeButton}\n\t\t\ticons={{\n\t\t\t\tsuccess: <Check className=\"size-basalt-icon-lg\" />,\n\t\t\t\terror: <CircleAlert className=\"size-basalt-icon-lg\" />,\n\t\t\t\twarning: <TriangleAlert className=\"size-basalt-icon-lg\" />,\n\t\t\t\tinfo: <Info className=\"size-basalt-icon-lg\" />,\n\t\t\t\tclose: <X className=\"size-basalt-icon\" />,\n\t\t\t}}\n\t\t\ttoastOptions={{\n\t\t\t\tunstyled: true,\n\t\t\t\tclassNames: {\n\t\t\t\t\ttoast:\n\t\t\t\t\t\t\"basalt-ui basalt-toast flex w-full items-center gap-basalt-space-lg rounded-basalt-md bg-basalt-popover px-basalt-card-lg py-basalt-card text-basalt-base leading-[var(--basalt-leading-banner)] text-basalt-foreground shadow-lg [&_[data-content]]:min-w-0 [&_[data-content]]:flex-1\",\n\t\t\t\t\ttitle: \"font-medium\",\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t\"text-basalt-sm leading-[var(--basalt-line-relaxed)] text-basalt-muted-foreground\",\n\t\t\t\t\tcloseButton:\n\t\t\t\t\t\t\"basalt-action basalt-action-icon order-last inline-flex shrink-0 cursor-pointer items-center justify-center rounded-basalt-sm text-basalt-muted-foreground hover:bg-basalt-hover hover:text-basalt-foreground focus-visible:ring-2 focus-visible:ring-basalt-ring\",\n\t\t\t\t\tactionButton:\n\t\t\t\t\t\t\"basalt-action shrink-0 cursor-pointer rounded-basalt-sm bg-basalt-primary text-basalt-primary-foreground hover:bg-basalt-primary-hover\",\n\t\t\t\t\tcancelButton:\n\t\t\t\t\t\t\"basalt-action shrink-0 cursor-pointer rounded-basalt-sm bg-basalt-control hover:bg-basalt-hover\",\n\t\t\t\t\ticon: \"flex size-basalt-icon-lg shrink-0 items-center justify-center\",\n\t\t\t\t\tsuccess: VARIANT_CLASS.success,\n\t\t\t\t\terror: VARIANT_CLASS.error,\n\t\t\t\t\twarning: VARIANT_CLASS.warning,\n\t\t\t\t\tinfo: VARIANT_CLASS.info,\n\t\t\t\t},\n\t\t\t}}\n\t\t\t{...props}\n\t\t/>\n\t);\n}\n\nexport const Toast = Toaster;\n"],"mappings":";;;;;AAiDA,IAAMI,IAA8C;CACnD,SAAS;CACT,SACC;CACD,OACC;CACD,SACC;CACD,MAAM;AACP,GAEMC,IAAgD;CACrD,SAAS;CACT,SAAS,kBAACC,GAAD,EAAO,WAAU,sBAAuB,CAAA;CACjD,OAAO,kBAACC,GAAD,EAAa,WAAU,sBAAuB,CAAA;CACrD,SAAS,kBAACC,GAAD,EAAe,WAAU,sBAAuB,CAAA;CACzD,MAAM,kBAACC,GAAD,EAAM,WAAU,sBAAuB,CAAA;AAC9C;AAEA,SAASC,EAAY,GAAuB,GAA4B;CAOvE,OANIC,MAAS,KACL,OAEJA,KAGGN,EAAaO,MAAY,KAAA;AACjC;AAQA,SAASC,EAAK,GAAoB,IAA4B,CAAC,GAAG;CACjE,IAAM,EAAE,aAAU,WAAW,SAAM,WAAQ,IAAM,GAAGC,MAASC,GACvDC,IAAU;EACf,GAAGF;EACH,aAAaG;EACb,WAAWb,EAAcQ;EACzB,MAAMF,EAAYE,GAASD,CAAI;CAChC;CAaA,OAZIC,MAAY,YACRZ,EAAY,QAAQkB,GAASF,CAAO,IAExCJ,MAAY,UACRZ,EAAY,MAAMkB,GAASF,CAAO,IAEtCJ,MAAY,YACRZ,EAAY,QAAQkB,GAASF,CAAO,IAExCJ,MAAY,SACRZ,EAAY,KAAKkB,GAASF,CAAO,IAElChB,EAAYkB,GAASF,CAAO;AACpC;AAKA,IAAaG,IAAQ,OAAO,OAAON,GAAM;CAOxC,UAAU,GAAoB,MAC7BA,EAAKK,GAAS;EAAE,GAAGH;EAAS,SAAS;CAAU,CAAC;CAOjD,QAAQ,GAAoB,MAC3BF,EAAKK,GAAS;EAAE,GAAGH;EAAS,SAAS;CAAQ,CAAC;CAO/C,UAAU,GAAoB,MAC7BF,EAAKK,GAAS;EAAE,GAAGH;EAAS,SAAS;CAAU,CAAC;CAOjD,OAAO,GAAoB,MAC1BF,EAAKK,GAAS;EAAE,GAAGH;EAAS,SAAS;CAAO,CAAC;CAM9C,SAASf,EAAY;AACtB,CAAC;AAqID,SAAgBoB,EAAQ,EAAE,iBAAc,IAAM,GAAGC,KAAuB;CACvE,OACC,kBAACpB,GAAD;EACc;EACb,OAAO;GACN,SAAS,kBAACK,GAAD,EAAO,WAAU,sBAAuB,CAAA;GACjD,OAAO,kBAACC,GAAD,EAAa,WAAU,sBAAuB,CAAA;GACrD,SAAS,kBAACC,GAAD,EAAe,WAAU,sBAAuB,CAAA;GACzD,MAAM,kBAACC,GAAD,EAAM,WAAU,sBAAuB,CAAA;GAC7C,OAAO,kBAACa,GAAD,EAAG,WAAU,mBAAoB,CAAA;EACzC;EACA,cAAc;GACb,UAAU;GACV,YAAY;IACX,OACC;IACD,OAAO;IACP,aACC;IACD,aACC;IACD,cACC;IACD,cACC;IACD,MAAM;IACN,SAASlB,EAAc;IACvB,OAAOA,EAAc;IACrB,SAASA,EAAc;IACvB,MAAMA,EAAc;GACrB;EACD;EACA,GAAIiB;CACJ,CAAA;AAEH;AAEA,IAAaE,IAAQH"}
|
|
1
|
+
{"version":3,"file":"toast.js","names":["sonnerToast","Sonner","Toaster$1","toast$1","VARIANT_CLASS","VARIANT_ICON","Check","CircleAlert","TriangleAlert","Info","resolveIcon","icon","variant","show","rest","options","payload","close","message","toast","Toaster","props","X","Toast"],"sources":["../../src/components/toast.tsx"],"sourcesContent":["import { Check, CircleAlert, Info, TriangleAlert, X } from \"lucide-react\";\nimport type { ComponentProps, ReactNode } from \"react\";\nimport { Toaster as Sonner, toast as sonnerToast } from \"sonner\";\n\nexport type ToastVariant = \"default\" | \"success\" | \"error\" | \"warning\" | \"info\";\n\nexport type ToastOptions = {\n\t/**\n\t * Secondary supporting text or node displayed below the main message.\n\t */\n\tdescription?: ReactNode;\n\t/**\n\t * Custom icon override. When set to `false`, suppresses default status or notification icons.\n\t */\n\ticon?: ReactNode | false;\n\t/**\n\t * Whether a close button is displayed on this individual toast notification.\n\t * @default true\n\t */\n\tclose?: boolean;\n\t/**\n\t * Visibility duration in milliseconds before auto-dismissal. Resolved as `toast.duration || (Toaster.toastOptions.duration ?? Toaster.duration) || 4000`. Infinity disables auto-closing. Setting to 0 treats it as falsy and falls back through container duration before defaulting to 4000ms.\n\t * @default \"inherited from container, finally 4000ms\"\n\t */\n\tduration?: number;\n\t/**\n\t * Unique identifier for this toast notification. Can be used with `toast.dismiss(id)` to manually dismiss this specific toast.\n\t */\n\tid?: string | number;\n\t/**\n\t * Optional action button configuration with label and onClick handler.\n\t */\n\taction?: {\n\t\tlabel: string;\n\t\tonClick: () => void;\n\t};\n};\n\n/**\n * Options accepted by the root `toast(message, options)` dispatch function, extending `ToastOptions` with an optional `variant`.\n */\nexport type ToastCallOptions = ToastOptions & {\n\t/**\n\t * Visual status variant style for this toast.\n\t * @default \"default\"\n\t */\n\tvariant?: ToastVariant;\n};\n\nconst VARIANT_CLASS: Record<ToastVariant, string> = {\n\tdefault: \"bg-basalt-popover\",\n\tsuccess:\n\t\t\"bg-basalt-heatmap-green-1 [&_[data-icon]]:text-basalt-heatmap-green-4 [&_[data-title]]:text-basalt-heatmap-green-4\",\n\terror:\n\t\t\"bg-basalt-danger-tint [&_[data-icon]]:text-basalt-danger [&_[data-title]]:text-basalt-danger\",\n\twarning:\n\t\t\"bg-basalt-warning-tint [&_[data-icon]]:text-basalt-warning [&_[data-title]]:text-basalt-warning\",\n\tinfo: \"bg-basalt-info-tint [&_[data-icon]]:text-basalt-info [&_[data-title]]:text-basalt-info\",\n};\n\nconst VARIANT_ICON: Record<ToastVariant, ReactNode> = {\n\tdefault: null,\n\tsuccess: <Check className=\"size-basalt-icon-lg\" />,\n\terror: <CircleAlert className=\"size-basalt-icon-lg\" />,\n\twarning: <TriangleAlert className=\"size-basalt-icon-lg\" />,\n\tinfo: <Info className=\"size-basalt-icon-lg\" />,\n};\n\nfunction resolveIcon(variant: ToastVariant, icon: ToastOptions[\"icon\"]) {\n\tif (icon === false) {\n\t\treturn null;\n\t}\n\tif (icon != null) {\n\t\treturn icon;\n\t}\n\treturn VARIANT_ICON[variant] ?? undefined;\n}\n\n/**\n * Dispatches a toast notification with the given message and options.\n * @param message Main notification content or React node.\n * @param options Notification customization options including optional variant.\n * @returns The unique toast identifier (string or number).\n */\nfunction show(message: ReactNode, options: ToastCallOptions = {}) {\n\tconst { variant = \"default\", icon, close = true, ...rest } = options;\n\tconst payload = {\n\t\t...rest,\n\t\tcloseButton: close,\n\t\tclassName: VARIANT_CLASS[variant],\n\t\ticon: resolveIcon(variant, icon),\n\t};\n\tif (variant === \"success\") {\n\t\treturn sonnerToast.success(message, payload);\n\t}\n\tif (variant === \"error\") {\n\t\treturn sonnerToast.error(message, payload);\n\t}\n\tif (variant === \"warning\") {\n\t\treturn sonnerToast.warning(message, payload);\n\t}\n\tif (variant === \"info\") {\n\t\treturn sonnerToast.info(message, payload);\n\t}\n\treturn sonnerToast(message, payload);\n}\n\n/**\n * Imperative notification dispatcher. Directly callable as `toast(message, options)` to display a default notification, with helper methods for status variants (`success`, `error`, `warning`, `info`) and dismissal (`dismiss`).\n */\nexport const toast = Object.assign(show, {\n\t/**\n\t * Dispatches a success status toast notification.\n\t * @param message Main notification content or React node.\n\t * @param options Notification customization options.\n\t * @returns The unique toast identifier (string or number).\n\t */\n\tsuccess: (message: ReactNode, options?: ToastOptions) =>\n\t\tshow(message, { ...options, variant: \"success\" }),\n\t/**\n\t * Dispatches an error status toast notification.\n\t * @param message Main notification content or React node.\n\t * @param options Notification customization options.\n\t * @returns The unique toast identifier (string or number).\n\t */\n\terror: (message: ReactNode, options?: ToastOptions) =>\n\t\tshow(message, { ...options, variant: \"error\" }),\n\t/**\n\t * Dispatches a warning status toast notification.\n\t * @param message Main notification content or React node.\n\t * @param options Notification customization options.\n\t * @returns The unique toast identifier (string or number).\n\t */\n\twarning: (message: ReactNode, options?: ToastOptions) =>\n\t\tshow(message, { ...options, variant: \"warning\" }),\n\t/**\n\t * Dispatches an info status toast notification.\n\t * @param message Main notification content or React node.\n\t * @param options Notification customization options.\n\t * @returns The unique toast identifier (string or number).\n\t */\n\tinfo: (message: ReactNode, options?: ToastOptions) =>\n\t\tshow(message, { ...options, variant: \"info\" }),\n\t/**\n\t * Dismisses an active toast by its identifier, or dismisses all toasts when called without arguments. Note: Calling without arguments returns `undefined` at runtime; calling with `id` returns the dismissed `id`.\n\t * @param id Optional identifier of the toast to dismiss. When omitted, all toasts are dismissed.\n\t * @returns The dismissed toast identifier if provided, or undefined if dismissed without arguments.\n\t */\n\tdismiss: sonnerToast.dismiss,\n});\n\ntype SonnerComponentProps = ComponentProps<typeof Sonner>;\n\nexport type ToasterToastOptions = NonNullable<SonnerComponentProps[\"toastOptions\"]>;\nexport type ToasterIcons = NonNullable<SonnerComponentProps[\"icons\"]>;\nexport type ToasterSwipeDirection = NonNullable<SonnerComponentProps[\"swipeDirections\"]>[number];\n\nexport interface ToasterProps\n\textends Omit<\n\t\tSonnerComponentProps,\n\t\t| \"id\"\n\t\t| \"invert\"\n\t\t| \"theme\"\n\t\t| \"position\"\n\t\t| \"hotkey\"\n\t\t| \"richColors\"\n\t\t| \"expand\"\n\t\t| \"duration\"\n\t\t| \"gap\"\n\t\t| \"visibleToasts\"\n\t\t| \"closeButton\"\n\t\t| \"toastOptions\"\n\t\t| \"className\"\n\t\t| \"style\"\n\t\t| \"offset\"\n\t\t| \"mobileOffset\"\n\t\t| \"dir\"\n\t\t| \"swipeDirections\"\n\t\t| \"icons\"\n\t\t| \"containerAriaLabel\"\n\t\t| \"customAriaLabel\"\n\t> {\n\t/**\n\t * Unique identifier for this toaster instance. When set, only toasts dispatched with a matching toasterId will display here. Basalt standard toast options do not expose toasterId, so global un-identified mounting is recommended.\n\t */\n\tid?: SonnerComponentProps[\"id\"];\n\t/**\n\t * Invert toast foreground and background colors.\n\t * @default false\n\t */\n\tinvert?: SonnerComponentProps[\"invert\"];\n\t/**\n\t * Color scheme theme override for toast notifications.\n\t * @default \"light\"\n\t */\n\ttheme?: SonnerComponentProps[\"theme\"];\n\t/**\n\t * Screen positioning for the toast viewport stack.\n\t * @default \"bottom-right\"\n\t */\n\tposition?: SonnerComponentProps[\"position\"];\n\t/**\n\t * Keyboard hotkey combination to expand and focus the toast viewport.\n\t * @default [\"altKey\", \"KeyT\"]\n\t */\n\thotkey?: SonnerComponentProps[\"hotkey\"];\n\t/**\n\t * Whether rich semantic colors should be applied to default notification styles.\n\t * @default false\n\t */\n\trichColors?: SonnerComponentProps[\"richColors\"];\n\t/**\n\t * Whether toasts should be expanded by default rather than collapsed into a stacked pile.\n\t * @default false\n\t */\n\texpand?: SonnerComponentProps[\"expand\"];\n\t/**\n\t * Default visibility duration in milliseconds before auto-dismissal. Resolved as `toast.duration || (Toaster.toastOptions.duration ?? Toaster.duration) || 4000`. Passing Infinity prevents auto-closing. When `toastOptions.duration === 0`, it is treated as falsy and bypasses `Toaster.duration`, falling back to 4000.\n\t * @default 4000\n\t */\n\tduration?: SonnerComponentProps[\"duration\"];\n\t/**\n\t * Pixel gap between stacked toasts.\n\t * @default 14\n\t */\n\tgap?: SonnerComponentProps[\"gap\"];\n\t/**\n\t * Maximum number of toasts visible simultaneously in the stack.\n\t * @default 3\n\t */\n\tvisibleToasts?: SonnerComponentProps[\"visibleToasts\"];\n\t/**\n\t * Whether a close button is displayed on each toast notification. Basalt enables this by default (`closeButton = true`), and Basalt single-toast calls also default to `close: true`, overriding `Toaster.closeButton = false`. To hide the close button on an individual toast, pass `close: false` in the dispatch options.\n\t * @default true\n\t */\n\tcloseButton?: SonnerComponentProps[\"closeButton\"];\n\t/**\n\t * Default options and custom class names applied to all rendered toasts. Passing a custom `toastOptions` object will override Basalt default styling rather than deep-merging.\n\t */\n\ttoastOptions?: ToasterToastOptions;\n\t/**\n\t * Additional CSS class name applied to each rendered ordered list (`ol`) toast viewport.\n\t */\n\tclassName?: SonnerComponentProps[\"className\"];\n\t/**\n\t * Inline style properties applied to each rendered ordered list (`ol`) toast viewport.\n\t */\n\tstyle?: SonnerComponentProps[\"style\"];\n\t/**\n\t * Viewport offset margin from screen edges on desktop screens.\n\t * @default \"24px\"\n\t */\n\toffset?: SonnerComponentProps[\"offset\"];\n\t/**\n\t * Viewport offset margin from screen edges on mobile devices.\n\t * @default \"16px\"\n\t */\n\tmobileOffset?: SonnerComponentProps[\"mobileOffset\"];\n\t/**\n\t * Layout direction of the notification viewport ('ltr', 'rtl', or document direction when unspecified).\n\t * @default document direction\n\t */\n\tdir?: SonnerComponentProps[\"dir\"];\n\t/**\n\t * Allowed swipe directions to dismiss toasts. Defaults based on position orientation (e.g. ['bottom', 'right'] for bottom-right).\n\t */\n\tswipeDirections?: ToasterSwipeDirection[];\n\t/**\n\t * Custom icon overrides for toast status variants. Basalt preconfigures Lucide icons; passing an `icons` object replaces defaults rather than deep-merging. Basalt status variant dispatches (`toast.success`, `error`, `warning`, `info`) supply default status icons directly, which take precedence over `Toaster.icons`; custom individual toast icons should be passed via `options.icon`.\n\t */\n\ticons?: ToasterIcons;\n\t/**\n\t * Accessible label for the notification region container.\n\t * @default \"Notifications\"\n\t */\n\tcontainerAriaLabel?: SonnerComponentProps[\"containerAriaLabel\"];\n\t/**\n\t * Custom accessible label overriding both containerAriaLabel and hotkey text on the section wrapper.\n\t */\n\tcustomAriaLabel?: SonnerComponentProps[\"customAriaLabel\"];\n}\n\nexport function Toaster({ closeButton = true, ...props }: ToasterProps) {\n\treturn (\n\t\t<Sonner\n\t\t\tcloseButton={closeButton}\n\t\t\ticons={{\n\t\t\t\tsuccess: <Check className=\"size-basalt-icon-lg\" />,\n\t\t\t\terror: <CircleAlert className=\"size-basalt-icon-lg\" />,\n\t\t\t\twarning: <TriangleAlert className=\"size-basalt-icon-lg\" />,\n\t\t\t\tinfo: <Info className=\"size-basalt-icon-lg\" />,\n\t\t\t\tclose: <X className=\"size-basalt-icon\" />,\n\t\t\t}}\n\t\t\ttoastOptions={{\n\t\t\t\tunstyled: true,\n\t\t\t\tclassNames: {\n\t\t\t\t\ttoast:\n\t\t\t\t\t\t\"basalt-ui basalt-toast flex w-full items-center gap-basalt-space-lg rounded-basalt-md bg-basalt-popover px-basalt-card-lg py-basalt-card text-basalt-base leading-[var(--basalt-leading-banner)] text-basalt-foreground shadow-lg [&_[data-content]]:min-w-0 [&_[data-content]]:flex-1\",\n\t\t\t\t\ttitle: \"font-medium\",\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t\"text-basalt-sm leading-[var(--basalt-line-relaxed)] text-basalt-muted-foreground\",\n\t\t\t\t\tcloseButton:\n\t\t\t\t\t\t\"basalt-action basalt-action-icon order-last inline-flex shrink-0 cursor-pointer items-center justify-center rounded-basalt-sm text-basalt-muted-foreground hover:bg-basalt-hover hover:text-basalt-foreground\",\n\t\t\t\t\tactionButton:\n\t\t\t\t\t\t\"basalt-action shrink-0 cursor-pointer rounded-basalt-sm bg-basalt-primary text-basalt-primary-foreground hover:bg-basalt-primary-hover\",\n\t\t\t\t\tcancelButton:\n\t\t\t\t\t\t\"basalt-action shrink-0 cursor-pointer rounded-basalt-sm bg-basalt-control hover:bg-basalt-hover\",\n\t\t\t\t\ticon: \"flex size-basalt-icon-lg shrink-0 items-center justify-center\",\n\t\t\t\t\tsuccess: VARIANT_CLASS.success,\n\t\t\t\t\terror: VARIANT_CLASS.error,\n\t\t\t\t\twarning: VARIANT_CLASS.warning,\n\t\t\t\t\tinfo: VARIANT_CLASS.info,\n\t\t\t\t},\n\t\t\t}}\n\t\t\t{...props}\n\t\t/>\n\t);\n}\n\nexport const Toast = Toaster;\n"],"mappings":";;;;;AAiDA,IAAMI,IAA8C;CACnD,SAAS;CACT,SACC;CACD,OACC;CACD,SACC;CACD,MAAM;AACP,GAEMC,IAAgD;CACrD,SAAS;CACT,SAAS,kBAACC,GAAD,EAAO,WAAU,sBAAuB,CAAA;CACjD,OAAO,kBAACC,GAAD,EAAa,WAAU,sBAAuB,CAAA;CACrD,SAAS,kBAACC,GAAD,EAAe,WAAU,sBAAuB,CAAA;CACzD,MAAM,kBAACC,GAAD,EAAM,WAAU,sBAAuB,CAAA;AAC9C;AAEA,SAASC,EAAY,GAAuB,GAA4B;CAOvE,OANIC,MAAS,KACL,OAEJA,KAGGN,EAAaO,MAAY,KAAA;AACjC;AAQA,SAASC,EAAK,GAAoB,IAA4B,CAAC,GAAG;CACjE,IAAM,EAAE,aAAU,WAAW,SAAM,WAAQ,IAAM,GAAGC,MAASC,GACvDC,IAAU;EACf,GAAGF;EACH,aAAaG;EACb,WAAWb,EAAcQ;EACzB,MAAMF,EAAYE,GAASD,CAAI;CAChC;CAaA,OAZIC,MAAY,YACRZ,EAAY,QAAQkB,GAASF,CAAO,IAExCJ,MAAY,UACRZ,EAAY,MAAMkB,GAASF,CAAO,IAEtCJ,MAAY,YACRZ,EAAY,QAAQkB,GAASF,CAAO,IAExCJ,MAAY,SACRZ,EAAY,KAAKkB,GAASF,CAAO,IAElChB,EAAYkB,GAASF,CAAO;AACpC;AAKA,IAAaG,IAAQ,OAAO,OAAON,GAAM;CAOxC,UAAU,GAAoB,MAC7BA,EAAKK,GAAS;EAAE,GAAGH;EAAS,SAAS;CAAU,CAAC;CAOjD,QAAQ,GAAoB,MAC3BF,EAAKK,GAAS;EAAE,GAAGH;EAAS,SAAS;CAAQ,CAAC;CAO/C,UAAU,GAAoB,MAC7BF,EAAKK,GAAS;EAAE,GAAGH;EAAS,SAAS;CAAU,CAAC;CAOjD,OAAO,GAAoB,MAC1BF,EAAKK,GAAS;EAAE,GAAGH;EAAS,SAAS;CAAO,CAAC;CAM9C,SAASf,EAAY;AACtB,CAAC;AAqID,SAAgBoB,EAAQ,EAAE,iBAAc,IAAM,GAAGC,KAAuB;CACvE,OACC,kBAACpB,GAAD;EACc;EACb,OAAO;GACN,SAAS,kBAACK,GAAD,EAAO,WAAU,sBAAuB,CAAA;GACjD,OAAO,kBAACC,GAAD,EAAa,WAAU,sBAAuB,CAAA;GACrD,SAAS,kBAACC,GAAD,EAAe,WAAU,sBAAuB,CAAA;GACzD,MAAM,kBAACC,GAAD,EAAM,WAAU,sBAAuB,CAAA;GAC7C,OAAO,kBAACa,GAAD,EAAG,WAAU,mBAAoB,CAAA;EACzC;EACA,cAAc;GACb,UAAU;GACV,YAAY;IACX,OACC;IACD,OAAO;IACP,aACC;IACD,aACC;IACD,cACC;IACD,cACC;IACD,MAAM;IACN,SAASlB,EAAc;IACvB,OAAOA,EAAc;IACrB,SAASA,EAAc;IACvB,MAAMA,EAAc;GACrB;EACD;EACA,GAAIiB;CACJ,CAAA;AAEH;AAEA,IAAaE,IAAQH"}
|
|
@@ -47,16 +47,16 @@ var l = i.forwardRef(({ className: t, onKeyDown: n, onFocus: r, ...o }, l) => {
|
|
|
47
47
|
});
|
|
48
48
|
});
|
|
49
49
|
l.displayName = "Toolbar";
|
|
50
|
-
var u = i.forwardRef(({ className:
|
|
51
|
-
let
|
|
50
|
+
var u = i.forwardRef(({ className: r, size: i, icon: s, children: c, ...l }, u) => {
|
|
51
|
+
let d = i ?? (s && c == null ? "icon" : "default");
|
|
52
52
|
return /* @__PURE__ */ a(n, {
|
|
53
|
-
ref:
|
|
54
|
-
icon:
|
|
55
|
-
className: e(o, "h-auto min-h-basalt-control shrink-0",
|
|
56
|
-
...
|
|
53
|
+
ref: u,
|
|
54
|
+
icon: s,
|
|
55
|
+
className: e(o, t, "h-auto min-h-basalt-control shrink-0", d === "icon" && "w-basalt-control", r),
|
|
56
|
+
...l,
|
|
57
57
|
variant: "ghost",
|
|
58
|
-
size:
|
|
59
|
-
children:
|
|
58
|
+
size: d,
|
|
59
|
+
children: c
|
|
60
60
|
});
|
|
61
61
|
});
|
|
62
62
|
u.displayName = "Toolbar.Button";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"toolbar.js","names":["React","toolbarControlClass","cn","toolbarItems","root","node","setRovingTab","item","items","active","ToolbarRoot","props","innerRef","ref","event","target","onKeyDown","start","index","className","ToolbarButton","resolvedSize","size","icon","children","Button","
|
|
1
|
+
{"version":3,"file":"toolbar.js","names":["React","toolbarControlClass","cn","toolbarItems","root","node","setRovingTab","item","items","active","ToolbarRoot","props","innerRef","ref","event","target","onKeyDown","start","index","className","ToolbarButton","resolvedSize","size","icon","children","Button","FOCUS_INSET","ToolbarInput","Input","Toolbar"],"sources":["../../src/components/toolbar.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { Button, type ButtonProps } from \"./button\";\nimport { Input } from \"./input\";\nimport { FOCUS_INSET } from \"./overlay\";\n\nconst toolbarControlClass = cn(\n\t\"relative min-w-0 rounded-none border-0 bg-transparent shadow-none\",\n\t\"first:rounded-l-basalt-md last:rounded-r-basalt-md\",\n\t\"focus-within:z-2 focus:z-2 focus-visible:z-2\",\n);\n\nexport type ToolbarProps = Omit<React.HTMLAttributes<HTMLDivElement>, \"aria-label\"> & {\n\t/**\n\t * Accessible name for the toolbar.\n\t */\n\t\"aria-label\"?: string;\n};\n\nfunction toolbarItems(root: HTMLElement) {\n\treturn [\n\t\t...root.querySelectorAll<HTMLElement>(\"button:not([disabled]), input:not([disabled])\"),\n\t].filter((node) => node.closest('[role=\"toolbar\"]') === root);\n}\n\nfunction setRovingTab(items: HTMLElement[], active: HTMLElement) {\n\tfor (const item of items) {\n\t\titem.tabIndex = item === active ? 0 : -1;\n\t}\n}\n\nconst ToolbarRoot = React.forwardRef<HTMLDivElement, ToolbarProps>(\n\t({ className, onKeyDown, onFocus, ...props }, ref) => {\n\t\tconst innerRef = React.useRef<HTMLDivElement | null>(null);\n\t\tReact.useLayoutEffect(() => {\n\t\t\tconst root = innerRef.current;\n\t\t\tif (!root) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst items = toolbarItems(root);\n\t\t\tconst active =\n\t\t\t\titems.find((item) => item.tabIndex === 0 && !(item as HTMLButtonElement).disabled) ??\n\t\t\t\titems[0];\n\t\t\tif (active) {\n\t\t\t\tsetRovingTab(items, active);\n\t\t\t}\n\t\t});\n\t\treturn (\n\t\t\t<div\n\t\t\t\tref={(node) => {\n\t\t\t\t\tinnerRef.current = node;\n\t\t\t\t\tif (typeof ref === \"function\") {\n\t\t\t\t\t\tref(node);\n\t\t\t\t\t} else if (ref) {\n\t\t\t\t\t\tref.current = node;\n\t\t\t\t\t}\n\t\t\t\t}}\n\t\t\t\t{...props}\n\t\t\t\trole=\"toolbar\"\n\t\t\t\tonFocus={(event) => {\n\t\t\t\t\tonFocus?.(event);\n\t\t\t\t\tconst items = toolbarItems(event.currentTarget);\n\t\t\t\t\tconst target = event.target as HTMLElement;\n\t\t\t\t\tif (items.includes(target)) {\n\t\t\t\t\t\tsetRovingTab(items, target);\n\t\t\t\t\t}\n\t\t\t\t}}\n\t\t\t\tonKeyDown={(event) => {\n\t\t\t\t\tonKeyDown?.(event);\n\t\t\t\t\tif (event.defaultPrevented || (event.key !== \"ArrowRight\" && event.key !== \"ArrowLeft\")) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tif (\n\t\t\t\t\t\tevent.target instanceof HTMLInputElement ||\n\t\t\t\t\t\tevent.target instanceof HTMLTextAreaElement\n\t\t\t\t\t) {\n\t\t\t\t\t\tconst start = event.target.selectionStart ?? 0;\n\t\t\t\t\t\tconst end = event.target.selectionEnd ?? start;\n\t\t\t\t\t\tif (start !== end) {\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (event.key === \"ArrowLeft\" && start > 0) {\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (event.key === \"ArrowRight\" && start < event.target.value.length) {\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tconst items = toolbarItems(event.currentTarget);\n\t\t\t\t\tconst index = items.indexOf(event.target as HTMLElement);\n\t\t\t\t\tif (index < 0 || items.length === 0) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\tconst next =\n\t\t\t\t\t\tevent.key === \"ArrowRight\"\n\t\t\t\t\t\t\t? (index + 1) % items.length\n\t\t\t\t\t\t\t: (index - 1 + items.length) % items.length;\n\t\t\t\t\tconst node = items[next];\n\t\t\t\t\tif (node) {\n\t\t\t\t\t\tsetRovingTab(items, node);\n\t\t\t\t\t\tnode.focus();\n\t\t\t\t\t}\n\t\t\t\t}}\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"inline-flex w-fit items-stretch rounded-basalt-md bg-basalt-control shadow-xs ring-1 ring-basalt-border\",\n\t\t\t\t\t\"[&>*:not(:first-child)]:border-l [&>*:not(:first-child)]:border-basalt-border\",\n\t\t\t\t\tclassName,\n\t\t\t\t)}\n\t\t\t/>\n\t\t);\n\t},\n);\nToolbarRoot.displayName = \"Toolbar\";\n\nexport type ToolbarButtonProps = Omit<ButtonProps, \"variant\" | \"disabled\" | \"asChild\"> & {\n\t/**\n\t * Disable the toolbar button.\n\t * @default false\n\t */\n\tdisabled?: boolean;\n};\n\nexport const ToolbarButton = React.forwardRef<HTMLButtonElement, ToolbarButtonProps>(\n\t({ className, size, icon, children, ...props }, ref) => {\n\t\tconst resolvedSize = size ?? (icon && children == null ? \"icon\" : \"default\");\n\t\treturn (\n\t\t\t<Button\n\t\t\t\tref={ref}\n\t\t\t\ticon={icon}\n\t\t\t\tclassName={cn(\n\t\t\t\t\ttoolbarControlClass,\n\t\t\t\t\tFOCUS_INSET,\n\t\t\t\t\t\"h-auto min-h-basalt-control shrink-0\",\n\t\t\t\t\tresolvedSize === \"icon\" && \"w-basalt-control\",\n\t\t\t\t\tclassName,\n\t\t\t\t)}\n\t\t\t\t{...props}\n\t\t\t\tvariant=\"ghost\"\n\t\t\t\tsize={resolvedSize}\n\t\t\t>\n\t\t\t\t{children}\n\t\t\t</Button>\n\t\t);\n\t},\n);\nToolbarButton.displayName = \"Toolbar.Button\";\n\nexport type ToolbarInputProps = Omit<React.ComponentPropsWithoutRef<typeof Input>, \"disabled\"> & {\n\t/**\n\t * Disable the toolbar input.\n\t * @default false\n\t */\n\tdisabled?: boolean;\n};\n\nexport const ToolbarInput = React.forwardRef<HTMLInputElement, ToolbarInputProps>(\n\t({ className, ...props }, ref) => (\n\t\t<Input\n\t\t\tref={ref}\n\t\t\tclassName={cn(toolbarControlClass, FOCUS_INSET, \"h-auto min-h-basalt-control\", className)}\n\t\t\t{...props}\n\t\t/>\n\t),\n);\nToolbarInput.displayName = \"Toolbar.Input\";\n\nexport const Toolbar = Object.assign(ToolbarRoot, {\n\tButton: ToolbarButton,\n\tInput: ToolbarInput,\n});\n"],"mappings":"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"}
|
package/dist/styles/base.css
CHANGED
|
@@ -202,6 +202,63 @@
|
|
|
202
202
|
}
|
|
203
203
|
|
|
204
204
|
@layer components {
|
|
205
|
+
:is(.basalt-focus, .basalt-action) {
|
|
206
|
+
scroll-margin: var(--basalt-focus-clearance);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
:is(.basalt-focus, .basalt-action):focus:not(:focus-visible) {
|
|
210
|
+
outline: none;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
:is(.basalt-focus, .basalt-action):focus-visible,
|
|
214
|
+
.basalt-nav-actions :focus-visible,
|
|
215
|
+
.basalt-focus-frame:has(> .basalt-focus:focus-visible)::after,
|
|
216
|
+
.basalt-focus-group:has(:is(input, textarea):focus-visible):not(
|
|
217
|
+
:has(.basalt-focus-group :focus-visible)
|
|
218
|
+
) {
|
|
219
|
+
outline: var(--basalt-focus-width) solid hsl(var(--basalt-ring));
|
|
220
|
+
outline-offset: var(--basalt-focus-offset);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
.basalt-focus-inset:focus-visible,
|
|
224
|
+
.basalt-focus-frame:has(> .basalt-focus:focus-visible)::after,
|
|
225
|
+
.basalt-focus-group.basalt-focus-inset:has(:is(input, textarea):focus-visible):not(
|
|
226
|
+
:has(.basalt-focus-group :focus-visible)
|
|
227
|
+
),
|
|
228
|
+
.basalt-focus-group .basalt-choice:focus-visible,
|
|
229
|
+
.basalt-nav-actions .basalt-choice:focus-visible {
|
|
230
|
+
outline-offset: calc(-1 * var(--basalt-focus-offset));
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
.basalt-focus-group :is(input, textarea):focus-visible,
|
|
234
|
+
.basalt-focus-frame > .basalt-focus:focus-visible {
|
|
235
|
+
outline: none;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
.basalt-focus-frame:has(> .basalt-focus:focus-visible)::after {
|
|
239
|
+
content: "";
|
|
240
|
+
position: absolute;
|
|
241
|
+
inset: 0;
|
|
242
|
+
z-index: 1;
|
|
243
|
+
border-radius: inherit;
|
|
244
|
+
pointer-events: none;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
@media (forced-colors: active) {
|
|
248
|
+
:is(.basalt-focus, .basalt-action):focus-visible,
|
|
249
|
+
.basalt-nav-actions :focus-visible,
|
|
250
|
+
.basalt-focus-frame:has(> .basalt-focus:focus-visible)::after,
|
|
251
|
+
.basalt-focus-group:has(:is(input, textarea):focus-visible):not(
|
|
252
|
+
:has(.basalt-focus-group :focus-visible)
|
|
253
|
+
) {
|
|
254
|
+
outline: 2px solid Highlight;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
.basalt-focus-group :is(input, textarea):focus-visible {
|
|
258
|
+
outline: none;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
205
262
|
[data-basalt-header][data-density="compact"]
|
|
206
263
|
:where([data-basalt-header-leading], [data-basalt-header-actions])
|
|
207
264
|
:where(button, a, [role="button"]) {
|
|
@@ -209,3 +266,17 @@
|
|
|
209
266
|
min-width: var(--basalt-size-touch);
|
|
210
267
|
}
|
|
211
268
|
}
|
|
269
|
+
|
|
270
|
+
:is(.basalt-focus, .basalt-action):focus-visible,
|
|
271
|
+
.basalt-nav-actions :focus-visible,
|
|
272
|
+
.basalt-focus-group:has(:is(input, textarea):focus-visible):not(
|
|
273
|
+
:has(.basalt-focus-group :focus-visible)
|
|
274
|
+
),
|
|
275
|
+
.basalt-chart :focus-visible {
|
|
276
|
+
transition: none;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
.basalt-focus-swatch:focus-visible {
|
|
280
|
+
box-shadow: inset 0 0 0 calc(var(--basalt-focus-offset) + var(--basalt-focus-width))
|
|
281
|
+
hsl(var(--basalt-background));
|
|
282
|
+
}
|