@devalok/shilp-sutra 0.42.0 → 0.43.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +10 -0
- package/MIGRATION.md +32 -0
- package/dist/_chunks/chat.js +1 -1
- package/dist/_chunks/chat.js.map +1 -1
- package/dist/_chunks/mention-suggestion.js +1 -1
- package/dist/_chunks/mention-suggestion.js.map +1 -1
- package/dist/_chunks/popover.js +1 -1
- package/dist/_chunks/popover.js.map +1 -1
- package/dist/_chunks/shared.js +1 -1
- package/dist/_chunks/shared.js.map +1 -1
- package/dist/ai/command-bar.js +1 -1
- package/dist/ai/command-bar.js.map +1 -1
- package/dist/composed/bulk-action-bar.js +1 -1
- package/dist/composed/bulk-action-bar.js.map +1 -1
- package/dist/composed/command-palette.js +1 -1
- package/dist/composed/command-palette.js.map +1 -1
- package/dist/composed/content-card.js +1 -1
- package/dist/composed/content-card.js.map +1 -1
- package/dist/composed/error-boundary.js +1 -1
- package/dist/composed/error-boundary.js.map +1 -1
- package/dist/composed/extensions/emoji-suggestion.js +1 -1
- package/dist/composed/extensions/emoji-suggestion.js.map +1 -1
- package/dist/composed/file-preview.js +1 -1
- package/dist/composed/file-preview.js.map +1 -1
- package/dist/composed/rich-chat-input.js +5 -5
- package/dist/composed/rich-chat-input.js.map +1 -1
- package/dist/composed/rich-text-editor.js +2 -2
- package/dist/composed/rich-text-editor.js.map +1 -1
- package/dist/shell/notification-center.js +1 -1
- package/dist/shell/notification-center.js.map +1 -1
- package/dist/shell/sidebar.d.ts +6 -0
- package/dist/shell/sidebar.d.ts.map +1 -1
- package/dist/shell/sidebar.js +27 -18
- package/dist/shell/sidebar.js.map +1 -1
- package/dist/shell/top-bar.js +1 -1
- package/dist/shell/top-bar.js.map +1 -1
- package/dist/tokens/semantic.css +8 -2
- package/dist/ui/alert-dialog.js +1 -1
- package/dist/ui/alert-dialog.js.map +1 -1
- package/dist/ui/autocomplete.js +1 -1
- package/dist/ui/autocomplete.js.map +1 -1
- package/dist/ui/card.d.ts.map +1 -1
- package/dist/ui/card.js +3 -3
- package/dist/ui/card.js.map +1 -1
- package/dist/ui/color-input.js +1 -1
- package/dist/ui/color-input.js.map +1 -1
- package/dist/ui/combobox.js +1 -1
- package/dist/ui/combobox.js.map +1 -1
- package/dist/ui/context-menu.js +2 -2
- package/dist/ui/context-menu.js.map +1 -1
- package/dist/ui/data-table-bulk-actions.js +1 -1
- package/dist/ui/data-table-bulk-actions.js.map +1 -1
- package/dist/ui/dialog.js +1 -1
- package/dist/ui/dialog.js.map +1 -1
- package/dist/ui/dropdown-menu.js +2 -2
- package/dist/ui/dropdown-menu.js.map +1 -1
- package/dist/ui/hover-card.js +1 -1
- package/dist/ui/hover-card.js.map +1 -1
- package/dist/ui/index.d.ts +1 -0
- package/dist/ui/index.d.ts.map +1 -1
- package/dist/ui/index.js +20 -19
- package/dist/ui/index.js.map +1 -1
- package/dist/ui/input-otp.js +1 -1
- package/dist/ui/input-otp.js.map +1 -1
- package/dist/ui/menubar.js +3 -3
- package/dist/ui/menubar.js.map +1 -1
- package/dist/ui/navigation-menu.js +1 -1
- package/dist/ui/navigation-menu.js.map +1 -1
- package/dist/ui/select.js +1 -1
- package/dist/ui/select.js.map +1 -1
- package/dist/ui/sidebar.js +1 -1
- package/dist/ui/sidebar.js.map +1 -1
- package/dist/ui/split-button.js +1 -1
- package/dist/ui/split-button.js.map +1 -1
- package/dist/ui/stat-card.d.ts +22 -2
- package/dist/ui/stat-card.d.ts.map +1 -1
- package/dist/ui/stat-card.js +101 -86
- package/dist/ui/stat-card.js.map +1 -1
- package/dist/ui/stat-flash.d.ts +46 -0
- package/dist/ui/stat-flash.d.ts.map +1 -0
- package/dist/ui/stat-flash.js +114 -0
- package/dist/ui/stat-flash.js.map +1 -0
- package/dist/ui/toast.js +2 -2
- package/dist/ui/toast.js.map +1 -1
- package/docs/components/ui/stat-card.md +13 -3
- package/docs/components/ui/stat-flash.md +44 -0
- package/llms-full.txt +58 -4
- package/llms.txt +4 -0
- package/package.json +1 -1
- package/skill/SKILL.md +1 -1
- package/skill/references/components-full.md +58 -4
- package/skill/references/components.md +4 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sidebar.js","names":[],"sources":["../../src/shell/sidebar.tsx"],"sourcesContent":["'use client'\n\n/**\n * AppSidebar -- Application-layer sidebar built on the Sidebar primitive.\n *\n * Design-system token migration (2026-02-28):\n * All V1 colour tokens have been replaced with semantic design-system tokens.\n * Typography classes replaced with Tailwind equivalents.\n *\n * Props-driven: accepts user info, currentPath, and navItems instead of\n * reading from Remix hooks or Zustand stores.\n */\nimport * as React from 'react'\n\nimport { Avatar, AvatarFallback, AvatarImage } from '../ui/avatar'\nimport { IconProvider } from '../ui/icon-context'\nimport type { IconInput } from '../ui/lib/icon-input'\nimport { normalizeIcon } from '../ui/lib/normalize-icon'\nimport {\n Collapsible,\n CollapsibleContent,\n CollapsibleTrigger,\n} from '../ui/collapsible'\nimport { cn } from '../ui/lib/utils'\nimport {\n Sidebar as ShadcnSidebar,\n SidebarContent,\n SidebarFooter,\n SidebarGroup,\n SidebarGroupAction,\n SidebarGroupContent,\n SidebarGroupLabel,\n SidebarHeader,\n SidebarMenu,\n SidebarMenuBadge,\n SidebarMenuButton,\n SidebarMenuItem,\n SidebarMenuSub,\n SidebarMenuSubButton,\n SidebarMenuSubItem,\n SidebarSeparator,\n} from '../ui/sidebar'\nimport { useLink } from './link-context'\n\n// -----------------------------------------------------------------------\n// Types\n// -----------------------------------------------------------------------\n\nexport interface NavSubItem {\n title: string\n href: string\n /** Optional icon. Accepts any `IconInput`. */\n icon?: IconInput\n exact?: boolean\n}\n\nexport interface NavItem {\n title: string\n href: string\n /** Icon for this nav item. Accepts any `IconInput`. */\n icon: IconInput\n /** When true, the route matches only when the path is exactly equal */\n exact?: boolean\n /** Badge rendered on the right side of the nav item */\n badge?: string | number\n /** Optional child items — renders as collapsible sub-list with chevron */\n children?: NavSubItem[]\n /** Whether the collapsible is open by default. Auto-opens when a child is active. */\n defaultOpen?: boolean\n}\n\nexport interface NavGroup {\n label: string\n items: NavItem[]\n /** Action rendered next to the group label (e.g., a \"+\" button) */\n action?: React.ReactNode\n}\n\nexport interface SidebarUser {\n name: string\n email?: string\n image?: string | null\n designation?: string\n role?: string\n}\n\nexport interface SidebarPromo {\n /** Promo message text */\n text: string\n /** Optional icon rendered before the text. Accepts any `IconInput`. */\n icon?: IconInput\n /** Action button rendered in the promo banner */\n action?: { label: string; href?: string; onClick?: () => void }\n /** When provided, renders a dismiss (X) button that calls this handler */\n onDismiss?: () => void\n}\n\nexport interface SidebarFooterConfig {\n /** Legal/utility links rendered as a row separated by dividers */\n links?: Array<{ label: string; href: string }>\n /** Version or build info text (or link) rendered inline after links */\n version?: string | { label: string; href: string }\n /** Custom content rendered above the links row */\n slot?: React.ReactNode\n /** Promo/upsell banner rendered above the links row */\n promo?: SidebarPromo\n}\n\nexport interface AppSidebarProps\n extends React.HTMLAttributes<HTMLDivElement> {\n /** Currently active pathname -- used to highlight the active nav item */\n currentPath?: string\n /** User information displayed in the sidebar header */\n user?: SidebarUser | null\n /** Primary navigation groups rendered in the main content area */\n navGroups?: NavGroup[]\n /** Optional logo element. Falls back to a text placeholder. */\n logo?: React.ReactNode\n /** Footer links rendered at the bottom of the sidebar */\n footerLinks?: Array<{ label: string; href: string }>\n /** Structured footer config (takes precedence over footerLinks) */\n footer?: SidebarFooterConfig\n /** Content rendered between user header and navigation */\n headerSlot?: React.ReactNode\n /** Content rendered between navigation and footer */\n preFooterSlot?: React.ReactNode\n /** className applied to the wrapper div around preFooterSlot */\n preFooterClassName?: string\n /** Override rendering for specific nav items. Return null to use default rendering. */\n renderItem?: (item: NavItem, defaultRender: () => React.ReactNode) => React.ReactNode | null\n /** Additional className for the root sidebar element */\n className?: string\n}\n\n// -----------------------------------------------------------------------\n// ChevronRight (inline SVG icon for collapsible toggle)\n// -----------------------------------------------------------------------\n\nfunction ChevronRight({ className }: { className?: string }) {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className={className}\n >\n <path d=\"m9 18 6-6-6-6\" />\n </svg>\n )\n}\n\nfunction CloseIcon({ className }: { className?: string }) {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className={className}\n >\n <path d=\"M18 6 6 18\" />\n <path d=\"m6 6 12 12\" />\n </svg>\n )\n}\n\n// -----------------------------------------------------------------------\n// Shared styles\n// -----------------------------------------------------------------------\n\nconst navItemBase = 'relative gap-ds-04 rounded-surface px-ds-04 py-ds-03 transition-colors duration-fast-02'\nconst navItemActive =\n \"bg-accent-2 text-accent-11 after:absolute after:right-0 after:top-0 after:h-full after:w-ds-01 after:rounded-l-pill after:bg-accent-9 after:content-['']\"\nconst navItemInactive = 'text-surface-fg-subtle hover:bg-surface-raised-hover hover:text-surface-fg'\n\n// -----------------------------------------------------------------------\n// NavLink (internal)\n// -----------------------------------------------------------------------\n\nfunction NavLink({\n item,\n isActive,\n isPathActive,\n}: {\n item: NavItem\n isActive: boolean\n isPathActive: (path: string, exact?: boolean) => boolean\n}) {\n const Link = useLink()\n const badgeContent =\n item.badge != null\n ? typeof item.badge === 'number' && item.badge > 99\n ? '99+'\n : String(item.badge)\n : null\n\n // S9: Collapsible children\n if (item.children && item.children.length > 0) {\n const hasActiveChild = item.children.some((child) =>\n isPathActive(child.href, child.exact),\n )\n const shouldOpen = hasActiveChild || isActive || (item.defaultOpen ?? false)\n\n return (\n <Collapsible defaultOpen={shouldOpen} className=\"group/collapsible\">\n <SidebarMenuItem>\n {/* Button row — chevron is anchored here, not on the full <li> */}\n <div className=\"relative\">\n <SidebarMenuButton\n asChild\n isActive={isActive || hasActiveChild}\n tooltip={item.title}\n className={cn(\n navItemBase,\n isActive || hasActiveChild ? navItemActive : navItemInactive,\n )}\n >\n <Link\n href={item.href}\n aria-label={item.title}\n aria-current={isActive ? 'page' : undefined}\n >\n <span className=\"[&>svg]:h-ico-md [&>svg]:w-ico-md shrink-0\" aria-hidden=\"true\">\n <IconProvider size=\"md\">{normalizeIcon(item.icon)}</IconProvider>\n </span>\n <span className=\"text-ds-base\">{item.title}</span>\n </Link>\n </SidebarMenuButton>\n {badgeContent && <SidebarMenuBadge>{badgeContent}</SidebarMenuBadge>}\n <CollapsibleTrigger asChild>\n <button\n className=\"absolute right-ds-02 top-1/2 flex h-5 w-5 -translate-y-1/2 items-center justify-center rounded-control text-surface-fg-subtle transition-colors hover:bg-surface-raised-hover hover:text-surface-fg group-data-[collapsible=icon]:hidden\"\n aria-label={`Toggle ${item.title}`}\n >\n <ChevronRight className=\"h-4 w-4 transition-transform duration-fast-02 ease-productive-standard group-data-[state=open]/collapsible:rotate-90\" />\n </button>\n </CollapsibleTrigger>\n </div>\n <CollapsibleContent>\n <SidebarMenuSub>\n {item.children.map((child) => {\n const childActive = isPathActive(child.href, child.exact)\n return (\n <SidebarMenuSubItem key={child.href}>\n <SidebarMenuSubButton\n asChild\n isActive={childActive}\n >\n <Link\n href={child.href}\n aria-current={childActive ? 'page' : undefined}\n >\n {child.icon && (\n <span className=\"[&>svg]:h-ico-sm [&>svg]:w-ico-sm shrink-0\" aria-hidden=\"true\">\n <IconProvider size=\"sm\">{normalizeIcon(child.icon)}</IconProvider>\n </span>\n )}\n <span>{child.title}</span>\n </Link>\n </SidebarMenuSubButton>\n </SidebarMenuSubItem>\n )\n })}\n </SidebarMenuSub>\n </CollapsibleContent>\n </SidebarMenuItem>\n </Collapsible>\n )\n }\n\n // Default: flat nav item\n return (\n <SidebarMenuItem>\n <SidebarMenuButton\n asChild\n isActive={isActive}\n tooltip={item.title}\n className={cn(\n navItemBase,\n isActive ? navItemActive : navItemInactive,\n )}\n >\n <Link\n href={item.href}\n aria-label={item.title}\n aria-current={isActive ? 'page' : undefined}\n >\n <span className=\"[&>svg]:h-ico-md [&>svg]:w-ico-md shrink-0\" aria-hidden=\"true\"><IconProvider size=\"md\">{normalizeIcon(item.icon)}</IconProvider></span>\n <span className=\"text-ds-base\">{item.title}</span>\n </Link>\n </SidebarMenuButton>\n {badgeContent && <SidebarMenuBadge>{badgeContent}</SidebarMenuBadge>}\n </SidebarMenuItem>\n )\n}\n\n// -----------------------------------------------------------------------\n// AppSidebar\n// -----------------------------------------------------------------------\n\nconst AppSidebar = React.forwardRef<HTMLDivElement, AppSidebarProps>(\n (\n {\n currentPath = '/',\n user,\n navGroups = [],\n logo,\n headerSlot,\n preFooterSlot,\n preFooterClassName,\n footerLinks = [],\n footer,\n renderItem,\n className,\n ...props\n },\n ref,\n ) => {\n const Link = useLink()\n const isActive = (path: string, exact = false) => {\n if (exact || path === '/') {\n return currentPath === path\n }\n return currentPath.startsWith(path)\n }\n\n return (\n <ShadcnSidebar\n {...props}\n ref={ref}\n aria-label=\"Main navigation\"\n className={cn(\n 'z-raised hidden h-full flex-col border-r border-surface-border-strong bg-surface-raised md:flex',\n className,\n )}\n >\n {/* Logo Header */}\n <SidebarHeader className=\"px-ds-06 py-ds-06\">\n {logo ?? (\n <span className=\"text-ds-lg font-semibold text-surface-fg\">\n Logo\n </span>\n )}\n </SidebarHeader>\n\n {/* User Info */}\n {user && (\n <div className=\"flex items-center gap-ds-04 px-ds-06 pb-ds-05\">\n <Avatar className=\"h-ds-sm-plus w-ds-sm-plus\">\n {user.image ? (\n <AvatarImage src={user.image} alt={user.name} />\n ) : null}\n <AvatarFallback className=\"bg-surface-raised-hover text-surface-fg\">\n {user.name?.charAt(0).toUpperCase()}\n </AvatarFallback>\n </Avatar>\n <div className=\"flex min-w-0 flex-col\">\n <span className=\"truncate text-ds-md text-surface-fg\">\n {user.name}\n </span>\n <span className=\"truncate text-ds-sm text-surface-fg-subtle\">\n {user.designation || user.role}\n </span>\n </div>\n </div>\n )}\n\n <SidebarSeparator />\n\n {/* Header Slot (S13) */}\n {headerSlot && (\n <>\n {headerSlot}\n <SidebarSeparator />\n </>\n )}\n\n {/* Navigation Groups */}\n <SidebarContent className=\"no-scrollbar px-ds-04\">\n {navGroups.map((group, idx) => (\n <div key={group.label}>\n {idx > 0 && <SidebarSeparator />}\n <SidebarGroup>\n <SidebarGroupLabel className=\"px-ds-04 text-ds-sm text-surface-fg-subtle\">\n {group.label}\n </SidebarGroupLabel>\n {group.action && (\n <SidebarGroupAction asChild>{group.action}</SidebarGroupAction>\n )}\n <SidebarGroupContent>\n <SidebarMenu>\n {group.items.map((item) => {\n const defaultRender = () => (\n <NavLink\n item={item}\n isActive={isActive(item.href, item.exact)}\n isPathActive={isActive}\n />\n )\n\n if (renderItem) {\n const custom = renderItem(item, defaultRender)\n if (custom !== null) {\n return <React.Fragment key={item.href}>{custom}</React.Fragment>\n }\n }\n\n return <React.Fragment key={item.href}>{defaultRender()}</React.Fragment>\n })}\n </SidebarMenu>\n </SidebarGroupContent>\n </SidebarGroup>\n </div>\n ))}\n </SidebarContent>\n\n {/* Pre-Footer Slot (S13) */}\n {preFooterSlot && (\n <>\n <SidebarSeparator />\n <div className={preFooterClassName}>\n {preFooterSlot}\n </div>\n </>\n )}\n\n {/* Footer */}\n {footer ? (\n <SidebarFooter className=\"gap-ds-03 px-ds-06 py-ds-05\">\n {footer.slot && <div>{footer.slot}</div>}\n\n {/* Promo banner */}\n {footer.promo && (\n <div className=\"relative rounded-surface border border-surface-border bg-surface-raised p-ds-04 shadow-raised\">\n {footer.promo.onDismiss && (\n <button\n onClick={footer.promo.onDismiss}\n aria-label=\"Dismiss\"\n className=\"absolute right-ds-02 top-ds-02 flex h-5 w-5 items-center justify-center rounded-control text-surface-fg-subtle transition-colors hover:bg-surface-raised-hover hover:text-surface-fg\"\n >\n <CloseIcon className=\"h-3.5 w-3.5\" />\n </button>\n )}\n <div className=\"flex flex-col gap-ds-03\">\n {footer.promo.icon && (\n <span className=\"text-accent-11 [&>svg]:h-ico-md [&>svg]:w-ico-md\" aria-hidden=\"true\">\n <IconProvider size=\"md\">{normalizeIcon(footer.promo.icon)}</IconProvider>\n </span>\n )}\n <div className=\"flex min-w-0 flex-col gap-ds-03\">\n <p className=\"text-ds-sm text-surface-fg\">{footer.promo.text}</p>\n {footer.promo.action && (\n footer.promo.action.href ? (\n <Link\n href={footer.promo.action.href}\n onClick={footer.promo.action.onClick}\n className=\"inline-flex self-start rounded-control bg-accent-9 px-ds-04 py-ds-02 text-ds-sm font-medium text-accent-fg transition-colors hover:bg-accent-10\"\n >\n {footer.promo.action.label}\n </Link>\n ) : (\n <button\n onClick={footer.promo.action.onClick}\n className=\"inline-flex self-start rounded-control bg-accent-9 px-ds-04 py-ds-02 text-ds-sm font-medium text-accent-fg transition-colors hover:bg-accent-10\"\n >\n {footer.promo.action.label}\n </button>\n )\n )}\n </div>\n </div>\n </div>\n )}\n\n {/* Links + version on same line */}\n {(footer.links?.length || footer.version) && (\n <div className=\"flex items-center gap-ds-03 text-ds-sm text-surface-fg-subtle\">\n {footer.links?.map((link, i) => (\n <React.Fragment key={link.href}>\n {i > 0 && <span>·</span>}\n <Link\n className=\"transition-colors hover:text-accent-11\"\n href={link.href}\n >\n {link.label}\n </Link>\n </React.Fragment>\n ))}\n {footer.links?.length && footer.version && <span>·</span>}\n {footer.version && (\n typeof footer.version === 'string'\n ? <span>{footer.version}</span>\n : <Link className=\"transition-colors hover:text-accent-11\" href={footer.version.href}>{footer.version.label}</Link>\n )}\n </div>\n )}\n </SidebarFooter>\n ) : footerLinks.length > 0 ? (\n <SidebarFooter className=\"px-ds-06 py-ds-05\">\n <div className=\"flex items-center gap-ds-03 text-ds-sm text-surface-fg-subtle\">\n {footerLinks.map((link, i) => (\n <React.Fragment key={link.href}>\n {i > 0 && <span>·</span>}\n <Link\n className=\"transition-colors hover:text-accent-11\"\n href={link.href}\n >\n {link.label}\n </Link>\n </React.Fragment>\n ))}\n </div>\n </SidebarFooter>\n ) : null}\n </ShadcnSidebar>\n )\n },\n)\nAppSidebar.displayName = 'AppSidebar'\n\nexport { AppSidebar }\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"sidebar.js","names":[],"sources":["../../src/shell/sidebar.tsx"],"sourcesContent":["'use client'\n\n/**\n * AppSidebar -- Application-layer sidebar built on the Sidebar primitive.\n *\n * Design-system token migration (2026-02-28):\n * All V1 colour tokens have been replaced with semantic design-system tokens.\n * Typography classes replaced with Tailwind equivalents.\n *\n * Props-driven: accepts user info, currentPath, and navItems instead of\n * reading from Remix hooks or Zustand stores.\n */\nimport * as React from 'react'\n\nimport { Avatar, AvatarFallback, AvatarImage } from '../ui/avatar'\nimport { IconProvider } from '../ui/icon-context'\nimport type { IconInput } from '../ui/lib/icon-input'\nimport { normalizeIcon } from '../ui/lib/normalize-icon'\nimport {\n Collapsible,\n CollapsibleContent,\n CollapsibleTrigger,\n} from '../ui/collapsible'\nimport { cn } from '../ui/lib/utils'\nimport {\n Sidebar as ShadcnSidebar,\n SidebarContent,\n SidebarFooter,\n SidebarGroup,\n SidebarGroupAction,\n SidebarGroupContent,\n SidebarGroupLabel,\n SidebarHeader,\n SidebarMenu,\n SidebarMenuBadge,\n SidebarMenuButton,\n SidebarMenuItem,\n SidebarMenuSub,\n SidebarMenuSubButton,\n SidebarMenuSubItem,\n SidebarSeparator,\n} from '../ui/sidebar'\nimport { useLink } from './link-context'\n\n// -----------------------------------------------------------------------\n// Types\n// -----------------------------------------------------------------------\n\nexport interface NavSubItem {\n title: string\n href: string\n /** Optional icon. Accepts any `IconInput`. */\n icon?: IconInput\n exact?: boolean\n}\n\nexport interface NavItem {\n title: string\n href: string\n /** Icon for this nav item. Accepts any `IconInput`. */\n icon: IconInput\n /** When true, the route matches only when the path is exactly equal */\n exact?: boolean\n /** Badge rendered on the right side of the nav item */\n badge?: string | number\n /** Optional child items — renders as collapsible sub-list with chevron */\n children?: NavSubItem[]\n /** Whether the collapsible is open by default. Auto-opens when a child is active. */\n defaultOpen?: boolean\n}\n\nexport interface NavGroup {\n label: string\n items: NavItem[]\n /** Action rendered next to the group label (e.g., a \"+\" button) */\n action?: React.ReactNode\n}\n\nexport interface SidebarUser {\n name: string\n email?: string\n image?: string | null\n designation?: string\n role?: string\n}\n\nexport interface SidebarPromo {\n /** Promo message text */\n text: string\n /** Optional icon rendered before the text. Accepts any `IconInput`. */\n icon?: IconInput\n /** Action button rendered in the promo banner */\n action?: { label: string; href?: string; onClick?: () => void }\n /** When provided, renders a dismiss (X) button that calls this handler */\n onDismiss?: () => void\n}\n\nexport interface SidebarFooterConfig {\n /** Legal/utility links rendered as a row separated by dividers */\n links?: Array<{ label: string; href: string }>\n /** Version or build info text (or link) rendered inline after links */\n version?: string | { label: string; href: string }\n /** Custom content rendered above the links row */\n slot?: React.ReactNode\n /** Promo/upsell banner rendered above the links row */\n promo?: SidebarPromo\n}\n\nexport interface AppSidebarProps\n extends React.HTMLAttributes<HTMLDivElement> {\n /** Currently active pathname -- used to highlight the active nav item */\n currentPath?: string\n /** User information displayed in the sidebar header */\n user?: SidebarUser | null\n /** Primary navigation groups rendered in the main content area */\n navGroups?: NavGroup[]\n /** Optional logo element. Falls back to a text placeholder. */\n logo?: React.ReactNode\n /** Footer links rendered at the bottom of the sidebar */\n footerLinks?: Array<{ label: string; href: string }>\n /** Structured footer config (takes precedence over footerLinks) */\n footer?: SidebarFooterConfig\n /** Content rendered between user header and navigation */\n headerSlot?: React.ReactNode\n /** Content rendered between navigation and footer */\n preFooterSlot?: React.ReactNode\n /** className applied to the wrapper div around preFooterSlot */\n preFooterClassName?: string\n /** Override rendering for specific nav items. Return null to use default rendering. */\n renderItem?: (item: NavItem, defaultRender: () => React.ReactNode) => React.ReactNode | null\n /** Additional className for the root sidebar element */\n className?: string\n /**\n * Corner radius of nav items (composable). @default 'md' (control radius, ~6px).\n * `'lg'` restores the previous rounder look; `'sm'` is tighter; `'pill'` is fully rounded.\n * Sets the `--ds-sidebar-item-radius` CSS var, so you can also override it via `className`/`style`.\n */\n navItemRadius?: 'sm' | 'md' | 'lg' | 'pill'\n}\n\n// -----------------------------------------------------------------------\n// ChevronRight (inline SVG icon for collapsible toggle)\n// -----------------------------------------------------------------------\n\nfunction ChevronRight({ className }: { className?: string }) {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className={className}\n >\n <path d=\"m9 18 6-6-6-6\" />\n </svg>\n )\n}\n\nfunction CloseIcon({ className }: { className?: string }) {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className={className}\n >\n <path d=\"M18 6 6 18\" />\n <path d=\"m6 6 12 12\" />\n </svg>\n )\n}\n\n// -----------------------------------------------------------------------\n// Shared styles\n// -----------------------------------------------------------------------\n\n// Radius is composable via the `navItemRadius` prop (sets --ds-sidebar-item-radius).\n// Default is the control radius (~6px) — surface (10px) read as over-rounded blobs.\nconst navItemBase =\n 'relative gap-ds-04 rounded-[var(--ds-sidebar-item-radius,var(--radius-control))] px-ds-04 py-ds-03 transition-colors duration-fast-02'\nconst NAV_ITEM_RADIUS = {\n sm: 'var(--radius-control-inner)',\n md: 'var(--radius-control)',\n lg: 'var(--radius-surface)',\n pill: 'var(--radius-pill)',\n} as const\n// Active = tinted surface + accent text + weight. No accent rail — the tint and\n// colour already signal \"you are here\"; a stripe on top is doubled accent (AI tell).\nconst navItemActive = 'bg-accent-2 text-accent-11 font-medium'\nconst navItemInactive = 'text-surface-fg-subtle hover:bg-surface-raised-hover hover:text-surface-fg'\n\n// -----------------------------------------------------------------------\n// NavLink (internal)\n// -----------------------------------------------------------------------\n\nfunction NavLink({\n item,\n isActive,\n isPathActive,\n}: {\n item: NavItem\n isActive: boolean\n isPathActive: (path: string, exact?: boolean) => boolean\n}) {\n const Link = useLink()\n const badgeContent =\n item.badge != null\n ? typeof item.badge === 'number' && item.badge > 99\n ? '99+'\n : String(item.badge)\n : null\n\n // S9: Collapsible children\n if (item.children && item.children.length > 0) {\n const hasActiveChild = item.children.some((child) =>\n isPathActive(child.href, child.exact),\n )\n const shouldOpen = hasActiveChild || isActive || (item.defaultOpen ?? false)\n\n return (\n <Collapsible defaultOpen={shouldOpen} className=\"group/collapsible\">\n <SidebarMenuItem>\n {/* Button row — chevron is anchored here, not on the full <li> */}\n <div className=\"relative\">\n <SidebarMenuButton\n asChild\n isActive={isActive || hasActiveChild}\n tooltip={item.title}\n className={cn(\n navItemBase,\n isActive || hasActiveChild ? navItemActive : navItemInactive,\n )}\n >\n <Link\n href={item.href}\n aria-label={item.title}\n aria-current={isActive ? 'page' : undefined}\n >\n <span className=\"[&>svg]:h-ico-md [&>svg]:w-ico-md shrink-0\" aria-hidden=\"true\">\n <IconProvider size=\"md\">{normalizeIcon(item.icon)}</IconProvider>\n </span>\n <span className=\"text-ds-base\">{item.title}</span>\n </Link>\n </SidebarMenuButton>\n {badgeContent && <SidebarMenuBadge>{badgeContent}</SidebarMenuBadge>}\n <CollapsibleTrigger asChild>\n <button\n className=\"absolute right-ds-02 top-1/2 flex h-5 w-5 -translate-y-1/2 items-center justify-center rounded-control text-surface-fg-subtle transition-colors hover:bg-surface-raised-hover hover:text-surface-fg group-data-[collapsible=icon]:hidden\"\n aria-label={`Toggle ${item.title}`}\n >\n <ChevronRight className=\"h-4 w-4 transition-transform duration-fast-02 ease-productive-standard group-data-[state=open]/collapsible:rotate-90\" />\n </button>\n </CollapsibleTrigger>\n </div>\n <CollapsibleContent>\n <SidebarMenuSub>\n {item.children.map((child) => {\n const childActive = isPathActive(child.href, child.exact)\n return (\n <SidebarMenuSubItem key={child.href}>\n <SidebarMenuSubButton\n asChild\n isActive={childActive}\n >\n <Link\n href={child.href}\n aria-current={childActive ? 'page' : undefined}\n >\n {child.icon && (\n <span className=\"[&>svg]:h-ico-sm [&>svg]:w-ico-sm shrink-0\" aria-hidden=\"true\">\n <IconProvider size=\"sm\">{normalizeIcon(child.icon)}</IconProvider>\n </span>\n )}\n <span>{child.title}</span>\n </Link>\n </SidebarMenuSubButton>\n </SidebarMenuSubItem>\n )\n })}\n </SidebarMenuSub>\n </CollapsibleContent>\n </SidebarMenuItem>\n </Collapsible>\n )\n }\n\n // Default: flat nav item\n return (\n <SidebarMenuItem>\n <SidebarMenuButton\n asChild\n isActive={isActive}\n tooltip={item.title}\n className={cn(\n navItemBase,\n isActive ? navItemActive : navItemInactive,\n )}\n >\n <Link\n href={item.href}\n aria-label={item.title}\n aria-current={isActive ? 'page' : undefined}\n >\n <span className=\"[&>svg]:h-ico-md [&>svg]:w-ico-md shrink-0\" aria-hidden=\"true\"><IconProvider size=\"md\">{normalizeIcon(item.icon)}</IconProvider></span>\n <span className=\"text-ds-base\">{item.title}</span>\n </Link>\n </SidebarMenuButton>\n {badgeContent && <SidebarMenuBadge>{badgeContent}</SidebarMenuBadge>}\n </SidebarMenuItem>\n )\n}\n\n// -----------------------------------------------------------------------\n// AppSidebar\n// -----------------------------------------------------------------------\n\nconst AppSidebar = React.forwardRef<HTMLDivElement, AppSidebarProps>(\n (\n {\n currentPath = '/',\n user,\n navGroups = [],\n logo,\n headerSlot,\n preFooterSlot,\n preFooterClassName,\n footerLinks = [],\n footer,\n renderItem,\n className,\n navItemRadius,\n style,\n ...props\n },\n ref,\n ) => {\n const Link = useLink()\n const isActive = (path: string, exact = false) => {\n if (exact || path === '/') {\n return currentPath === path\n }\n return currentPath.startsWith(path)\n }\n\n return (\n <ShadcnSidebar\n {...props}\n ref={ref}\n aria-label=\"Main navigation\"\n style={\n navItemRadius\n ? ({ '--ds-sidebar-item-radius': NAV_ITEM_RADIUS[navItemRadius], ...style } as React.CSSProperties)\n : style\n }\n className={cn(\n 'z-raised hidden h-full flex-col border-r border-surface-border-strong bg-surface-raised md:flex',\n className,\n )}\n >\n {/* Logo Header */}\n <SidebarHeader className=\"px-ds-06 py-ds-06\">\n {logo ?? (\n <span className=\"text-ds-lg font-semibold text-surface-fg\">\n Logo\n </span>\n )}\n </SidebarHeader>\n\n {/* User Info */}\n {user && (\n <div className=\"flex items-center gap-ds-04 px-ds-06 pb-ds-05\">\n <Avatar className=\"h-ds-sm-plus w-ds-sm-plus\">\n {user.image ? (\n <AvatarImage src={user.image} alt={user.name} />\n ) : null}\n <AvatarFallback className=\"bg-surface-raised-hover text-surface-fg\">\n {user.name?.charAt(0).toUpperCase()}\n </AvatarFallback>\n </Avatar>\n <div className=\"flex min-w-0 flex-col\">\n <span className=\"truncate text-ds-md text-surface-fg\">\n {user.name}\n </span>\n <span className=\"truncate text-ds-sm text-surface-fg-subtle\">\n {user.designation || user.role}\n </span>\n </div>\n </div>\n )}\n\n <SidebarSeparator />\n\n {/* Header Slot (S13) */}\n {headerSlot && (\n <>\n {headerSlot}\n <SidebarSeparator />\n </>\n )}\n\n {/* Navigation Groups */}\n <SidebarContent className=\"no-scrollbar px-ds-04\">\n {navGroups.map((group, idx) => (\n <div key={group.label}>\n {idx > 0 && <SidebarSeparator />}\n <SidebarGroup>\n <SidebarGroupLabel className=\"px-ds-04 text-ds-sm text-surface-fg-subtle\">\n {group.label}\n </SidebarGroupLabel>\n {group.action && (\n <SidebarGroupAction asChild>{group.action}</SidebarGroupAction>\n )}\n <SidebarGroupContent>\n <SidebarMenu>\n {group.items.map((item) => {\n const defaultRender = () => (\n <NavLink\n item={item}\n isActive={isActive(item.href, item.exact)}\n isPathActive={isActive}\n />\n )\n\n if (renderItem) {\n const custom = renderItem(item, defaultRender)\n if (custom !== null) {\n return <React.Fragment key={item.href}>{custom}</React.Fragment>\n }\n }\n\n return <React.Fragment key={item.href}>{defaultRender()}</React.Fragment>\n })}\n </SidebarMenu>\n </SidebarGroupContent>\n </SidebarGroup>\n </div>\n ))}\n </SidebarContent>\n\n {/* Pre-Footer Slot (S13) */}\n {preFooterSlot && (\n <>\n <SidebarSeparator />\n <div className={preFooterClassName}>\n {preFooterSlot}\n </div>\n </>\n )}\n\n {/* Footer */}\n {footer ? (\n <SidebarFooter className=\"gap-ds-03 px-ds-06 py-ds-05\">\n {footer.slot && <div>{footer.slot}</div>}\n\n {/* Promo banner */}\n {footer.promo && (\n <div className=\"relative rounded-surface bg-surface-raised p-ds-04 shadow-raised\">\n {footer.promo.onDismiss && (\n <button\n onClick={footer.promo.onDismiss}\n aria-label=\"Dismiss\"\n className=\"absolute right-ds-02 top-ds-02 flex h-5 w-5 items-center justify-center rounded-control text-surface-fg-subtle transition-colors hover:bg-surface-raised-hover hover:text-surface-fg\"\n >\n <CloseIcon className=\"h-3.5 w-3.5\" />\n </button>\n )}\n <div className=\"flex flex-col gap-ds-03\">\n {footer.promo.icon && (\n <span className=\"text-accent-11 [&>svg]:h-ico-md [&>svg]:w-ico-md\" aria-hidden=\"true\">\n <IconProvider size=\"md\">{normalizeIcon(footer.promo.icon)}</IconProvider>\n </span>\n )}\n <div className=\"flex min-w-0 flex-col gap-ds-03\">\n <p className=\"text-ds-sm text-surface-fg\">{footer.promo.text}</p>\n {footer.promo.action && (\n footer.promo.action.href ? (\n <Link\n href={footer.promo.action.href}\n onClick={footer.promo.action.onClick}\n className=\"inline-flex self-start rounded-control bg-accent-9 px-ds-04 py-ds-02 text-ds-sm font-medium text-accent-fg transition-colors hover:bg-accent-10\"\n >\n {footer.promo.action.label}\n </Link>\n ) : (\n <button\n onClick={footer.promo.action.onClick}\n className=\"inline-flex self-start rounded-control bg-accent-9 px-ds-04 py-ds-02 text-ds-sm font-medium text-accent-fg transition-colors hover:bg-accent-10\"\n >\n {footer.promo.action.label}\n </button>\n )\n )}\n </div>\n </div>\n </div>\n )}\n\n {/* Links + version on same line */}\n {(footer.links?.length || footer.version) && (\n <div className=\"flex items-center gap-ds-03 text-ds-sm text-surface-fg-subtle\">\n {footer.links?.map((link, i) => (\n <React.Fragment key={link.href}>\n {i > 0 && <span>·</span>}\n <Link\n className=\"transition-colors hover:text-accent-11\"\n href={link.href}\n >\n {link.label}\n </Link>\n </React.Fragment>\n ))}\n {footer.links?.length && footer.version && <span>·</span>}\n {footer.version && (\n typeof footer.version === 'string'\n ? <span>{footer.version}</span>\n : <Link className=\"transition-colors hover:text-accent-11\" href={footer.version.href}>{footer.version.label}</Link>\n )}\n </div>\n )}\n </SidebarFooter>\n ) : footerLinks.length > 0 ? (\n <SidebarFooter className=\"px-ds-06 py-ds-05\">\n <div className=\"flex items-center gap-ds-03 text-ds-sm text-surface-fg-subtle\">\n {footerLinks.map((link, i) => (\n <React.Fragment key={link.href}>\n {i > 0 && <span>·</span>}\n <Link\n className=\"transition-colors hover:text-accent-11\"\n href={link.href}\n >\n {link.label}\n </Link>\n </React.Fragment>\n ))}\n </div>\n </SidebarFooter>\n ) : null}\n </ShadcnSidebar>\n )\n },\n)\nAppSidebar.displayName = 'AppSidebar'\n\nexport { AppSidebar }\n"],"mappings":";;;;;;;;;;;;AAgJA,SAAS,EAAa,EAAE,gBAAqC;AAC3D,QACE,kBAAC,OAAD;EACE,OAAM;EACN,OAAM;EACN,QAAO;EACP,SAAQ;EACR,MAAK;EACL,QAAO;EACP,aAAY;EACZ,eAAc;EACd,gBAAe;EACJ;YAEX,kBAAC,QAAD,EAAM,GAAE,iBAAkB,CAAA;EACtB,CAAA;;AAIV,SAAS,EAAU,EAAE,gBAAqC;AACxD,QACE,kBAAC,OAAD;EACE,OAAM;EACN,OAAM;EACN,QAAO;EACP,SAAQ;EACR,MAAK;EACL,QAAO;EACP,aAAY;EACZ,eAAc;EACd,gBAAe;EACJ;YAVb,CAYE,kBAAC,QAAD,EAAM,GAAE,cAAe,CAAA,EACvB,kBAAC,QAAD,EAAM,GAAE,cAAe,CAAA,CACnB;;;AAUV,IAAM,IACJ,yIACI,IAAkB;CACtB,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,MAAM;CACP,EAGK,IAAgB,0CAChB,IAAkB;AAMxB,SAAS,EAAQ,EACf,SACA,aACA,mBAKC;CACD,IAAM,IAAO,GAAS,EAChB,IACJ,EAAK,SAAS,OAIV,OAHA,OAAO,EAAK,SAAU,YAAY,EAAK,QAAQ,KAC7C,QACA,OAAO,EAAK,MAAM;AAI1B,KAAI,EAAK,YAAY,EAAK,SAAS,SAAS,GAAG;EAC7C,IAAM,IAAiB,EAAK,SAAS,MAAM,MACzC,EAAa,EAAM,MAAM,EAAM,MAAM,CACtC;AAGD,SACE,kBAAC,GAAD;GAAa,aAHI,KAAkB,MAAa,EAAK,eAAe;GAG9B,WAAU;aAC9C,kBAAC,GAAD,EAAA,UAAA,CAEE,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,GAAD;MACE,SAAA;MACA,UAAU,KAAY;MACtB,SAAS,EAAK;MACd,WAAW,EACT,GACA,KAAY,IAAiB,IAAgB,EAC9C;gBAED,kBAAC,GAAD;OACE,MAAM,EAAK;OACX,cAAY,EAAK;OACjB,gBAAc,IAAW,SAAS,KAAA;iBAHpC,CAKE,kBAAC,QAAD;QAAM,WAAU;QAA6C,eAAY;kBACvE,kBAAC,GAAD;SAAc,MAAK;mBAAM,EAAc,EAAK,KAAK;SAAgB,CAAA;QAC5D,CAAA,EACP,kBAAC,QAAD;QAAM,WAAU;kBAAgB,EAAK;QAAa,CAAA,CAC7C;;MACW,CAAA;KACnB,KAAgB,kBAAC,GAAD,EAAA,UAAmB,GAAgC,CAAA;KACpE,kBAAC,GAAD;MAAoB,SAAA;gBAClB,kBAAC,UAAD;OACE,WAAU;OACV,cAAY,UAAU,EAAK;iBAE3B,kBAAC,GAAD,EAAc,WAAU,wHAAyH,CAAA;OAC1I,CAAA;MACU,CAAA;KACjB;OACN,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD,EAAA,UACG,EAAK,SAAS,KAAK,MAAU;IAC5B,IAAM,IAAc,EAAa,EAAM,MAAM,EAAM,MAAM;AACzD,WACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;KACE,SAAA;KACA,UAAU;eAEV,kBAAC,GAAD;MACE,MAAM,EAAM;MACZ,gBAAc,IAAc,SAAS,KAAA;gBAFvC,CAIG,EAAM,QACL,kBAAC,QAAD;OAAM,WAAU;OAA6C,eAAY;iBACvE,kBAAC,GAAD;QAAc,MAAK;kBAAM,EAAc,EAAM,KAAK;QAAgB,CAAA;OAC7D,CAAA,EAET,kBAAC,QAAD,EAAA,UAAO,EAAM,OAAa,CAAA,CACrB;;KACc,CAAA,EACJ,EAjBI,EAAM,KAiBV;KAEvB,EACa,CAAA,EACE,CAAA,CACL,EAAA,CAAA;GACN,CAAA;;AAKlB,QACE,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD;EACE,SAAA;EACU;EACV,SAAS,EAAK;EACd,WAAW,EACT,GACA,IAAW,IAAgB,EAC5B;YAED,kBAAC,GAAD;GACE,MAAM,EAAK;GACX,cAAY,EAAK;GACjB,gBAAc,IAAW,SAAS,KAAA;aAHpC,CAKE,kBAAC,QAAD;IAAM,WAAU;IAA6C,eAAY;cAAO,kBAAC,GAAD;KAAc,MAAK;eAAM,EAAc,EAAK,KAAK;KAAgB,CAAA;IAAO,CAAA,EACxJ,kBAAC,QAAD;IAAM,WAAU;cAAgB,EAAK;IAAa,CAAA,CAC7C;;EACW,CAAA,EACnB,KAAgB,kBAAC,GAAD,EAAA,UAAmB,GAAgC,CAAA,CACpD,EAAA,CAAA;;AAQtB,IAAM,IAAa,EAAM,YAErB,EACE,iBAAc,KACd,SACA,eAAY,EAAE,EACd,SACA,eACA,kBACA,uBACA,iBAAc,EAAE,EAChB,WACA,eACA,cACA,kBACA,UACA,GAAG,KAEL,MACG;CACH,IAAM,IAAO,GAAS,EAChB,KAAY,GAAc,IAAQ,OAClC,KAAS,MAAS,MACb,MAAgB,IAElB,EAAY,WAAW,EAAK;AAGrC,QACE,kBAAC,GAAD;EACE,GAAI;EACC;EACL,cAAW;EACX,OACE,IACK;GAAE,4BAA4B,EAAgB;GAAgB,GAAG;GAAO,GACzE;EAEN,WAAW,EACT,mGACA,EACD;YAZH;GAeE,kBAAC,GAAD;IAAe,WAAU;cACtB,KACC,kBAAC,QAAD;KAAM,WAAU;eAA2C;KAEpD,CAAA;IAEK,CAAA;GAGf,KACC,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,GAAD;KAAQ,WAAU;eAAlB,CACG,EAAK,QACJ,kBAAC,GAAD;MAAa,KAAK,EAAK;MAAO,KAAK,EAAK;MAAQ,CAAA,GAC9C,MACJ,kBAAC,GAAD;MAAgB,WAAU;gBACvB,EAAK,MAAM,OAAO,EAAE,CAAC,aAAa;MACpB,CAAA,CACV;QACT,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,QAAD;MAAM,WAAU;gBACb,EAAK;MACD,CAAA,EACP,kBAAC,QAAD;MAAM,WAAU;gBACb,EAAK,eAAe,EAAK;MACrB,CAAA,CACH;OACF;;GAGR,kBAAC,GAAD,EAAoB,CAAA;GAGnB,KACC,kBAAA,GAAA,EAAA,UAAA,CACG,GACD,kBAAC,GAAD,EAAoB,CAAA,CACnB,EAAA,CAAA;GAIL,kBAAC,GAAD;IAAgB,WAAU;cACvB,EAAU,KAAK,GAAO,MACrB,kBAAC,OAAD,EAAA,UAAA,CACG,IAAM,KAAK,kBAAC,GAAD,EAAoB,CAAA,EAChC,kBAAC,GAAD,EAAA,UAAA;KACE,kBAAC,GAAD;MAAmB,WAAU;gBAC1B,EAAM;MACW,CAAA;KACnB,EAAM,UACL,kBAAC,GAAD;MAAoB,SAAA;gBAAS,EAAM;MAA4B,CAAA;KAEjE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD,EAAA,UACG,EAAM,MAAM,KAAK,MAAS;MACzB,IAAM,UACJ,kBAAC,GAAD;OACQ;OACN,UAAU,EAAS,EAAK,MAAM,EAAK,MAAM;OACzC,cAAc;OACd,CAAA;AAGJ,UAAI,GAAY;OACd,IAAM,IAAS,EAAW,GAAM,EAAc;AAC9C,WAAI,MAAW,KACb,QAAO,kBAAC,EAAM,UAAP,EAAA,UAAiC,GAAwB,EAApC,EAAK,KAA+B;;AAIpE,aAAO,kBAAC,EAAM,UAAP,EAAA,UAAiC,GAAe,EAAkB,EAA7C,EAAK,KAAwC;OACzE,EACU,CAAA,EACM,CAAA;KACT,EAAA,CAAA,CACX,EAAA,EAhCI,EAAM,MAgCV,CACN;IACa,CAAA;GAGhB,KACC,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,GAAD,EAAoB,CAAA,EACpB,kBAAC,OAAD;IAAK,WAAW;cACb;IACG,CAAA,CACL,EAAA,CAAA;GAIJ,IACC,kBAAC,GAAD;IAAe,WAAU;cAAzB;KACG,EAAO,QAAQ,kBAAC,OAAD,EAAA,UAAM,EAAO,MAAW,CAAA;KAGvC,EAAO,SACN,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACG,EAAO,MAAM,aACZ,kBAAC,UAAD;OACE,SAAS,EAAO,MAAM;OACtB,cAAW;OACX,WAAU;iBAEV,kBAAC,GAAD,EAAW,WAAU,eAAgB,CAAA;OAC9B,CAAA,EAEX,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACG,EAAO,MAAM,QACZ,kBAAC,QAAD;QAAM,WAAU;QAAmD,eAAY;kBAC7E,kBAAC,GAAD;SAAc,MAAK;mBAAM,EAAc,EAAO,MAAM,KAAK;SAAgB,CAAA;QACpE,CAAA,EAET,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,KAAD;SAAG,WAAU;mBAA8B,EAAO,MAAM;SAAS,CAAA,EAChE,EAAO,MAAM,WACZ,EAAO,MAAM,OAAO,OAClB,kBAAC,GAAD;SACE,MAAM,EAAO,MAAM,OAAO;SAC1B,SAAS,EAAO,MAAM,OAAO;SAC7B,WAAU;mBAET,EAAO,MAAM,OAAO;SAChB,CAAA,GAEP,kBAAC,UAAD;SACE,SAAS,EAAO,MAAM,OAAO;SAC7B,WAAU;mBAET,EAAO,MAAM,OAAO;SACd,CAAA,EAGT;UACF;SACF;;MAIN,EAAO,OAAO,UAAU,EAAO,YAC/B,kBAAC,OAAD;MAAK,WAAU;gBAAf;OACG,EAAO,OAAO,KAAK,GAAM,MACxB,kBAAC,EAAM,UAAP,EAAA,UAAA,CACG,IAAI,KAAK,kBAAC,QAAD,EAAA,UAAM,KAAQ,CAAA,EACxB,kBAAC,GAAD;QACE,WAAU;QACV,MAAM,EAAK;kBAEV,EAAK;QACD,CAAA,CACQ,EAAA,EARI,EAAK,KAQT,CACjB;OACD,EAAO,OAAO,UAAU,EAAO,WAAW,kBAAC,QAAD,EAAA,UAAM,KAAQ,CAAA;OACxD,EAAO,YACN,OAAO,EAAO,WAAY,WACtB,kBAAC,QAAD,EAAA,UAAO,EAAO,SAAe,CAAA,GAC7B,kBAAC,GAAD;QAAM,WAAU;QAAyC,MAAM,EAAO,QAAQ;kBAAO,EAAO,QAAQ;QAAa,CAAA;OAEnH;;KAEM;QACd,EAAY,SAAS,IACvB,kBAAC,GAAD;IAAe,WAAU;cACvB,kBAAC,OAAD;KAAK,WAAU;eACZ,EAAY,KAAK,GAAM,MACtB,kBAAC,EAAM,UAAP,EAAA,UAAA,CACG,IAAI,KAAK,kBAAC,QAAD,EAAA,UAAM,KAAQ,CAAA,EACxB,kBAAC,GAAD;MACE,WAAU;MACV,MAAM,EAAK;gBAEV,EAAK;MACD,CAAA,CACQ,EAAA,EARI,EAAK,KAQT,CACjB;KACE,CAAA;IACQ,CAAA,GACd;GACU;;EAGrB;AACD,EAAW,cAAc"}
|
package/dist/shell/top-bar.js
CHANGED
|
@@ -110,7 +110,7 @@ var M = g.forwardRef(({ user: w, onNavigate: T, onLogout: E, userMenuItems: D, c
|
|
|
110
110
|
align: "center",
|
|
111
111
|
children: "User Menu"
|
|
112
112
|
})] }), /* @__PURE__ */ y(c, {
|
|
113
|
-
className: "w-[200px] rounded-overlay-lg
|
|
113
|
+
className: "w-[200px] rounded-overlay-lg bg-surface-overlay p-0 shadow-floating",
|
|
114
114
|
sideOffset: 8,
|
|
115
115
|
align: "end",
|
|
116
116
|
children: [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"top-bar.js","names":[],"sources":["../../src/shell/top-bar.tsx"],"sourcesContent":["'use client'\n\n/**\n * TopBar v2 — Composition-based application top bar.\n *\n * Subcomponents: TopBar.Left, TopBar.Center, TopBar.Right,\n * TopBar.Section, TopBar.IconButton, TopBar.Title, TopBar.UserMenu.\n */\nimport { IconLogout, IconMoon, IconSun,IconUser } from '@tabler/icons-react'\nimport * as React from 'react'\n\nimport { useColorMode } from '../hooks/use-color-mode'\nimport { Avatar, AvatarFallback, AvatarImage } from '../ui/avatar'\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from '../ui/dropdown-menu'\nimport { Icon } from '../ui/icon'\nimport { IconProvider } from '../ui/icon-context'\nimport type { IconInput } from '../ui/lib/icon-input'\nimport { normalizeIcon } from '../ui/lib/normalize-icon'\nimport { cn } from '../ui/lib/utils'\nimport {\n Tooltip,\n TooltipContent,\n TooltipTrigger,\n} from '../ui/tooltip'\n\n// -----------------------------------------------------------------------\n// Types\n// -----------------------------------------------------------------------\n\nexport interface TopBarUser {\n name: string\n email?: string\n image?: string | null\n}\n\nexport interface UserMenuItem {\n /** Display label */\n label: string\n /** Optional icon. Accepts any `IconInput`. */\n icon?: IconInput\n /** Navigate via onNavigate when clicked */\n href?: string\n /** Custom click handler */\n onClick?: () => void\n /** Render a separator before this item */\n separator?: boolean\n /** Text color semantic token (e.g. \"error\") — maps to text-{color} */\n color?: string\n /** Badge content — string for count, true for dot indicator */\n badge?: string | boolean\n /** Whether the item is disabled */\n disabled?: boolean\n}\n\n// -----------------------------------------------------------------------\n// TopBar (root)\n// -----------------------------------------------------------------------\n\ninterface TopBarRootProps extends React.HTMLAttributes<HTMLElement> {\n children: React.ReactNode\n className?: string\n}\n\nconst TopBarRoot = React.forwardRef<HTMLElement, TopBarRootProps>(\n ({ className, children, ...props }, ref) => {\n // Detect if a Center zone is present to switch to grid layout\n const hasCenter = React.Children.toArray(children).some(\n (child) => React.isValidElement(child) && child.type === TopBarCenter,\n )\n\n return (\n <header\n {...props}\n ref={ref}\n className={cn(\n 'z-sticky w-full border-b border-surface-border-strong bg-surface-raised px-ds-05 py-ds-04 md:px-ds-06',\n hasCenter\n ? 'grid grid-cols-[1fr_auto_1fr] items-center'\n : 'flex items-center',\n className,\n )}\n >\n {children}\n </header>\n )\n },\n)\nTopBarRoot.displayName = 'TopBar'\n\n// -----------------------------------------------------------------------\n// TopBar.Left\n// -----------------------------------------------------------------------\n\ninterface TopBarLeftProps extends React.HTMLAttributes<HTMLDivElement> {\n children: React.ReactNode\n}\n\nconst TopBarLeft = React.forwardRef<HTMLDivElement, TopBarLeftProps>(\n ({ className, children, ...props }, ref) => (\n <div\n ref={ref}\n className={cn('flex items-center gap-ds-04', className)}\n {...props}\n >\n {children}\n </div>\n ),\n)\nTopBarLeft.displayName = 'TopBar.Left'\n\n// -----------------------------------------------------------------------\n// TopBar.Center\n// -----------------------------------------------------------------------\n\ninterface TopBarCenterProps extends React.HTMLAttributes<HTMLDivElement> {\n children: React.ReactNode\n}\n\nconst TopBarCenter = React.forwardRef<HTMLDivElement, TopBarCenterProps>(\n ({ className, children, ...props }, ref) => (\n <div\n ref={ref}\n className={cn('flex items-center justify-center px-ds-04', className)}\n {...props}\n >\n {children}\n </div>\n ),\n)\nTopBarCenter.displayName = 'TopBar.Center'\n\n// -----------------------------------------------------------------------\n// TopBar.Right\n// -----------------------------------------------------------------------\n\ninterface TopBarRightProps extends React.HTMLAttributes<HTMLDivElement> {\n children: React.ReactNode\n}\n\nconst TopBarRight = React.forwardRef<HTMLDivElement, TopBarRightProps>(\n ({ className, children, ...props }, ref) => (\n <div\n ref={ref}\n className={cn('ml-auto flex items-center gap-ds-04', className)}\n {...props}\n >\n {children}\n </div>\n ),\n)\nTopBarRight.displayName = 'TopBar.Right'\n\n// -----------------------------------------------------------------------\n// TopBar.Section\n// -----------------------------------------------------------------------\n\nconst gapMap = {\n tight: 'gap-ds-02',\n default: 'gap-ds-04',\n loose: 'gap-ds-06',\n} as const\n\ninterface TopBarSectionProps extends React.HTMLAttributes<HTMLDivElement> {\n gap?: keyof typeof gapMap\n children: React.ReactNode\n}\n\nconst TopBarSection = React.forwardRef<HTMLDivElement, TopBarSectionProps>(\n ({ gap = 'default', className, children, ...props }, ref) => (\n <div\n ref={ref}\n className={cn('flex items-center', gapMap[gap], className)}\n {...props}\n >\n {children}\n </div>\n ),\n)\nTopBarSection.displayName = 'TopBar.Section'\n\n// -----------------------------------------------------------------------\n// TopBar.IconButton\n// -----------------------------------------------------------------------\n\ninterface TopBarIconButtonProps\n extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n icon: IconInput\n tooltip: string\n}\n\nconst TopBarIconButton = React.forwardRef<\n HTMLButtonElement,\n TopBarIconButtonProps\n>(({ icon, tooltip, className, ...props }, ref) => (\n <Tooltip>\n <TooltipTrigger asChild>\n <button\n ref={ref}\n type=\"button\"\n aria-label={tooltip}\n className={cn(\n 'flex h-ds-sm-plus w-ds-sm-plus items-center justify-center rounded-pill border border-surface-border-strong bg-surface-raised-hover text-surface-fg-muted transition-[color,background-color,border-color,transform] hover:bg-surface-raised-active active:scale-90 duration-fast-01 ease-productive-standard',\n className,\n )}\n {...props}\n >\n <span className=\"[&>svg]:h-ico-sm [&>svg]:w-ico-sm\" aria-hidden=\"true\">\n <IconProvider size=\"sm\">{normalizeIcon(icon)}</IconProvider>\n </span>\n </button>\n </TooltipTrigger>\n <TooltipContent side=\"bottom\" align=\"center\">\n {tooltip}\n </TooltipContent>\n </Tooltip>\n))\nTopBarIconButton.displayName = 'TopBar.IconButton'\n\n// -----------------------------------------------------------------------\n// TopBar.Title\n// -----------------------------------------------------------------------\n\ninterface TopBarTitleProps extends React.HTMLAttributes<HTMLHeadingElement> {\n children: React.ReactNode\n}\n\nconst TopBarTitle = React.forwardRef<HTMLHeadingElement, TopBarTitleProps>(\n ({ className, children, ...props }, ref) => (\n <h2\n ref={ref}\n className={cn(\n 'hidden text-ds-lg text-surface-fg md:block',\n className,\n )}\n {...props}\n >\n {children}\n </h2>\n ),\n)\nTopBarTitle.displayName = 'TopBar.Title'\n\n// -----------------------------------------------------------------------\n// TopBar.UserMenu\n// -----------------------------------------------------------------------\n\ninterface TopBarUserMenuProps {\n user: TopBarUser\n onNavigate?: (path: string) => void\n onLogout?: () => void\n userMenuItems?: UserMenuItem[]\n className?: string\n}\n\nconst TopBarUserMenu = React.forwardRef<HTMLButtonElement, TopBarUserMenuProps>(\n ({ user, onNavigate, onLogout, userMenuItems, className }, ref) => {\n const { colorMode, toggleColorMode } = useColorMode()\n\n return (\n <DropdownMenu>\n <Tooltip>\n <TooltipTrigger asChild>\n <DropdownMenuTrigger asChild>\n <button\n ref={ref}\n type=\"button\"\n className={cn('flex items-center gap-ds-03 outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 focus-visible:ring-offset-2', className)}\n >\n <Avatar className=\"h-ds-sm-plus w-ds-sm-plus cursor-pointer\">\n {user.image ? (\n <AvatarImage src={user.image} alt={user.name} />\n ) : null}\n <AvatarFallback className=\"bg-surface-raised-hover text-surface-fg\">\n {user.name?.charAt(0).toUpperCase()}\n </AvatarFallback>\n </Avatar>\n </button>\n </DropdownMenuTrigger>\n </TooltipTrigger>\n <TooltipContent side=\"bottom\" align=\"center\">\n User Menu\n </TooltipContent>\n </Tooltip>\n\n <DropdownMenuContent\n className=\"w-[200px] rounded-overlay-lg border border-surface-border-strong bg-surface-overlay p-0 shadow-floating\"\n sideOffset={8}\n align=\"end\"\n >\n {/* User Info */}\n <div className=\"border-b border-surface-border-strong px-ds-05 py-ds-04\">\n <p className=\"text-ds-md text-surface-fg\">{user.name}</p>\n {user.email && (\n <p className=\"text-ds-sm text-surface-fg-subtle truncate\">{user.email}</p>\n )}\n </div>\n\n <DropdownMenuItem\n className=\"flex w-full cursor-pointer items-center gap-ds-03 px-ds-05 py-ds-04 hover:bg-surface-raised\"\n onClick={() => onNavigate?.('/profile')}\n >\n <Icon icon={IconUser} size=\"sm\" className=\"text-surface-fg-muted\" />\n <span className=\"text-ds-md text-surface-fg-muted\">Profile</span>\n </DropdownMenuItem>\n\n {/* Custom user menu items */}\n {userMenuItems?.map((item, index) => {\n const colorMap: Record<string, string> = {\n error: 'text-error-11',\n success: 'text-success-11',\n warning: 'text-warning-11',\n info: 'text-info-11',\n }\n const textColor = item.color\n ? (colorMap[item.color] ?? 'text-surface-fg-muted')\n : 'text-surface-fg-muted'\n return (\n <React.Fragment key={item.label + index}>\n {item.separator && (\n <DropdownMenuSeparator className=\"bg-surface-border\" />\n )}\n <DropdownMenuItem\n className={cn(\n 'flex w-full cursor-pointer items-center gap-ds-03 px-ds-05 py-ds-04 hover:bg-surface-raised',\n item.disabled && 'pointer-events-none opacity-action-disabled',\n )}\n disabled={item.disabled}\n onClick={() => {\n if (item.disabled) return\n if (item.onClick) item.onClick()\n else if (item.href) onNavigate?.(item.href)\n }}\n >\n {item.icon && (\n <span\n className={cn(\n '[&>svg]:h-ico-sm [&>svg]:w-ico-sm',\n textColor,\n )}\n >\n <IconProvider size=\"sm\">{normalizeIcon(item.icon)}</IconProvider>\n </span>\n )}\n <span className={cn('text-ds-md', textColor)}>\n {item.label}\n </span>\n {item.badge != null &&\n item.badge !== false &&\n (typeof item.badge === 'string' ? (\n <span className=\"ml-auto inline-flex h-[18px] min-w-[18px] items-center justify-center rounded-pill bg-error-9 px-ds-02 text-[10px] font-semibold leading-none text-error-fg\">\n {item.badge}\n </span>\n ) : (\n <span className=\"ml-auto h-[8px] w-[8px] rounded-pill bg-error-9\" />\n ))}\n </DropdownMenuItem>\n </React.Fragment>\n )\n })}\n\n <DropdownMenuItem\n className=\"flex w-full cursor-pointer items-center gap-ds-03 px-ds-05 py-ds-04 hover:bg-surface-raised\"\n onClick={toggleColorMode}\n >\n {colorMode === 'dark' ? (\n <Icon icon={IconSun} size=\"sm\" className=\"text-surface-fg-muted\" />\n ) : (\n <Icon icon={IconMoon} size=\"sm\" className=\"text-surface-fg-muted\" />\n )}\n <span className=\"text-ds-md text-surface-fg-muted\">\n {colorMode === 'dark' ? 'Light Mode' : 'Dark Mode'}\n </span>\n </DropdownMenuItem>\n\n {onLogout && (\n <>\n <DropdownMenuSeparator className=\"bg-surface-border\" />\n <DropdownMenuItem\n className=\"flex w-full cursor-pointer items-center gap-ds-03 px-ds-05 py-ds-04 hover:bg-surface-raised\"\n onClick={onLogout}\n >\n <Icon icon={IconLogout} size=\"sm\" className=\"text-error-11\" />\n <span className=\"text-ds-md text-error-11\">Logout</span>\n </DropdownMenuItem>\n </>\n )}\n </DropdownMenuContent>\n </DropdownMenu>\n )\n },\n)\nTopBarUserMenu.displayName = 'TopBar.UserMenu'\n\n// -----------------------------------------------------------------------\n// Compound export\n// -----------------------------------------------------------------------\n\nexport type TopBarProps = TopBarRootProps\n\nconst TopBar = Object.assign(TopBarRoot, {\n Left: TopBarLeft,\n Center: TopBarCenter,\n Right: TopBarRight,\n Section: TopBarSection,\n IconButton: TopBarIconButton,\n Title: TopBarTitle,\n UserMenu: TopBarUserMenu,\n})\n\nexport { TopBar }\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"top-bar.js","names":[],"sources":["../../src/shell/top-bar.tsx"],"sourcesContent":["'use client'\n\n/**\n * TopBar v2 — Composition-based application top bar.\n *\n * Subcomponents: TopBar.Left, TopBar.Center, TopBar.Right,\n * TopBar.Section, TopBar.IconButton, TopBar.Title, TopBar.UserMenu.\n */\nimport { IconLogout, IconMoon, IconSun,IconUser } from '@tabler/icons-react'\nimport * as React from 'react'\n\nimport { useColorMode } from '../hooks/use-color-mode'\nimport { Avatar, AvatarFallback, AvatarImage } from '../ui/avatar'\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from '../ui/dropdown-menu'\nimport { Icon } from '../ui/icon'\nimport { IconProvider } from '../ui/icon-context'\nimport type { IconInput } from '../ui/lib/icon-input'\nimport { normalizeIcon } from '../ui/lib/normalize-icon'\nimport { cn } from '../ui/lib/utils'\nimport {\n Tooltip,\n TooltipContent,\n TooltipTrigger,\n} from '../ui/tooltip'\n\n// -----------------------------------------------------------------------\n// Types\n// -----------------------------------------------------------------------\n\nexport interface TopBarUser {\n name: string\n email?: string\n image?: string | null\n}\n\nexport interface UserMenuItem {\n /** Display label */\n label: string\n /** Optional icon. Accepts any `IconInput`. */\n icon?: IconInput\n /** Navigate via onNavigate when clicked */\n href?: string\n /** Custom click handler */\n onClick?: () => void\n /** Render a separator before this item */\n separator?: boolean\n /** Text color semantic token (e.g. \"error\") — maps to text-{color} */\n color?: string\n /** Badge content — string for count, true for dot indicator */\n badge?: string | boolean\n /** Whether the item is disabled */\n disabled?: boolean\n}\n\n// -----------------------------------------------------------------------\n// TopBar (root)\n// -----------------------------------------------------------------------\n\ninterface TopBarRootProps extends React.HTMLAttributes<HTMLElement> {\n children: React.ReactNode\n className?: string\n}\n\nconst TopBarRoot = React.forwardRef<HTMLElement, TopBarRootProps>(\n ({ className, children, ...props }, ref) => {\n // Detect if a Center zone is present to switch to grid layout\n const hasCenter = React.Children.toArray(children).some(\n (child) => React.isValidElement(child) && child.type === TopBarCenter,\n )\n\n return (\n <header\n {...props}\n ref={ref}\n className={cn(\n 'z-sticky w-full border-b border-surface-border-strong bg-surface-raised px-ds-05 py-ds-04 md:px-ds-06',\n hasCenter\n ? 'grid grid-cols-[1fr_auto_1fr] items-center'\n : 'flex items-center',\n className,\n )}\n >\n {children}\n </header>\n )\n },\n)\nTopBarRoot.displayName = 'TopBar'\n\n// -----------------------------------------------------------------------\n// TopBar.Left\n// -----------------------------------------------------------------------\n\ninterface TopBarLeftProps extends React.HTMLAttributes<HTMLDivElement> {\n children: React.ReactNode\n}\n\nconst TopBarLeft = React.forwardRef<HTMLDivElement, TopBarLeftProps>(\n ({ className, children, ...props }, ref) => (\n <div\n ref={ref}\n className={cn('flex items-center gap-ds-04', className)}\n {...props}\n >\n {children}\n </div>\n ),\n)\nTopBarLeft.displayName = 'TopBar.Left'\n\n// -----------------------------------------------------------------------\n// TopBar.Center\n// -----------------------------------------------------------------------\n\ninterface TopBarCenterProps extends React.HTMLAttributes<HTMLDivElement> {\n children: React.ReactNode\n}\n\nconst TopBarCenter = React.forwardRef<HTMLDivElement, TopBarCenterProps>(\n ({ className, children, ...props }, ref) => (\n <div\n ref={ref}\n className={cn('flex items-center justify-center px-ds-04', className)}\n {...props}\n >\n {children}\n </div>\n ),\n)\nTopBarCenter.displayName = 'TopBar.Center'\n\n// -----------------------------------------------------------------------\n// TopBar.Right\n// -----------------------------------------------------------------------\n\ninterface TopBarRightProps extends React.HTMLAttributes<HTMLDivElement> {\n children: React.ReactNode\n}\n\nconst TopBarRight = React.forwardRef<HTMLDivElement, TopBarRightProps>(\n ({ className, children, ...props }, ref) => (\n <div\n ref={ref}\n className={cn('ml-auto flex items-center gap-ds-04', className)}\n {...props}\n >\n {children}\n </div>\n ),\n)\nTopBarRight.displayName = 'TopBar.Right'\n\n// -----------------------------------------------------------------------\n// TopBar.Section\n// -----------------------------------------------------------------------\n\nconst gapMap = {\n tight: 'gap-ds-02',\n default: 'gap-ds-04',\n loose: 'gap-ds-06',\n} as const\n\ninterface TopBarSectionProps extends React.HTMLAttributes<HTMLDivElement> {\n gap?: keyof typeof gapMap\n children: React.ReactNode\n}\n\nconst TopBarSection = React.forwardRef<HTMLDivElement, TopBarSectionProps>(\n ({ gap = 'default', className, children, ...props }, ref) => (\n <div\n ref={ref}\n className={cn('flex items-center', gapMap[gap], className)}\n {...props}\n >\n {children}\n </div>\n ),\n)\nTopBarSection.displayName = 'TopBar.Section'\n\n// -----------------------------------------------------------------------\n// TopBar.IconButton\n// -----------------------------------------------------------------------\n\ninterface TopBarIconButtonProps\n extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n icon: IconInput\n tooltip: string\n}\n\nconst TopBarIconButton = React.forwardRef<\n HTMLButtonElement,\n TopBarIconButtonProps\n>(({ icon, tooltip, className, ...props }, ref) => (\n <Tooltip>\n <TooltipTrigger asChild>\n <button\n ref={ref}\n type=\"button\"\n aria-label={tooltip}\n className={cn(\n 'flex h-ds-sm-plus w-ds-sm-plus items-center justify-center rounded-pill border border-surface-border-strong bg-surface-raised-hover text-surface-fg-muted transition-[color,background-color,border-color,transform] hover:bg-surface-raised-active active:scale-90 duration-fast-01 ease-productive-standard',\n className,\n )}\n {...props}\n >\n <span className=\"[&>svg]:h-ico-sm [&>svg]:w-ico-sm\" aria-hidden=\"true\">\n <IconProvider size=\"sm\">{normalizeIcon(icon)}</IconProvider>\n </span>\n </button>\n </TooltipTrigger>\n <TooltipContent side=\"bottom\" align=\"center\">\n {tooltip}\n </TooltipContent>\n </Tooltip>\n))\nTopBarIconButton.displayName = 'TopBar.IconButton'\n\n// -----------------------------------------------------------------------\n// TopBar.Title\n// -----------------------------------------------------------------------\n\ninterface TopBarTitleProps extends React.HTMLAttributes<HTMLHeadingElement> {\n children: React.ReactNode\n}\n\nconst TopBarTitle = React.forwardRef<HTMLHeadingElement, TopBarTitleProps>(\n ({ className, children, ...props }, ref) => (\n <h2\n ref={ref}\n className={cn(\n 'hidden text-ds-lg text-surface-fg md:block',\n className,\n )}\n {...props}\n >\n {children}\n </h2>\n ),\n)\nTopBarTitle.displayName = 'TopBar.Title'\n\n// -----------------------------------------------------------------------\n// TopBar.UserMenu\n// -----------------------------------------------------------------------\n\ninterface TopBarUserMenuProps {\n user: TopBarUser\n onNavigate?: (path: string) => void\n onLogout?: () => void\n userMenuItems?: UserMenuItem[]\n className?: string\n}\n\nconst TopBarUserMenu = React.forwardRef<HTMLButtonElement, TopBarUserMenuProps>(\n ({ user, onNavigate, onLogout, userMenuItems, className }, ref) => {\n const { colorMode, toggleColorMode } = useColorMode()\n\n return (\n <DropdownMenu>\n <Tooltip>\n <TooltipTrigger asChild>\n <DropdownMenuTrigger asChild>\n <button\n ref={ref}\n type=\"button\"\n className={cn('flex items-center gap-ds-03 outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 focus-visible:ring-offset-2', className)}\n >\n <Avatar className=\"h-ds-sm-plus w-ds-sm-plus cursor-pointer\">\n {user.image ? (\n <AvatarImage src={user.image} alt={user.name} />\n ) : null}\n <AvatarFallback className=\"bg-surface-raised-hover text-surface-fg\">\n {user.name?.charAt(0).toUpperCase()}\n </AvatarFallback>\n </Avatar>\n </button>\n </DropdownMenuTrigger>\n </TooltipTrigger>\n <TooltipContent side=\"bottom\" align=\"center\">\n User Menu\n </TooltipContent>\n </Tooltip>\n\n <DropdownMenuContent\n className=\"w-[200px] rounded-overlay-lg bg-surface-overlay p-0 shadow-floating\"\n sideOffset={8}\n align=\"end\"\n >\n {/* User Info */}\n <div className=\"border-b border-surface-border-strong px-ds-05 py-ds-04\">\n <p className=\"text-ds-md text-surface-fg\">{user.name}</p>\n {user.email && (\n <p className=\"text-ds-sm text-surface-fg-subtle truncate\">{user.email}</p>\n )}\n </div>\n\n <DropdownMenuItem\n className=\"flex w-full cursor-pointer items-center gap-ds-03 px-ds-05 py-ds-04 hover:bg-surface-raised\"\n onClick={() => onNavigate?.('/profile')}\n >\n <Icon icon={IconUser} size=\"sm\" className=\"text-surface-fg-muted\" />\n <span className=\"text-ds-md text-surface-fg-muted\">Profile</span>\n </DropdownMenuItem>\n\n {/* Custom user menu items */}\n {userMenuItems?.map((item, index) => {\n const colorMap: Record<string, string> = {\n error: 'text-error-11',\n success: 'text-success-11',\n warning: 'text-warning-11',\n info: 'text-info-11',\n }\n const textColor = item.color\n ? (colorMap[item.color] ?? 'text-surface-fg-muted')\n : 'text-surface-fg-muted'\n return (\n <React.Fragment key={item.label + index}>\n {item.separator && (\n <DropdownMenuSeparator className=\"bg-surface-border\" />\n )}\n <DropdownMenuItem\n className={cn(\n 'flex w-full cursor-pointer items-center gap-ds-03 px-ds-05 py-ds-04 hover:bg-surface-raised',\n item.disabled && 'pointer-events-none opacity-action-disabled',\n )}\n disabled={item.disabled}\n onClick={() => {\n if (item.disabled) return\n if (item.onClick) item.onClick()\n else if (item.href) onNavigate?.(item.href)\n }}\n >\n {item.icon && (\n <span\n className={cn(\n '[&>svg]:h-ico-sm [&>svg]:w-ico-sm',\n textColor,\n )}\n >\n <IconProvider size=\"sm\">{normalizeIcon(item.icon)}</IconProvider>\n </span>\n )}\n <span className={cn('text-ds-md', textColor)}>\n {item.label}\n </span>\n {item.badge != null &&\n item.badge !== false &&\n (typeof item.badge === 'string' ? (\n <span className=\"ml-auto inline-flex h-[18px] min-w-[18px] items-center justify-center rounded-pill bg-error-9 px-ds-02 text-[10px] font-semibold leading-none text-error-fg\">\n {item.badge}\n </span>\n ) : (\n <span className=\"ml-auto h-[8px] w-[8px] rounded-pill bg-error-9\" />\n ))}\n </DropdownMenuItem>\n </React.Fragment>\n )\n })}\n\n <DropdownMenuItem\n className=\"flex w-full cursor-pointer items-center gap-ds-03 px-ds-05 py-ds-04 hover:bg-surface-raised\"\n onClick={toggleColorMode}\n >\n {colorMode === 'dark' ? (\n <Icon icon={IconSun} size=\"sm\" className=\"text-surface-fg-muted\" />\n ) : (\n <Icon icon={IconMoon} size=\"sm\" className=\"text-surface-fg-muted\" />\n )}\n <span className=\"text-ds-md text-surface-fg-muted\">\n {colorMode === 'dark' ? 'Light Mode' : 'Dark Mode'}\n </span>\n </DropdownMenuItem>\n\n {onLogout && (\n <>\n <DropdownMenuSeparator className=\"bg-surface-border\" />\n <DropdownMenuItem\n className=\"flex w-full cursor-pointer items-center gap-ds-03 px-ds-05 py-ds-04 hover:bg-surface-raised\"\n onClick={onLogout}\n >\n <Icon icon={IconLogout} size=\"sm\" className=\"text-error-11\" />\n <span className=\"text-ds-md text-error-11\">Logout</span>\n </DropdownMenuItem>\n </>\n )}\n </DropdownMenuContent>\n </DropdownMenu>\n )\n },\n)\nTopBarUserMenu.displayName = 'TopBar.UserMenu'\n\n// -----------------------------------------------------------------------\n// Compound export\n// -----------------------------------------------------------------------\n\nexport type TopBarProps = TopBarRootProps\n\nconst TopBar = Object.assign(TopBarRoot, {\n Left: TopBarLeft,\n Center: TopBarCenter,\n Right: TopBarRight,\n Section: TopBarSection,\n IconButton: TopBarIconButton,\n Title: TopBarTitle,\n UserMenu: TopBarUserMenu,\n})\n\nexport { TopBar }\n"],"mappings":"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"}
|
package/dist/tokens/semantic.css
CHANGED
|
@@ -493,14 +493,18 @@
|
|
|
493
493
|
0 2px 4px -1.5px oklch(var(--shadow-color) / calc(0.045 * var(--shadow-strength))),
|
|
494
494
|
0 6px 12px -3px oklch(var(--shadow-color) / calc(0.035 * var(--shadow-strength))),
|
|
495
495
|
0 14px 28px -8px oklch(var(--shadow-color) / calc(0.025 * var(--shadow-strength)));
|
|
496
|
+
/* Hairline edge ring — the shadow's own 1px border-substitute (make-kit rule #6:
|
|
497
|
+
shadow already carries the ring, so components never add an explicit border).
|
|
498
|
+
Light: cool tint. Dark: a light ring, since drop shadows barely read on dark. */
|
|
499
|
+
--shadow-edge-ring: 0 0 0 1px oklch(var(--shadow-color) / calc(0.09 * var(--shadow-strength)));
|
|
496
500
|
--shadow-md-internal:
|
|
497
|
-
|
|
501
|
+
var(--shadow-edge-ring),
|
|
498
502
|
0 1px 2px -1px oklch(var(--shadow-color) / calc(0.05 * var(--shadow-strength))),
|
|
499
503
|
0 4px 8px -2px oklch(var(--shadow-color) / calc(0.04 * var(--shadow-strength))),
|
|
500
504
|
0 10px 20px -5px oklch(var(--shadow-color) / calc(0.035 * var(--shadow-strength))),
|
|
501
505
|
0 24px 44px -12px oklch(var(--shadow-color) / calc(0.025 * var(--shadow-strength)));
|
|
502
506
|
--shadow-lg-internal:
|
|
503
|
-
|
|
507
|
+
var(--shadow-edge-ring),
|
|
504
508
|
0 1px 2px -1px oklch(var(--shadow-color) / calc(0.05 * var(--shadow-strength))),
|
|
505
509
|
0 3px 6px -2px oklch(var(--shadow-color) / calc(0.045 * var(--shadow-strength))),
|
|
506
510
|
0 8px 16px -4px oklch(var(--shadow-color) / calc(0.04 * var(--shadow-strength))),
|
|
@@ -603,6 +607,8 @@
|
|
|
603
607
|
/* Shadows (heavier in dark mode) — brand-reactive via color-mix on
|
|
604
608
|
--color-accent-9 so they follow consumer brand swaps. */
|
|
605
609
|
--shadow-strength: 2.5;
|
|
610
|
+
/* Light ring on dark — a dark-tinted ring would vanish against dark surfaces. */
|
|
611
|
+
--shadow-edge-ring: 0 0 0 1px oklch(1 0 0 / 0.12);
|
|
606
612
|
--shadow-brand: 0 2px 8px color-mix(in oklch, var(--color-accent-9) 30%, transparent), 0 6px 20px color-mix(in oklch, var(--color-accent-9) 20%, transparent);
|
|
607
613
|
--shadow-glow: 0 0 0 1.5px color-mix(in oklch, var(--color-accent-9) 35%, transparent), 0 0 10px color-mix(in oklch, var(--color-accent-9) 20%, transparent);
|
|
608
614
|
--shadow-ring: 0 0 0 2px color-mix(in oklch, var(--color-accent-9) 45%, transparent);
|
package/dist/ui/alert-dialog.js
CHANGED
|
@@ -68,7 +68,7 @@ var w = p.forwardRef(({ className: e, children: t, responsive: n, ...r }, i) =>
|
|
|
68
68
|
...l.smooth,
|
|
69
69
|
opacity: u.fade
|
|
70
70
|
},
|
|
71
|
-
className: d("fixed z-modal grid w-full gap-ds-05 bg-surface-overlay p-ds-06", n === !1 ? "left-[50%] top-[50%] max-w-lg rounded-overlay-lg
|
|
71
|
+
className: d("fixed z-modal grid w-full gap-ds-05 bg-surface-overlay p-ds-06", n === !1 ? "left-[50%] top-[50%] max-w-lg rounded-overlay-lg shadow-overlay" : "inset-0 md:inset-auto md:left-[50%] md:top-[50%] md:max-w-lg md:rounded-overlay-lg md:shadow-overlay", e),
|
|
72
72
|
children: t
|
|
73
73
|
})
|
|
74
74
|
})]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"alert-dialog.js","names":[],"sources":["../../src/ui/alert-dialog.tsx"],"sourcesContent":["'use client'\n\nimport * as AlertDialogPrimitive from '@primitives/react-alert-dialog'\nimport { AnimatePresence,motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { useIsMobile } from '../hooks/use-mobile'\nimport { springs, tweens } from './lib/motion'\nimport { cn } from './lib/utils'\n\n// ── Internal context to thread `open` state to animated children ──\n\ntype AlertDialogContextValue = { open: boolean }\nconst AlertDialogContext = React.createContext<AlertDialogContextValue>({ open: false })\nconst useAlertDialogOpen = () => React.useContext(AlertDialogContext)\n\nconst AlertDialog: React.FC<React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Root>> = ({\n open: openProp,\n defaultOpen,\n onOpenChange,\n ...props\n}) => {\n const [internalOpen, setInternalOpen] = React.useState(defaultOpen ?? false)\n const isControlled = openProp !== undefined\n const open = isControlled ? openProp : internalOpen\n\n const handleOpenChange = React.useCallback(\n (nextOpen: boolean) => {\n if (!isControlled) setInternalOpen(nextOpen)\n onOpenChange?.(nextOpen)\n },\n [isControlled, onOpenChange],\n )\n\n const contextValue = React.useMemo(() => ({ open }), [open])\n\n return (\n <AlertDialogContext.Provider value={contextValue}>\n <AlertDialogPrimitive.Root open={open} onOpenChange={handleOpenChange} {...props} />\n </AlertDialogContext.Provider>\n )\n}\nAlertDialog.displayName = 'AlertDialog'\n\nconst AlertDialogTrigger = AlertDialogPrimitive.Trigger\n\nconst AlertDialogPortal = AlertDialogPrimitive.Portal\n\nconst AlertDialogOverlay = React.forwardRef<\n React.ElementRef<typeof AlertDialogPrimitive.Overlay>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Overlay>\n>(({ className, ...props }, ref) => (\n <AlertDialogPrimitive.Overlay\n ref={ref}\n forceMount\n className={cn(\n 'fixed inset-0 z-modal bg-overlay',\n className,\n )}\n {...props}\n />\n))\nAlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName\n\ninterface AlertDialogContentProps extends React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Content> {\n /** When true (default), AlertDialog fills the screen on mobile (<768px). Set false to always use centered modal. */\n responsive?: boolean\n}\n\nconst AlertDialogContent = React.forwardRef<\n React.ElementRef<typeof AlertDialogPrimitive.Content>,\n AlertDialogContentProps\n>(({ className, children, responsive, ...props }, ref) => {\n const { open } = useAlertDialogOpen()\n const isMobileRaw = useIsMobile()\n const isMobile = responsive !== false && isMobileRaw\n\n return (\n <AnimatePresence>\n {open && (\n <AlertDialogPortal forceMount>\n <AlertDialogOverlay asChild>\n <motion.div\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n exit={{ opacity: 0 }}\n transition={tweens.fade}\n />\n </AlertDialogOverlay>\n <AlertDialogPrimitive.Content\n ref={ref}\n forceMount\n asChild\n {...props}\n >\n <motion.div\n initial={isMobile ? { y: '100%' } : { opacity: 0, scale: 0.95, x: '-50%', y: '-50%' }}\n animate={isMobile ? { y: 0 } : { opacity: 1, scale: 1, x: '-50%', y: '-50%' }}\n exit={isMobile ? { y: '100%' } : { opacity: 0, scale: 0.95, x: '-50%', y: '-50%' }}\n transition={isMobile\n ? springs.smooth\n : { ...springs.smooth, opacity: tweens.fade }\n }\n className={cn(\n 'fixed z-modal grid w-full gap-ds-05 bg-surface-overlay p-ds-06',\n responsive !== false\n ? 'inset-0 md:inset-auto md:left-[50%] md:top-[50%] md:max-w-lg md:rounded-overlay-lg md:border md:border-surface-border-strong md:shadow-overlay'\n : 'left-[50%] top-[50%] max-w-lg rounded-overlay-lg border border-surface-border-strong shadow-overlay',\n className,\n )}\n >\n {children}\n </motion.div>\n </AlertDialogPrimitive.Content>\n </AlertDialogPortal>\n )}\n </AnimatePresence>\n )\n})\nAlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName\n\nconst AlertDialogHeader = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(\n ({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\n 'flex flex-col space-y-ds-02b text-center sm:text-left',\n className,\n )}\n {...props}\n />\n ),\n)\nAlertDialogHeader.displayName = 'AlertDialogHeader'\n\nconst AlertDialogFooter = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(\n ({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\n 'flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-ds-03',\n className,\n )}\n {...props}\n />\n ),\n)\nAlertDialogFooter.displayName = 'AlertDialogFooter'\n\nconst AlertDialogTitle = React.forwardRef<\n React.ElementRef<typeof AlertDialogPrimitive.Title>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Title>\n>(({ className, ...props }, ref) => (\n <AlertDialogPrimitive.Title\n ref={ref}\n className={cn(\n 'text-ds-lg font-semibold',\n className,\n )}\n {...props}\n />\n))\nAlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName\n\nconst AlertDialogDescription = React.forwardRef<\n React.ElementRef<typeof AlertDialogPrimitive.Description>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Description>\n>(({ className, ...props }, ref) => (\n <AlertDialogPrimitive.Description\n ref={ref}\n className={cn('text-ds-md text-surface-fg-muted', className)}\n {...props}\n />\n))\nAlertDialogDescription.displayName =\n AlertDialogPrimitive.Description.displayName\n\nconst AlertDialogAction = React.forwardRef<\n React.ElementRef<typeof AlertDialogPrimitive.Action>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Action>\n>(({ className, ...props }, ref) => (\n <AlertDialogPrimitive.Action\n ref={ref}\n className={cn(\n 'inline-flex h-ds-md items-center justify-center rounded-control px-ds-05 text-ds-md font-semibold transition-colors bg-accent-9 text-accent-fg hover:bg-accent-10 active:bg-accent-10 shadow-raised focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-action-disabled',\n className,\n )}\n {...props}\n />\n))\nAlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName\n\nconst AlertDialogCancel = React.forwardRef<\n React.ElementRef<typeof AlertDialogPrimitive.Cancel>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Cancel>\n>(({ className, ...props }, ref) => (\n <AlertDialogPrimitive.Cancel\n ref={ref}\n className={cn(\n 'inline-flex h-ds-md items-center justify-center rounded-control px-ds-05 text-ds-md font-semibold transition-colors bg-transparent text-surface-fg-muted border border-surface-border-strong hover:bg-surface-raised hover:text-surface-fg focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-action-disabled',\n className,\n )}\n {...props}\n />\n))\nAlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName\n\nexport type { AlertDialogContentProps }\nexport type AlertDialogActionProps = React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Action>\nexport type AlertDialogCancelProps = React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Cancel>\n\nexport {\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogOverlay,\n AlertDialogPortal,\n AlertDialogTitle,\n AlertDialogTrigger,\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"alert-dialog.js","names":[],"sources":["../../src/ui/alert-dialog.tsx"],"sourcesContent":["'use client'\n\nimport * as AlertDialogPrimitive from '@primitives/react-alert-dialog'\nimport { AnimatePresence,motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { useIsMobile } from '../hooks/use-mobile'\nimport { springs, tweens } from './lib/motion'\nimport { cn } from './lib/utils'\n\n// ── Internal context to thread `open` state to animated children ──\n\ntype AlertDialogContextValue = { open: boolean }\nconst AlertDialogContext = React.createContext<AlertDialogContextValue>({ open: false })\nconst useAlertDialogOpen = () => React.useContext(AlertDialogContext)\n\nconst AlertDialog: React.FC<React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Root>> = ({\n open: openProp,\n defaultOpen,\n onOpenChange,\n ...props\n}) => {\n const [internalOpen, setInternalOpen] = React.useState(defaultOpen ?? false)\n const isControlled = openProp !== undefined\n const open = isControlled ? openProp : internalOpen\n\n const handleOpenChange = React.useCallback(\n (nextOpen: boolean) => {\n if (!isControlled) setInternalOpen(nextOpen)\n onOpenChange?.(nextOpen)\n },\n [isControlled, onOpenChange],\n )\n\n const contextValue = React.useMemo(() => ({ open }), [open])\n\n return (\n <AlertDialogContext.Provider value={contextValue}>\n <AlertDialogPrimitive.Root open={open} onOpenChange={handleOpenChange} {...props} />\n </AlertDialogContext.Provider>\n )\n}\nAlertDialog.displayName = 'AlertDialog'\n\nconst AlertDialogTrigger = AlertDialogPrimitive.Trigger\n\nconst AlertDialogPortal = AlertDialogPrimitive.Portal\n\nconst AlertDialogOverlay = React.forwardRef<\n React.ElementRef<typeof AlertDialogPrimitive.Overlay>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Overlay>\n>(({ className, ...props }, ref) => (\n <AlertDialogPrimitive.Overlay\n ref={ref}\n forceMount\n className={cn(\n 'fixed inset-0 z-modal bg-overlay',\n className,\n )}\n {...props}\n />\n))\nAlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName\n\ninterface AlertDialogContentProps extends React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Content> {\n /** When true (default), AlertDialog fills the screen on mobile (<768px). Set false to always use centered modal. */\n responsive?: boolean\n}\n\nconst AlertDialogContent = React.forwardRef<\n React.ElementRef<typeof AlertDialogPrimitive.Content>,\n AlertDialogContentProps\n>(({ className, children, responsive, ...props }, ref) => {\n const { open } = useAlertDialogOpen()\n const isMobileRaw = useIsMobile()\n const isMobile = responsive !== false && isMobileRaw\n\n return (\n <AnimatePresence>\n {open && (\n <AlertDialogPortal forceMount>\n <AlertDialogOverlay asChild>\n <motion.div\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n exit={{ opacity: 0 }}\n transition={tweens.fade}\n />\n </AlertDialogOverlay>\n <AlertDialogPrimitive.Content\n ref={ref}\n forceMount\n asChild\n {...props}\n >\n <motion.div\n initial={isMobile ? { y: '100%' } : { opacity: 0, scale: 0.95, x: '-50%', y: '-50%' }}\n animate={isMobile ? { y: 0 } : { opacity: 1, scale: 1, x: '-50%', y: '-50%' }}\n exit={isMobile ? { y: '100%' } : { opacity: 0, scale: 0.95, x: '-50%', y: '-50%' }}\n transition={isMobile\n ? springs.smooth\n : { ...springs.smooth, opacity: tweens.fade }\n }\n className={cn(\n 'fixed z-modal grid w-full gap-ds-05 bg-surface-overlay p-ds-06',\n responsive !== false\n ? 'inset-0 md:inset-auto md:left-[50%] md:top-[50%] md:max-w-lg md:rounded-overlay-lg md:shadow-overlay'\n : 'left-[50%] top-[50%] max-w-lg rounded-overlay-lg shadow-overlay',\n className,\n )}\n >\n {children}\n </motion.div>\n </AlertDialogPrimitive.Content>\n </AlertDialogPortal>\n )}\n </AnimatePresence>\n )\n})\nAlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName\n\nconst AlertDialogHeader = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(\n ({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\n 'flex flex-col space-y-ds-02b text-center sm:text-left',\n className,\n )}\n {...props}\n />\n ),\n)\nAlertDialogHeader.displayName = 'AlertDialogHeader'\n\nconst AlertDialogFooter = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(\n ({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\n 'flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-ds-03',\n className,\n )}\n {...props}\n />\n ),\n)\nAlertDialogFooter.displayName = 'AlertDialogFooter'\n\nconst AlertDialogTitle = React.forwardRef<\n React.ElementRef<typeof AlertDialogPrimitive.Title>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Title>\n>(({ className, ...props }, ref) => (\n <AlertDialogPrimitive.Title\n ref={ref}\n className={cn(\n 'text-ds-lg font-semibold',\n className,\n )}\n {...props}\n />\n))\nAlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName\n\nconst AlertDialogDescription = React.forwardRef<\n React.ElementRef<typeof AlertDialogPrimitive.Description>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Description>\n>(({ className, ...props }, ref) => (\n <AlertDialogPrimitive.Description\n ref={ref}\n className={cn('text-ds-md text-surface-fg-muted', className)}\n {...props}\n />\n))\nAlertDialogDescription.displayName =\n AlertDialogPrimitive.Description.displayName\n\nconst AlertDialogAction = React.forwardRef<\n React.ElementRef<typeof AlertDialogPrimitive.Action>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Action>\n>(({ className, ...props }, ref) => (\n <AlertDialogPrimitive.Action\n ref={ref}\n className={cn(\n 'inline-flex h-ds-md items-center justify-center rounded-control px-ds-05 text-ds-md font-semibold transition-colors bg-accent-9 text-accent-fg hover:bg-accent-10 active:bg-accent-10 shadow-raised focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-action-disabled',\n className,\n )}\n {...props}\n />\n))\nAlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName\n\nconst AlertDialogCancel = React.forwardRef<\n React.ElementRef<typeof AlertDialogPrimitive.Cancel>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Cancel>\n>(({ className, ...props }, ref) => (\n <AlertDialogPrimitive.Cancel\n ref={ref}\n className={cn(\n 'inline-flex h-ds-md items-center justify-center rounded-control px-ds-05 text-ds-md font-semibold transition-colors bg-transparent text-surface-fg-muted border border-surface-border-strong hover:bg-surface-raised hover:text-surface-fg focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-action-disabled',\n className,\n )}\n {...props}\n />\n))\nAlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName\n\nexport type { AlertDialogContentProps }\nexport type AlertDialogActionProps = React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Action>\nexport type AlertDialogCancelProps = React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Cancel>\n\nexport {\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogOverlay,\n AlertDialogPortal,\n AlertDialogTitle,\n AlertDialogTrigger,\n}\n"],"mappings":"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"}
|
package/dist/ui/autocomplete.js
CHANGED
|
@@ -109,7 +109,7 @@ var g = {
|
|
|
109
109
|
exit: "hidden",
|
|
110
110
|
variants: g,
|
|
111
111
|
style: H,
|
|
112
|
-
className: c("z-popover overflow-auto rounded-overlay
|
|
112
|
+
className: c("z-popover overflow-auto rounded-overlay bg-surface-overlay shadow-raised-hover"),
|
|
113
113
|
children: G.length === 0 ? /* @__PURE__ */ d(h.li, {
|
|
114
114
|
initial: { opacity: 0 },
|
|
115
115
|
animate: { opacity: 1 },
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"autocomplete.js","names":[],"sources":["../../src/ui/autocomplete.tsx"],"sourcesContent":["'use client'\n\nimport { autoUpdate,flip, offset, shift, size, useFloating } from '@floating-ui/react-dom'\nimport { AnimatePresence,motion } from 'framer-motion'\nimport * as React from 'react'\nimport { createPortal } from 'react-dom'\n\nimport { useFormField } from './form'\nimport { springs, tweens } from './lib/motion'\nimport { cn } from './lib/utils'\n\nconst listVariants = {\n hidden: {},\n visible: { transition: { staggerChildren: 0.03 } },\n}\n\nconst itemVariants = {\n hidden: { opacity: 0, y: 4 },\n visible: { opacity: 1, y: 0, transition: springs.snappy },\n}\n\ntype AutocompleteOption = {\n label: string\n value: string\n}\n\n/**\n * Props for Autocomplete — a free-text input with a live-filtered dropdown list, keyboard\n * navigation, and ARIA combobox semantics. Suitable for \"type to search\" fields where the\n * full list is known ahead of time (client-side filtering only).\n *\n * **Key distinction from Combobox:** Autocomplete allows free-text input (no forced selection),\n * while `<Combobox>` enforces selection from the list. Use Autocomplete for search-as-you-type\n * with suggestions; use Combobox for structured single or multi-select dropdowns.\n *\n * **`value`:** A full `AutocompleteOption` object (or null), not just the string value.\n * The input's text is synced to `value.label` on mount.\n *\n * @example\n * // City search autocomplete:\n * <Autocomplete\n * options={[{ value: 'mumbai', label: 'Mumbai' }, { value: 'delhi', label: 'Delhi' }]}\n * value={selectedCity}\n * onValueChange={(opt) => setSelectedCity(opt)}\n * placeholder=\"Search cities...\"\n * />\n *\n * @example\n * // Employee name lookup with custom empty text:\n * <Autocomplete\n * options={employees.map(e => ({ value: e.id, label: e.fullName }))}\n * onValueChange={(opt) => setAssignee(opt.value)}\n * emptyText=\"No employees found\"\n * placeholder=\"Search employees...\"\n * />\n * // These are just a few ways — feel free to combine props creatively!\n */\ntype AutocompleteProps = React.HTMLAttributes<HTMLDivElement> & {\n options: AutocompleteOption[]\n value?: AutocompleteOption | null\n onValueChange?: (option: AutocompleteOption) => void\n placeholder?: string\n emptyText?: string\n disabled?: boolean\n className?: string\n id?: string\n}\n\nconst Autocomplete = React.forwardRef<HTMLInputElement, AutocompleteProps>(\n (\n {\n options,\n value,\n onValueChange,\n placeholder,\n emptyText = 'No options',\n disabled,\n className,\n id: externalId,\n ...props\n },\n ref,\n ) => {\n const internalId = React.useId()\n const baseId = externalId || internalId\n const listboxId = `${baseId}-listbox`\n const optionIdPrefix = `${baseId}-option`\n\n const [query, setQuery] = React.useState(value?.label ?? '')\n const [isOpen, setIsOpen] = React.useState(false)\n const [highlightedIndex, setHighlightedIndex] = React.useState(-1)\n const internalRef = React.useRef<HTMLInputElement>(null)\n const listRef = React.useRef<HTMLUListElement>(null)\n const containerRef = React.useRef<HTMLDivElement>(null)\n const floatingRef = React.useRef<HTMLUListElement>(null)\n\n // Floating UI positioning\n const { refs, floatingStyles } = useFloating({\n open: isOpen,\n placement: 'bottom-start',\n whileElementsMounted: autoUpdate,\n middleware: [\n offset(4),\n flip(),\n shift(),\n size({\n apply({ availableHeight, rects, elements }) {\n Object.assign(elements.floating.style, {\n maxHeight: `${Math.min(availableHeight, 240)}px`,\n width: `${rects.reference.width}px`,\n })\n },\n }),\n ],\n })\n\n // Compose external + internal ref + floating reference ref for input\n const composedRef = React.useCallback(\n (node: HTMLInputElement | null) => {\n (internalRef as React.MutableRefObject<HTMLInputElement | null>).current = node\n refs.setReference(node)\n if (typeof ref === 'function') ref(node)\n else if (ref) (ref as React.MutableRefObject<HTMLInputElement | null>).current = node\n },\n [ref, refs],\n )\n\n // Compose floating ref + listRef\n const composedFloatingRef = React.useCallback(\n (node: HTMLUListElement | null) => {\n (listRef as React.MutableRefObject<HTMLUListElement | null>).current = node\n ;(floatingRef as React.MutableRefObject<HTMLUListElement | null>).current = node\n refs.setFloating(node)\n },\n [refs],\n )\n\n // Sync query when value changes externally\n React.useEffect(() => {\n setQuery(value?.label ?? '')\n }, [value])\n\n // Cleanup blur timeout on unmount\n React.useEffect(() => {\n return () => {\n // Option selected — close and blur handled by relatedTarget check\n }\n }, [])\n\n const filtered = React.useMemo(\n () =>\n query\n ? options.filter((o) => o.label.toLowerCase().includes(query.toLowerCase()))\n : options,\n [options, query],\n )\n\n const handleSelect = React.useCallback(\n (option: AutocompleteOption) => {\n setQuery(option.label)\n setIsOpen(false)\n setHighlightedIndex(-1)\n onValueChange?.(option)\n },\n [onValueChange],\n )\n\n const handleKeyDown = React.useCallback(\n (e: React.KeyboardEvent) => {\n if (!isOpen) {\n if (e.key === 'ArrowDown' || e.key === 'Enter') setIsOpen(true)\n return\n }\n switch (e.key) {\n case 'ArrowDown':\n e.preventDefault()\n setHighlightedIndex((i) => Math.min(i + 1, filtered.length - 1))\n break\n case 'ArrowUp':\n e.preventDefault()\n setHighlightedIndex((i) => Math.max(i - 1, 0))\n break\n case 'Enter':\n e.preventDefault()\n if (highlightedIndex >= 0 && filtered[highlightedIndex]) {\n handleSelect(filtered[highlightedIndex])\n }\n break\n case 'Escape':\n setIsOpen(false)\n setHighlightedIndex(-1)\n break\n }\n },\n [isOpen, filtered, highlightedIndex, handleSelect],\n )\n\n const fieldCtx = useFormField()\n const isError = fieldCtx.state === 'error'\n const ariaDescribedBy = fieldCtx.helperTextId\n const ariaRequired = fieldCtx.required\n\n const highlightedOptionId =\n highlightedIndex >= 0 ? `${optionIdPrefix}-${highlightedIndex}` : undefined\n\n return (\n <div ref={containerRef} className={cn('relative', className)} {...props}>\n <input\n ref={composedRef}\n type=\"text\"\n role=\"combobox\"\n aria-expanded={isOpen}\n aria-autocomplete=\"list\"\n aria-controls={isOpen ? listboxId : undefined}\n aria-activedescendant={highlightedOptionId}\n aria-invalid={isError || undefined}\n aria-describedby={ariaDescribedBy}\n aria-required={ariaRequired || undefined}\n value={query}\n placeholder={placeholder}\n disabled={disabled}\n className={cn(\n 'flex h-ds-md w-full rounded-control border border-surface-border-strong bg-surface-raised-hover px-ds-04 py-ds-03 font-sans text-ds-md text-surface-fg placeholder:text-surface-fg-subtle',\n 'outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 focus-visible:ring-offset-[var(--border-focus-offset)]',\n 'transition-colors duration-fast-01',\n disabled && 'opacity-action-disabled cursor-not-allowed',\n )}\n onChange={(e) => {\n setQuery(e.target.value)\n setIsOpen(true)\n setHighlightedIndex(-1)\n }}\n onFocus={() => setIsOpen(true)}\n onBlur={(e) => {\n // Close only if focus moved outside both the container and the portal dropdown\n const target = e.relatedTarget as Node | null\n if (\n !containerRef.current?.contains(target) &&\n !floatingRef.current?.contains(target)\n ) {\n setIsOpen(false)\n }\n }}\n onKeyDown={handleKeyDown}\n />\n {typeof document !== 'undefined' &&\n createPortal(\n <AnimatePresence>\n {isOpen && (\n <motion.ul\n id={listboxId}\n ref={composedFloatingRef}\n role=\"listbox\"\n initial=\"hidden\"\n animate=\"visible\"\n exit=\"hidden\"\n variants={listVariants}\n style={floatingStyles}\n className={cn(\n 'z-popover overflow-auto rounded-overlay border border-surface-border-strong bg-surface-overlay shadow-raised-hover',\n )}\n >\n {filtered.length === 0 ? (\n <motion.li\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n transition={tweens.fade}\n className=\"px-ds-04 py-ds-03 text-ds-md text-surface-fg-muted\"\n >\n {emptyText}\n </motion.li>\n ) : (\n filtered.map((option, index) => (\n <motion.li\n key={option.value}\n id={`${optionIdPrefix}-${index}`}\n role=\"option\"\n aria-selected={highlightedIndex === index}\n variants={itemVariants}\n className={cn(\n 'cursor-pointer px-ds-04 py-ds-03 text-ds-md text-surface-fg transition-colors duration-fast-01',\n highlightedIndex === index && 'bg-accent-3',\n value?.value === option.value && 'font-semibold',\n )}\n onMouseDown={(e) => e.preventDefault()}\n onClick={() => handleSelect(option)}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n handleSelect(option)\n }\n }}\n onMouseEnter={() => setHighlightedIndex(index)}\n >\n {option.label}\n </motion.li>\n ))\n )}\n </motion.ul>\n )}\n </AnimatePresence>,\n document.body,\n )}\n </div>\n )\n },\n)\nAutocomplete.displayName = 'Autocomplete'\n\nexport { Autocomplete, type AutocompleteOption,type AutocompleteProps }\n"],"mappings":";;;;;;;;;;AAWA,IAAM,IAAe;CACnB,QAAQ,EAAE;CACV,SAAS,EAAE,YAAY,EAAE,iBAAiB,KAAM,EAAE;CACnD,EAEK,IAAe;CACnB,QAAQ;EAAE,SAAS;EAAG,GAAG;EAAG;CAC5B,SAAS;EAAE,SAAS;EAAG,GAAG;EAAG,YAAY,EAAQ;EAAQ;CAC1D,EAiDK,IAAe,EAAM,YAEvB,EACE,YACA,UACA,kBACA,gBACA,eAAY,cACZ,aACA,cACA,IAAI,GACJ,GAAG,KAEL,MACG;CACH,IAAM,IAAa,EAAM,OAAO,EAC1B,IAAS,KAAc,GACvB,IAAY,GAAG,EAAO,WACtB,IAAiB,GAAG,EAAO,UAE3B,CAAC,GAAO,KAAY,EAAM,SAAS,GAAO,SAAS,GAAG,EACtD,CAAC,GAAQ,KAAa,EAAM,SAAS,GAAM,EAC3C,CAAC,GAAkB,KAAuB,EAAM,SAAS,GAAG,EAC5D,IAAc,EAAM,OAAyB,KAAK,EAClD,IAAU,EAAM,OAAyB,KAAK,EAC9C,IAAe,EAAM,OAAuB,KAAK,EACjD,IAAc,EAAM,OAAyB,KAAK,EAGlD,EAAE,SAAM,sBAAmB,EAAY;EAC3C,MAAM;EACN,WAAW;EACX,sBAAsB;EACtB,YAAY;GACV,EAAO,EAAE;GACT,GAAM;GACN,GAAO;GACP,EAAK,EACH,MAAM,EAAE,oBAAiB,UAAO,eAAY;AAC1C,WAAO,OAAO,EAAS,SAAS,OAAO;KACrC,WAAW,GAAG,KAAK,IAAI,GAAiB,IAAI,CAAC;KAC7C,OAAO,GAAG,EAAM,UAAU,MAAM;KACjC,CAAC;MAEL,CAAC;GACH;EACF,CAAC,EAGI,IAAc,EAAM,aACvB,MAAkC;AAGjC,EAFC,EAAgE,UAAU,GAC3E,EAAK,aAAa,EAAK,EACnB,OAAO,KAAQ,aAAY,EAAI,EAAK,GAC/B,MAAM,EAAwD,UAAU;IAEnF,CAAC,GAAK,EAAK,CACZ,EAGK,IAAsB,EAAM,aAC/B,MAAkC;AAGjC,EAFC,EAA4D,UAAU,GACrE,EAAgE,UAAU,GAC5E,EAAK,YAAY,EAAK;IAExB,CAAC,EAAK,CACP;AAQD,CALA,EAAM,gBAAgB;AACpB,IAAS,GAAO,SAAS,GAAG;IAC3B,CAAC,EAAM,CAAC,EAGX,EAAM,sBACS,IAGZ,EAAE,CAAC;CAEN,IAAM,IAAW,EAAM,cAEnB,IACI,EAAQ,QAAQ,MAAM,EAAE,MAAM,aAAa,CAAC,SAAS,EAAM,aAAa,CAAC,CAAC,GAC1E,GACN,CAAC,GAAS,EAAM,CACjB,EAEK,IAAe,EAAM,aACxB,MAA+B;AAI9B,EAHA,EAAS,EAAO,MAAM,EACtB,EAAU,GAAM,EAChB,EAAoB,GAAG,EACvB,IAAgB,EAAO;IAEzB,CAAC,EAAc,CAChB,EAEK,IAAgB,EAAM,aACzB,MAA2B;AAC1B,MAAI,CAAC,GAAQ;AACX,IAAI,EAAE,QAAQ,eAAe,EAAE,QAAQ,YAAS,EAAU,GAAK;AAC/D;;AAEF,UAAQ,EAAE,KAAV;GACE,KAAK;AAEH,IADA,EAAE,gBAAgB,EAClB,GAAqB,MAAM,KAAK,IAAI,IAAI,GAAG,EAAS,SAAS,EAAE,CAAC;AAChE;GACF,KAAK;AAEH,IADA,EAAE,gBAAgB,EAClB,GAAqB,MAAM,KAAK,IAAI,IAAI,GAAG,EAAE,CAAC;AAC9C;GACF,KAAK;AAEH,IADA,EAAE,gBAAgB,EACd,KAAoB,KAAK,EAAS,MACpC,EAAa,EAAS,GAAkB;AAE1C;GACF,KAAK;AAEH,IADA,EAAU,GAAM,EAChB,EAAoB,GAAG;AACvB;;IAGN;EAAC;EAAQ;EAAU;EAAkB;EAAa,CACnD,EAEK,IAAW,GAAc,EACzB,IAAU,EAAS,UAAU,SAC7B,IAAkB,EAAS,cAC3B,IAAe,EAAS,UAExB,IACJ,KAAoB,IAAI,GAAG,EAAe,GAAG,MAAqB,KAAA;AAEpE,QACE,kBAAC,OAAD;EAAK,KAAK;EAAc,WAAW,EAAG,YAAY,EAAU;EAAE,GAAI;YAAlE,CACE,kBAAC,SAAD;GACE,KAAK;GACL,MAAK;GACL,MAAK;GACL,iBAAe;GACf,qBAAkB;GAClB,iBAAe,IAAS,IAAY,KAAA;GACpC,yBAAuB;GACvB,gBAAc,KAAW,KAAA;GACzB,oBAAkB;GAClB,iBAAe,KAAgB,KAAA;GAC/B,OAAO;GACM;GACH;GACV,WAAW,EACT,6LACA,0HACA,sCACA,KAAY,6CACb;GACD,WAAW,MAAM;AAGf,IAFA,EAAS,EAAE,OAAO,MAAM,EACxB,EAAU,GAAK,EACf,EAAoB,GAAG;;GAEzB,eAAe,EAAU,GAAK;GAC9B,SAAS,MAAM;IAEb,IAAM,IAAS,EAAE;AACjB,IACE,CAAC,EAAa,SAAS,SAAS,EAAO,IACvC,CAAC,EAAY,SAAS,SAAS,EAAO,IAEtC,EAAU,GAAM;;GAGpB,WAAW;GACX,CAAA,EACD,OAAO,WAAa,OACnB,EACE,kBAAC,GAAD,EAAA,UACG,KACC,kBAAC,EAAO,IAAR;GACE,IAAI;GACJ,KAAK;GACL,MAAK;GACL,SAAQ;GACR,SAAQ;GACR,MAAK;GACL,UAAU;GACV,OAAO;GACP,WAAW,EACT,qHACD;aAEA,EAAS,WAAW,IACnB,kBAAC,EAAO,IAAR;IACE,SAAS,EAAE,SAAS,GAAG;IACvB,SAAS,EAAE,SAAS,GAAG;IACvB,YAAY,EAAO;IACnB,WAAU;cAET;IACS,CAAA,GAEZ,EAAS,KAAK,GAAQ,MACpB,kBAAC,EAAO,IAAR;IAEE,IAAI,GAAG,EAAe,GAAG;IACzB,MAAK;IACL,iBAAe,MAAqB;IACpC,UAAU;IACV,WAAW,EACT,kGACA,MAAqB,KAAS,eAC9B,GAAO,UAAU,EAAO,SAAS,gBAClC;IACD,cAAc,MAAM,EAAE,gBAAgB;IACtC,eAAe,EAAa,EAAO;IACnC,YAAY,MAAM;AAChB,MAAI,EAAE,QAAQ,WAAW,EAAE,QAAQ,SACjC,EAAE,gBAAgB,EAClB,EAAa,EAAO;;IAGxB,oBAAoB,EAAoB,EAAM;cAE7C,EAAO;IACE,EArBL,EAAO,MAqBF,CACZ;GAEM,CAAA,EAEE,CAAA,EAClB,SAAS,KACV,CACC;;EAGX;AACD,EAAa,cAAc"}
|
|
1
|
+
{"version":3,"file":"autocomplete.js","names":[],"sources":["../../src/ui/autocomplete.tsx"],"sourcesContent":["'use client'\n\nimport { autoUpdate,flip, offset, shift, size, useFloating } from '@floating-ui/react-dom'\nimport { AnimatePresence,motion } from 'framer-motion'\nimport * as React from 'react'\nimport { createPortal } from 'react-dom'\n\nimport { useFormField } from './form'\nimport { springs, tweens } from './lib/motion'\nimport { cn } from './lib/utils'\n\nconst listVariants = {\n hidden: {},\n visible: { transition: { staggerChildren: 0.03 } },\n}\n\nconst itemVariants = {\n hidden: { opacity: 0, y: 4 },\n visible: { opacity: 1, y: 0, transition: springs.snappy },\n}\n\ntype AutocompleteOption = {\n label: string\n value: string\n}\n\n/**\n * Props for Autocomplete — a free-text input with a live-filtered dropdown list, keyboard\n * navigation, and ARIA combobox semantics. Suitable for \"type to search\" fields where the\n * full list is known ahead of time (client-side filtering only).\n *\n * **Key distinction from Combobox:** Autocomplete allows free-text input (no forced selection),\n * while `<Combobox>` enforces selection from the list. Use Autocomplete for search-as-you-type\n * with suggestions; use Combobox for structured single or multi-select dropdowns.\n *\n * **`value`:** A full `AutocompleteOption` object (or null), not just the string value.\n * The input's text is synced to `value.label` on mount.\n *\n * @example\n * // City search autocomplete:\n * <Autocomplete\n * options={[{ value: 'mumbai', label: 'Mumbai' }, { value: 'delhi', label: 'Delhi' }]}\n * value={selectedCity}\n * onValueChange={(opt) => setSelectedCity(opt)}\n * placeholder=\"Search cities...\"\n * />\n *\n * @example\n * // Employee name lookup with custom empty text:\n * <Autocomplete\n * options={employees.map(e => ({ value: e.id, label: e.fullName }))}\n * onValueChange={(opt) => setAssignee(opt.value)}\n * emptyText=\"No employees found\"\n * placeholder=\"Search employees...\"\n * />\n * // These are just a few ways — feel free to combine props creatively!\n */\ntype AutocompleteProps = React.HTMLAttributes<HTMLDivElement> & {\n options: AutocompleteOption[]\n value?: AutocompleteOption | null\n onValueChange?: (option: AutocompleteOption) => void\n placeholder?: string\n emptyText?: string\n disabled?: boolean\n className?: string\n id?: string\n}\n\nconst Autocomplete = React.forwardRef<HTMLInputElement, AutocompleteProps>(\n (\n {\n options,\n value,\n onValueChange,\n placeholder,\n emptyText = 'No options',\n disabled,\n className,\n id: externalId,\n ...props\n },\n ref,\n ) => {\n const internalId = React.useId()\n const baseId = externalId || internalId\n const listboxId = `${baseId}-listbox`\n const optionIdPrefix = `${baseId}-option`\n\n const [query, setQuery] = React.useState(value?.label ?? '')\n const [isOpen, setIsOpen] = React.useState(false)\n const [highlightedIndex, setHighlightedIndex] = React.useState(-1)\n const internalRef = React.useRef<HTMLInputElement>(null)\n const listRef = React.useRef<HTMLUListElement>(null)\n const containerRef = React.useRef<HTMLDivElement>(null)\n const floatingRef = React.useRef<HTMLUListElement>(null)\n\n // Floating UI positioning\n const { refs, floatingStyles } = useFloating({\n open: isOpen,\n placement: 'bottom-start',\n whileElementsMounted: autoUpdate,\n middleware: [\n offset(4),\n flip(),\n shift(),\n size({\n apply({ availableHeight, rects, elements }) {\n Object.assign(elements.floating.style, {\n maxHeight: `${Math.min(availableHeight, 240)}px`,\n width: `${rects.reference.width}px`,\n })\n },\n }),\n ],\n })\n\n // Compose external + internal ref + floating reference ref for input\n const composedRef = React.useCallback(\n (node: HTMLInputElement | null) => {\n (internalRef as React.MutableRefObject<HTMLInputElement | null>).current = node\n refs.setReference(node)\n if (typeof ref === 'function') ref(node)\n else if (ref) (ref as React.MutableRefObject<HTMLInputElement | null>).current = node\n },\n [ref, refs],\n )\n\n // Compose floating ref + listRef\n const composedFloatingRef = React.useCallback(\n (node: HTMLUListElement | null) => {\n (listRef as React.MutableRefObject<HTMLUListElement | null>).current = node\n ;(floatingRef as React.MutableRefObject<HTMLUListElement | null>).current = node\n refs.setFloating(node)\n },\n [refs],\n )\n\n // Sync query when value changes externally\n React.useEffect(() => {\n setQuery(value?.label ?? '')\n }, [value])\n\n // Cleanup blur timeout on unmount\n React.useEffect(() => {\n return () => {\n // Option selected — close and blur handled by relatedTarget check\n }\n }, [])\n\n const filtered = React.useMemo(\n () =>\n query\n ? options.filter((o) => o.label.toLowerCase().includes(query.toLowerCase()))\n : options,\n [options, query],\n )\n\n const handleSelect = React.useCallback(\n (option: AutocompleteOption) => {\n setQuery(option.label)\n setIsOpen(false)\n setHighlightedIndex(-1)\n onValueChange?.(option)\n },\n [onValueChange],\n )\n\n const handleKeyDown = React.useCallback(\n (e: React.KeyboardEvent) => {\n if (!isOpen) {\n if (e.key === 'ArrowDown' || e.key === 'Enter') setIsOpen(true)\n return\n }\n switch (e.key) {\n case 'ArrowDown':\n e.preventDefault()\n setHighlightedIndex((i) => Math.min(i + 1, filtered.length - 1))\n break\n case 'ArrowUp':\n e.preventDefault()\n setHighlightedIndex((i) => Math.max(i - 1, 0))\n break\n case 'Enter':\n e.preventDefault()\n if (highlightedIndex >= 0 && filtered[highlightedIndex]) {\n handleSelect(filtered[highlightedIndex])\n }\n break\n case 'Escape':\n setIsOpen(false)\n setHighlightedIndex(-1)\n break\n }\n },\n [isOpen, filtered, highlightedIndex, handleSelect],\n )\n\n const fieldCtx = useFormField()\n const isError = fieldCtx.state === 'error'\n const ariaDescribedBy = fieldCtx.helperTextId\n const ariaRequired = fieldCtx.required\n\n const highlightedOptionId =\n highlightedIndex >= 0 ? `${optionIdPrefix}-${highlightedIndex}` : undefined\n\n return (\n <div ref={containerRef} className={cn('relative', className)} {...props}>\n <input\n ref={composedRef}\n type=\"text\"\n role=\"combobox\"\n aria-expanded={isOpen}\n aria-autocomplete=\"list\"\n aria-controls={isOpen ? listboxId : undefined}\n aria-activedescendant={highlightedOptionId}\n aria-invalid={isError || undefined}\n aria-describedby={ariaDescribedBy}\n aria-required={ariaRequired || undefined}\n value={query}\n placeholder={placeholder}\n disabled={disabled}\n className={cn(\n 'flex h-ds-md w-full rounded-control border border-surface-border-strong bg-surface-raised-hover px-ds-04 py-ds-03 font-sans text-ds-md text-surface-fg placeholder:text-surface-fg-subtle',\n 'outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 focus-visible:ring-offset-[var(--border-focus-offset)]',\n 'transition-colors duration-fast-01',\n disabled && 'opacity-action-disabled cursor-not-allowed',\n )}\n onChange={(e) => {\n setQuery(e.target.value)\n setIsOpen(true)\n setHighlightedIndex(-1)\n }}\n onFocus={() => setIsOpen(true)}\n onBlur={(e) => {\n // Close only if focus moved outside both the container and the portal dropdown\n const target = e.relatedTarget as Node | null\n if (\n !containerRef.current?.contains(target) &&\n !floatingRef.current?.contains(target)\n ) {\n setIsOpen(false)\n }\n }}\n onKeyDown={handleKeyDown}\n />\n {typeof document !== 'undefined' &&\n createPortal(\n <AnimatePresence>\n {isOpen && (\n <motion.ul\n id={listboxId}\n ref={composedFloatingRef}\n role=\"listbox\"\n initial=\"hidden\"\n animate=\"visible\"\n exit=\"hidden\"\n variants={listVariants}\n style={floatingStyles}\n className={cn(\n 'z-popover overflow-auto rounded-overlay bg-surface-overlay shadow-raised-hover',\n )}\n >\n {filtered.length === 0 ? (\n <motion.li\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n transition={tweens.fade}\n className=\"px-ds-04 py-ds-03 text-ds-md text-surface-fg-muted\"\n >\n {emptyText}\n </motion.li>\n ) : (\n filtered.map((option, index) => (\n <motion.li\n key={option.value}\n id={`${optionIdPrefix}-${index}`}\n role=\"option\"\n aria-selected={highlightedIndex === index}\n variants={itemVariants}\n className={cn(\n 'cursor-pointer px-ds-04 py-ds-03 text-ds-md text-surface-fg transition-colors duration-fast-01',\n highlightedIndex === index && 'bg-accent-3',\n value?.value === option.value && 'font-semibold',\n )}\n onMouseDown={(e) => e.preventDefault()}\n onClick={() => handleSelect(option)}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n handleSelect(option)\n }\n }}\n onMouseEnter={() => setHighlightedIndex(index)}\n >\n {option.label}\n </motion.li>\n ))\n )}\n </motion.ul>\n )}\n </AnimatePresence>,\n document.body,\n )}\n </div>\n )\n },\n)\nAutocomplete.displayName = 'Autocomplete'\n\nexport { Autocomplete, type AutocompleteOption,type AutocompleteProps }\n"],"mappings":"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"}
|
package/dist/ui/card.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"card.d.ts","sourceRoot":"","sources":["../../src/ui/card.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAEjE,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAK9B,KAAK,QAAQ,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;AAIlC,QAAA,MAAM,YAAY;;;;
|
|
1
|
+
{"version":3,"file":"card.d.ts","sourceRoot":"","sources":["../../src/ui/card.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAEjE,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAK9B,KAAK,QAAQ,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;AAIlC,QAAA,MAAM,YAAY;;;;8EA+BjB,CAAA;AA6DD,MAAM,WAAW,SACf,SAAQ,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,OAAO,CAAC,EACzD,YAAY,CAAC,OAAO,YAAY,CAAC;IACnC,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,0CAA0C;IAC1C,MAAM,CAAC,EAAE,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,CAAA;IAC5C,uHAAuH;IACvH,WAAW,CAAC,EAAE,SAAS,GAAG,WAAW,GAAG,OAAO,GAAG,SAAS,GAAG,SAAS,GAAG,MAAM,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,CAAA;IAChG,qDAAqD;IACrD,WAAW,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;CAC5B;AAED,YAAY,EAAE,QAAQ,EAAE,CAAA;AAwBxB,QAAA,MAAM,IAAI,kFAiDT,CAAA;AASD,QAAA,MAAM,UAAU,6GAYd,CAAA;AAGF,QAAA,MAAM,SAAS,6GASb,CAAA;AAGF,QAAA,MAAM,eAAe,6GASnB,CAAA;AASF,QAAA,MAAM,WAAW,6GAQf,CAAA;AASF,QAAA,MAAM,UAAU,6GAYd,CAAA;AAGF,OAAO,EAAE,IAAI,EAAE,WAAW,EAAC,eAAe,EAAE,UAAU,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,CAAA"}
|
package/dist/ui/card.js
CHANGED
|
@@ -9,8 +9,8 @@ import { motion as c } from "framer-motion";
|
|
|
9
9
|
var l = a.createContext("md"), u = r("rounded-surface text-surface-fg transition-shadow duration-fast-02 ease-productive-standard", {
|
|
10
10
|
variants: {
|
|
11
11
|
variant: {
|
|
12
|
-
default: "bg-surface-raised border border-
|
|
13
|
-
elevated: "bg-surface-raised border border-
|
|
12
|
+
default: "bg-surface-raised border border-transparent shadow-raised",
|
|
13
|
+
elevated: "bg-surface-raised border border-transparent shadow-raised-hover",
|
|
14
14
|
outline: "bg-transparent border border-surface-border-strong shadow-none",
|
|
15
15
|
flat: "bg-surface-raised border-none shadow-none"
|
|
16
16
|
},
|
|
@@ -83,7 +83,7 @@ var g = a.forwardRef(({ className: r, variant: a, color: d, size: f, interactive
|
|
|
83
83
|
variant: a,
|
|
84
84
|
color: d,
|
|
85
85
|
size: f
|
|
86
|
-
}), g && "relative overflow-hidden", p && "hover:shadow-raised-hover
|
|
86
|
+
}), g && "relative overflow-hidden", p && "hover:shadow-raised-hover cursor-pointer transition-shadow duration-fast-02 ease-productive-standard", r), w = g ? /* @__PURE__ */ o(c.span, {
|
|
87
87
|
"aria-hidden": "true",
|
|
88
88
|
initial: { opacity: 0 },
|
|
89
89
|
animate: { opacity: 1 },
|
package/dist/ui/card.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"card.js","names":[],"sources":["../../src/ui/card.tsx"],"sourcesContent":["'use client'\n\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { motionProps,springs, tweens } from './lib/motion'\nimport { cn } from './lib/utils'\n\ntype CardSize = 'sm' | 'md' | 'lg'\n\nconst CardSizeContext = React.createContext<CardSize>('md')\n\nconst cardVariants = cva(\n 'rounded-surface text-surface-fg transition-shadow duration-fast-02 ease-productive-standard',\n {\n variants: {\n variant: {\n default: 'bg-surface-raised border border-surface-border shadow-raised',\n elevated: 'bg-surface-raised border border-surface-border shadow-raised-hover',\n outline: 'bg-transparent border border-surface-border-strong shadow-none',\n flat: 'bg-surface-raised border-none shadow-none',\n },\n color: {\n default: '',\n accent: 'border-accent-7',\n error: 'border-error-7',\n success: 'border-success-7',\n warning: 'border-warning-7',\n info: 'border-info-7',\n neutral: '',\n },\n size: {\n sm: '',\n md: '',\n lg: '',\n },\n },\n defaultVariants: { variant: 'default', color: 'default', size: 'md' },\n },\n)\n\n/**\n * Props for Card — a general-purpose content container with 4 elevation/style variants and\n * an optional interactive hover state.\n *\n * **Variants:** `default` (subtle border + shadow-raised) | `elevated` (stronger shadow-raised-hover) |\n * `outline` (2px solid border, no shadow) | `flat` (filled background, no shadow)\n *\n * **Composition:** Use sub-components `<CardHeader>`, `<CardTitle>`, `<CardDescription>`,\n * `<CardContent>`, and `<CardFooter>` for consistent internal spacing.\n *\n * **Interactive:** Pass `interactive` to enable hover shadow lift and pointer cursor —\n * useful for clickable cards in grids.\n *\n * @example\n * // Standard content card with header and body:\n * <Card>\n * <CardHeader>\n * <CardTitle>Project Alpha</CardTitle>\n * <CardDescription>Last updated 2 hours ago</CardDescription>\n * </CardHeader>\n * <CardContent>\n * <p>Sprint 4 is in progress with 12 open tasks.</p>\n * </CardContent>\n * </Card>\n *\n * @example\n * // Elevated card for a dashboard stat widget:\n * <Card variant=\"elevated\">\n * <CardContent>\n * <StatCard label=\"Revenue\" value=\"$12,400\" delta={{ value: \"+8%\", direction: \"up\" }} />\n * </CardContent>\n * </Card>\n *\n * @example\n * // Clickable card in a project grid (interactive hover effect):\n * <Card interactive onClick={() => router.push(`/projects/${id}`)}>\n * <CardHeader>\n * <CardTitle>{project.name}</CardTitle>\n * </CardHeader>\n * </Card>\n *\n * @example\n * // Flat card for a sidebar panel section (no shadow):\n * <Card variant=\"flat\" className=\"p-ds-05\">\n * <p className=\"text-surface-fg-muted text-ds-sm\">No recent activity</p>\n * </Card>\n * // These are just a few ways — feel free to combine props creatively!\n */\nconst accentColorMap: Record<string, string> = {\n default: 'var(--color-accent-9)',\n secondary: 'var(--color-secondary-9)',\n error: 'var(--color-error-9)',\n success: 'var(--color-success-9)',\n warning: 'var(--color-warning-9)',\n info: 'var(--color-info-9)',\n}\n\nexport interface CardProps\n extends Omit<React.HTMLAttributes<HTMLDivElement>, 'color'>,\n VariantProps<typeof cardVariants> {\n interactive?: boolean\n /** Position of the accent border strip */\n accent?: 'left' | 'top' | 'right' | 'bottom'\n /** Semantic color key or any CSS color string for the accent strip. Requires `accent` to be set. @default 'default' */\n accentColor?: 'default' | 'secondary' | 'error' | 'success' | 'warning' | 'info' | (string & {})\n /** Width of the accent strip in pixels @default 3 */\n accentWidth?: 2 | 3 | 4 | 6\n}\n\nexport type { CardSize }\n\nconst accentSizeClasses: Record<string, Record<number, string>> = {\n left: { 2: 'w-[2px]', 3: 'w-[3px]', 4: 'w-[4px]', 6: 'w-[6px]' },\n top: { 2: 'h-[2px]', 3: 'h-[3px]', 4: 'h-[4px]', 6: 'h-[6px]' },\n right: { 2: 'w-[2px]', 3: 'w-[3px]', 4: 'w-[4px]', 6: 'w-[6px]' },\n bottom: { 2: 'h-[2px]', 3: 'h-[3px]', 4: 'h-[4px]', 6: 'h-[6px]' },\n}\n\nconst accentPositionClasses: Record<string, string> = {\n left: 'left-0 top-0 bottom-0 rounded-l-surface',\n top: 'top-0 left-0 right-0 rounded-t-surface',\n right: 'right-0 top-0 bottom-0 rounded-r-surface',\n bottom: 'bottom-0 left-0 right-0 rounded-b-surface',\n}\n\nfunction getAccentPositionClasses(position: string, width: number): string {\n return `${accentPositionClasses[position] ?? ''} ${accentSizeClasses[position]?.[width] ?? ''}`\n}\n\nfunction resolveAccentColor(color: string): string {\n return accentColorMap[color] ?? color\n}\n\nconst Card = React.forwardRef<HTMLDivElement, CardProps>(\n ({ className, variant, color, size, interactive, accent, accentColor = 'default', accentWidth = 3, children, ...props }, ref) => {\n const resolvedSize: CardSize = size ?? 'md'\n const classes = cn(\n cardVariants({ variant, color, size }),\n accent && 'relative overflow-hidden',\n interactive && 'hover:shadow-raised-hover hover:border-surface-border-strong cursor-pointer transition-shadow duration-fast-02 ease-productive-standard',\n className,\n )\n\n const accentEl = accent ? (\n <motion.span\n aria-hidden=\"true\"\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n transition={tweens.fade}\n className={cn('absolute pointer-events-none bg-[var(--card-accent-bg)]', getAccentPositionClasses(accent, accentWidth))}\n style={{ '--card-accent-bg': resolveAccentColor(accentColor) } as React.CSSProperties}\n />\n ) : null\n\n const content = (\n <CardSizeContext.Provider value={resolvedSize}>\n {accentEl}\n {children}\n </CardSizeContext.Provider>\n )\n\n if (interactive) {\n return (\n <motion.div\n ref={ref}\n whileHover={{ y: -3 }}\n whileTap={{ scale: 0.98 }}\n transition={springs.snappy}\n className={classes}\n {...motionProps(props)}\n >\n {content}\n </motion.div>\n )\n }\n\n return (\n <div ref={ref} className={classes} {...props}>\n {content}\n </div>\n )\n },\n)\nCard.displayName = 'Card'\n\nconst headerSizeClasses: Record<CardSize, string> = {\n sm: 'p-ds-05',\n md: 'p-ds-06',\n lg: 'p-ds-07',\n}\n\nconst CardHeader = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => {\n const size = React.useContext(CardSizeContext)\n return (\n <div\n ref={ref}\n className={cn('flex flex-col space-y-ds-02b', headerSizeClasses[size], className)}\n {...props}\n />\n )\n})\nCardHeader.displayName = 'CardHeader'\n\nconst CardTitle = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn('font-sans font-semibold leading-ds-none tracking-normal text-surface-fg', className)}\n {...props}\n />\n))\nCardTitle.displayName = 'CardTitle'\n\nconst CardDescription = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn('text-ds-md text-surface-fg-muted', className)}\n {...props}\n />\n))\nCardDescription.displayName = 'CardDescription'\n\nconst contentSizeClasses: Record<CardSize, string> = {\n sm: 'p-ds-05 pt-0',\n md: 'p-ds-06 pt-0',\n lg: 'p-ds-07 pt-0',\n}\n\nconst CardContent = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => {\n const size = React.useContext(CardSizeContext)\n return (\n <div ref={ref} className={cn(contentSizeClasses[size], className)} {...props} />\n )\n})\nCardContent.displayName = 'CardContent'\n\nconst footerSizeClasses: Record<CardSize, string> = {\n sm: 'p-ds-05 pt-0',\n md: 'p-ds-06 pt-0',\n lg: 'p-ds-07 pt-0',\n}\n\nconst CardFooter = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => {\n const size = React.useContext(CardSizeContext)\n return (\n <div\n ref={ref}\n className={cn('flex items-center', footerSizeClasses[size], className)}\n {...props}\n />\n )\n})\nCardFooter.displayName = 'CardFooter'\n\nexport { Card, CardContent,CardDescription, CardFooter, CardHeader, CardTitle, cardVariants }\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"card.js","names":[],"sources":["../../src/ui/card.tsx"],"sourcesContent":["'use client'\n\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { motionProps,springs, tweens } from './lib/motion'\nimport { cn } from './lib/utils'\n\ntype CardSize = 'sm' | 'md' | 'lg'\n\nconst CardSizeContext = React.createContext<CardSize>('md')\n\nconst cardVariants = cva(\n 'rounded-surface text-surface-fg transition-shadow duration-fast-02 ease-productive-standard',\n {\n variants: {\n variant: {\n // Elevation-led: the shadow's own ring is the edge (make-kit rule #6 — no\n // border+shadow double-edge). border-transparent keeps the `color` prop able to\n // paint a deliberate colored edge without a grey one by default.\n default: 'bg-surface-raised border border-transparent shadow-raised',\n elevated: 'bg-surface-raised border border-transparent shadow-raised-hover',\n // Border-led: a visible edge, no shadow.\n outline: 'bg-transparent border border-surface-border-strong shadow-none',\n flat: 'bg-surface-raised border-none shadow-none',\n },\n color: {\n default: '',\n accent: 'border-accent-7',\n error: 'border-error-7',\n success: 'border-success-7',\n warning: 'border-warning-7',\n info: 'border-info-7',\n neutral: '',\n },\n size: {\n sm: '',\n md: '',\n lg: '',\n },\n },\n defaultVariants: { variant: 'default', color: 'default', size: 'md' },\n },\n)\n\n/**\n * Props for Card — a general-purpose content container with 4 elevation/style variants and\n * an optional interactive hover state.\n *\n * **Variants (elevation-led vs border-led — never both):** `default` (ring-in-shadow, no border) |\n * `elevated` (stronger shadow-raised-hover, no border) | `outline` (visible border, no shadow) |\n * `flat` (filled background, no edge). The shadow tokens carry their own 1px ring, so elevated\n * variants need no explicit border (make-kit rule #6).\n *\n * **Composition:** Use sub-components `<CardHeader>`, `<CardTitle>`, `<CardDescription>`,\n * `<CardContent>`, and `<CardFooter>` for consistent internal spacing.\n *\n * **Interactive:** Pass `interactive` to enable hover shadow lift and pointer cursor —\n * useful for clickable cards in grids.\n *\n * @example\n * // Standard content card with header and body:\n * <Card>\n * <CardHeader>\n * <CardTitle>Project Alpha</CardTitle>\n * <CardDescription>Last updated 2 hours ago</CardDescription>\n * </CardHeader>\n * <CardContent>\n * <p>Sprint 4 is in progress with 12 open tasks.</p>\n * </CardContent>\n * </Card>\n *\n * @example\n * // Elevated card for a dashboard stat widget:\n * <Card variant=\"elevated\">\n * <CardContent>\n * <StatCard label=\"Revenue\" value=\"$12,400\" delta={{ value: \"+8%\", direction: \"up\" }} />\n * </CardContent>\n * </Card>\n *\n * @example\n * // Clickable card in a project grid (interactive hover effect):\n * <Card interactive onClick={() => router.push(`/projects/${id}`)}>\n * <CardHeader>\n * <CardTitle>{project.name}</CardTitle>\n * </CardHeader>\n * </Card>\n *\n * @example\n * // Flat card for a sidebar panel section (no shadow):\n * <Card variant=\"flat\" className=\"p-ds-05\">\n * <p className=\"text-surface-fg-muted text-ds-sm\">No recent activity</p>\n * </Card>\n * // These are just a few ways — feel free to combine props creatively!\n */\nconst accentColorMap: Record<string, string> = {\n default: 'var(--color-accent-9)',\n secondary: 'var(--color-secondary-9)',\n error: 'var(--color-error-9)',\n success: 'var(--color-success-9)',\n warning: 'var(--color-warning-9)',\n info: 'var(--color-info-9)',\n}\n\nexport interface CardProps\n extends Omit<React.HTMLAttributes<HTMLDivElement>, 'color'>,\n VariantProps<typeof cardVariants> {\n interactive?: boolean\n /** Position of the accent border strip */\n accent?: 'left' | 'top' | 'right' | 'bottom'\n /** Semantic color key or any CSS color string for the accent strip. Requires `accent` to be set. @default 'default' */\n accentColor?: 'default' | 'secondary' | 'error' | 'success' | 'warning' | 'info' | (string & {})\n /** Width of the accent strip in pixels @default 3 */\n accentWidth?: 2 | 3 | 4 | 6\n}\n\nexport type { CardSize }\n\nconst accentSizeClasses: Record<string, Record<number, string>> = {\n left: { 2: 'w-[2px]', 3: 'w-[3px]', 4: 'w-[4px]', 6: 'w-[6px]' },\n top: { 2: 'h-[2px]', 3: 'h-[3px]', 4: 'h-[4px]', 6: 'h-[6px]' },\n right: { 2: 'w-[2px]', 3: 'w-[3px]', 4: 'w-[4px]', 6: 'w-[6px]' },\n bottom: { 2: 'h-[2px]', 3: 'h-[3px]', 4: 'h-[4px]', 6: 'h-[6px]' },\n}\n\nconst accentPositionClasses: Record<string, string> = {\n left: 'left-0 top-0 bottom-0 rounded-l-surface',\n top: 'top-0 left-0 right-0 rounded-t-surface',\n right: 'right-0 top-0 bottom-0 rounded-r-surface',\n bottom: 'bottom-0 left-0 right-0 rounded-b-surface',\n}\n\nfunction getAccentPositionClasses(position: string, width: number): string {\n return `${accentPositionClasses[position] ?? ''} ${accentSizeClasses[position]?.[width] ?? ''}`\n}\n\nfunction resolveAccentColor(color: string): string {\n return accentColorMap[color] ?? color\n}\n\nconst Card = React.forwardRef<HTMLDivElement, CardProps>(\n ({ className, variant, color, size, interactive, accent, accentColor = 'default', accentWidth = 3, children, ...props }, ref) => {\n const resolvedSize: CardSize = size ?? 'md'\n const classes = cn(\n cardVariants({ variant, color, size }),\n accent && 'relative overflow-hidden',\n interactive && 'hover:shadow-raised-hover cursor-pointer transition-shadow duration-fast-02 ease-productive-standard',\n className,\n )\n\n const accentEl = accent ? (\n <motion.span\n aria-hidden=\"true\"\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n transition={tweens.fade}\n className={cn('absolute pointer-events-none bg-[var(--card-accent-bg)]', getAccentPositionClasses(accent, accentWidth))}\n style={{ '--card-accent-bg': resolveAccentColor(accentColor) } as React.CSSProperties}\n />\n ) : null\n\n const content = (\n <CardSizeContext.Provider value={resolvedSize}>\n {accentEl}\n {children}\n </CardSizeContext.Provider>\n )\n\n if (interactive) {\n return (\n <motion.div\n ref={ref}\n whileHover={{ y: -3 }}\n whileTap={{ scale: 0.98 }}\n transition={springs.snappy}\n className={classes}\n {...motionProps(props)}\n >\n {content}\n </motion.div>\n )\n }\n\n return (\n <div ref={ref} className={classes} {...props}>\n {content}\n </div>\n )\n },\n)\nCard.displayName = 'Card'\n\nconst headerSizeClasses: Record<CardSize, string> = {\n sm: 'p-ds-05',\n md: 'p-ds-06',\n lg: 'p-ds-07',\n}\n\nconst CardHeader = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => {\n const size = React.useContext(CardSizeContext)\n return (\n <div\n ref={ref}\n className={cn('flex flex-col space-y-ds-02b', headerSizeClasses[size], className)}\n {...props}\n />\n )\n})\nCardHeader.displayName = 'CardHeader'\n\nconst CardTitle = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn('font-sans font-semibold leading-ds-none tracking-normal text-surface-fg', className)}\n {...props}\n />\n))\nCardTitle.displayName = 'CardTitle'\n\nconst CardDescription = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn('text-ds-md text-surface-fg-muted', className)}\n {...props}\n />\n))\nCardDescription.displayName = 'CardDescription'\n\nconst contentSizeClasses: Record<CardSize, string> = {\n sm: 'p-ds-05 pt-0',\n md: 'p-ds-06 pt-0',\n lg: 'p-ds-07 pt-0',\n}\n\nconst CardContent = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => {\n const size = React.useContext(CardSizeContext)\n return (\n <div ref={ref} className={cn(contentSizeClasses[size], className)} {...props} />\n )\n})\nCardContent.displayName = 'CardContent'\n\nconst footerSizeClasses: Record<CardSize, string> = {\n sm: 'p-ds-05 pt-0',\n md: 'p-ds-06 pt-0',\n lg: 'p-ds-07 pt-0',\n}\n\nconst CardFooter = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => {\n const size = React.useContext(CardSizeContext)\n return (\n <div\n ref={ref}\n className={cn('flex items-center', footerSizeClasses[size], className)}\n {...props}\n />\n )\n})\nCardFooter.displayName = 'CardFooter'\n\nexport { Card, CardContent,CardDescription, CardFooter, CardHeader, CardTitle, cardVariants }\n"],"mappings":"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"}
|
package/dist/ui/color-input.js
CHANGED
|
@@ -227,7 +227,7 @@ var y = s.forwardRef(({ value: y = "#000000", onChange: b, presets: x, disabled:
|
|
|
227
227
|
"aria-label": "Color picker",
|
|
228
228
|
align: T,
|
|
229
229
|
sideOffset: 8,
|
|
230
|
-
className: "w-[272px] rounded-overlay-lg
|
|
230
|
+
className: "w-[272px] rounded-overlay-lg bg-surface-overlay p-0 shadow-floating",
|
|
231
231
|
children: /* @__PURE__ */ l("div", {
|
|
232
232
|
className: "flex flex-col",
|
|
233
233
|
children: [
|