@devalok/shilp-sutra 0.52.0 → 0.54.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.
Files changed (123) hide show
  1. package/AGENTS.md +7 -1
  2. package/BREAKING.json +29 -0
  3. package/MIGRATION.md +61 -0
  4. package/dist/_chunks/motion-provider.js +7 -6
  5. package/dist/_chunks/motion-provider.js.map +1 -1
  6. package/dist/_chunks/success.js +53 -53
  7. package/dist/ai/command-bar.js +158 -158
  8. package/dist/ai/command-bar.js.map +1 -1
  9. package/dist/ai/conversation.js +5 -5
  10. package/dist/composed/avatar-group.d.ts +11 -9
  11. package/dist/composed/avatar-group.d.ts.map +1 -1
  12. package/dist/composed/avatar-group.js +108 -140
  13. package/dist/composed/avatar-group.js.map +1 -1
  14. package/dist/composed/bulk-action-bar.d.ts +19 -11
  15. package/dist/composed/bulk-action-bar.d.ts.map +1 -1
  16. package/dist/composed/bulk-action-bar.js +81 -110
  17. package/dist/composed/bulk-action-bar.js.map +1 -1
  18. package/dist/composed/command-palette.js +17 -17
  19. package/dist/composed/command-palette.js.map +1 -1
  20. package/dist/composed/error-boundary.d.ts +15 -3
  21. package/dist/composed/error-boundary.d.ts.map +1 -1
  22. package/dist/composed/error-boundary.js +43 -26
  23. package/dist/composed/error-boundary.js.map +1 -1
  24. package/dist/composed/loading-skeleton.d.ts +2 -0
  25. package/dist/composed/loading-skeleton.d.ts.map +1 -1
  26. package/dist/composed/loading-skeleton.js +79 -56
  27. package/dist/composed/loading-skeleton.js.map +1 -1
  28. package/dist/composed/master-detail.d.ts +21 -8
  29. package/dist/composed/master-detail.d.ts.map +1 -1
  30. package/dist/composed/master-detail.js +91 -77
  31. package/dist/composed/master-detail.js.map +1 -1
  32. package/dist/composed/page-skeletons.d.ts +6 -0
  33. package/dist/composed/page-skeletons.d.ts.map +1 -1
  34. package/dist/composed/page-skeletons.js +93 -71
  35. package/dist/composed/page-skeletons.js.map +1 -1
  36. package/dist/composed/priority-indicator.d.ts +15 -6
  37. package/dist/composed/priority-indicator.d.ts.map +1 -1
  38. package/dist/composed/priority-indicator.js +37 -88
  39. package/dist/composed/priority-indicator.js.map +1 -1
  40. package/dist/composed/schedule-view.d.ts +17 -2
  41. package/dist/composed/schedule-view.d.ts.map +1 -1
  42. package/dist/composed/schedule-view.js +163 -64
  43. package/dist/composed/schedule-view.js.map +1 -1
  44. package/dist/motion/motion-provider.d.ts.map +1 -1
  45. package/dist/shell/bottom-navbar.d.ts +32 -6
  46. package/dist/shell/bottom-navbar.d.ts.map +1 -1
  47. package/dist/shell/bottom-navbar.js +156 -129
  48. package/dist/shell/bottom-navbar.js.map +1 -1
  49. package/dist/shell/index.d.ts +5 -3
  50. package/dist/shell/index.d.ts.map +1 -1
  51. package/dist/shell/index.js +2 -3
  52. package/dist/shell/notification-preferences.d.ts.map +1 -1
  53. package/dist/shell/notification-preferences.js +2 -0
  54. package/dist/shell/notification-preferences.js.map +1 -1
  55. package/dist/tokens/primitives.css +6 -2
  56. package/dist/tokens/utilities.css +6 -0
  57. package/dist/ui/autocomplete.d.ts +34 -32
  58. package/dist/ui/autocomplete.d.ts.map +1 -1
  59. package/dist/ui/autocomplete.js +115 -110
  60. package/dist/ui/autocomplete.js.map +1 -1
  61. package/dist/ui/combobox.d.ts +1 -1
  62. package/dist/ui/combobox.d.ts.map +1 -1
  63. package/dist/ui/combobox.js +133 -128
  64. package/dist/ui/combobox.js.map +1 -1
  65. package/dist/ui/file-upload.d.ts.map +1 -1
  66. package/dist/ui/file-upload.js +124 -138
  67. package/dist/ui/file-upload.js.map +1 -1
  68. package/dist/ui/form.d.ts +7 -0
  69. package/dist/ui/form.d.ts.map +1 -1
  70. package/dist/ui/form.js +4 -2
  71. package/dist/ui/form.js.map +1 -1
  72. package/dist/ui/icon-button.d.ts +2 -1
  73. package/dist/ui/icon-button.d.ts.map +1 -1
  74. package/dist/ui/icon-button.js +1 -1
  75. package/dist/ui/icon-button.js.map +1 -1
  76. package/dist/ui/index.js +30 -30
  77. package/dist/ui/label.d.ts.map +1 -1
  78. package/dist/ui/label.js +7 -6
  79. package/dist/ui/label.js.map +1 -1
  80. package/dist/ui/search-input.js +4 -4
  81. package/dist/ui/sidebar.js +7 -7
  82. package/dist/ui/spinner.d.ts.map +1 -1
  83. package/dist/ui/spinner.js +50 -44
  84. package/dist/ui/spinner.js.map +1 -1
  85. package/dist/ui/switch.d.ts.map +1 -1
  86. package/dist/ui/switch.js +24 -24
  87. package/dist/ui/switch.js.map +1 -1
  88. package/dist/ui/table.js +1 -1
  89. package/dist/ui/table.js.map +1 -1
  90. package/docs/components/composed/bulk-action-bar.md +9 -3
  91. package/docs/components/composed/error-boundary.md +18 -2
  92. package/docs/components/composed/master-detail.md +12 -2
  93. package/docs/components/composed/page-skeletons.md +2 -2
  94. package/docs/components/composed/priority-indicator.md +22 -11
  95. package/docs/components/composed/rich-chat-input.md +18 -6
  96. package/docs/components/composed/schedule-view.md +20 -5
  97. package/docs/components/composed/simple-tooltip.md +1 -1
  98. package/docs/components/shell/app-command-palette.md +2 -1
  99. package/docs/components/shell/bottom-navbar.md +28 -9
  100. package/docs/components/shell/command-registry.md +2 -2
  101. package/docs/components/shell/link-context.md +2 -2
  102. package/docs/components/shell/top-bar.md +1 -1
  103. package/docs/components/ui/autocomplete.md +26 -10
  104. package/docs/components/ui/search-input.md +2 -2
  105. package/docs/components/ui/slider.md +2 -2
  106. package/docs/components/ui/split-button.md +3 -3
  107. package/llms.txt +2 -2
  108. package/make-kit/Guidelines.md +1 -1
  109. package/make-kit/components/overview.md +2 -2
  110. package/make-kit/foundations/surfaces.md +1 -1
  111. package/mcp-manifest.json +581 -172
  112. package/package.json +1 -6
  113. package/skill/SKILL.md +1 -1
  114. package/skill/chat-skill/README.md +18 -0
  115. package/skill/chat-skill/SKILL.md +78 -0
  116. package/skill/chat-skill/chatgpt-instructions.md +26 -0
  117. package/skill/chat-skill/gemini-instructions.md +25 -0
  118. package/skill/references/components.md +2 -2
  119. package/dist/shell/sidebar.d.ts +0 -113
  120. package/dist/shell/sidebar.d.ts.map +0 -1
  121. package/dist/shell/sidebar.js +0 -293
  122. package/dist/shell/sidebar.js.map +0 -1
  123. package/docs/components/shell/sidebar.md +0 -103
@@ -1 +1 @@
1
- {"version":3,"file":"avatar-group.js","names":[],"sources":["../../src/composed/avatar-group.tsx"],"sourcesContent":["'use client'\n\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { AnimatePresence,motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport type { AvatarRing } from '../ui/avatar'\nimport {\n Avatar,\n AvatarFallback,\n AvatarImage,\n} from '../ui/avatar'\nimport { springs } from '../ui/lib/motion'\nimport { cn } from '../ui/lib/utils'\nimport {\n Tooltip,\n TooltipContent,\n TooltipProvider,\n TooltipTrigger,\n} from '../ui/tooltip'\nimport { getInitials } from './lib/string-utils'\n\n// Ring classes applied at group level (not via Avatar's ring prop, which adds ring-offset-2 that gets clipped by overflow-hidden)\nconst groupRingMap: Record<string, string> = {\n lead: 'ring-2 ring-accent-7 ring-offset-1 ring-offset-surface-raised',\n admin: 'ring-2 ring-warning-7 ring-offset-1 ring-offset-surface-raised',\n client: 'ring-2 ring-info-7 ring-offset-1 ring-offset-surface-raised',\n}\n\nconst avatarSizeVariants = cva(\n 'shrink-0 overflow-hidden rounded-pill border-2',\n {\n variants: {\n size: {\n xs: 'h-ds-xs w-ds-xs',\n sm: 'h-ds-sm w-ds-sm',\n md: 'h-ds-md w-ds-md',\n lg: 'h-ds-lg w-ds-lg',\n xl: 'h-ds-xl w-ds-xl',\n },\n },\n defaultVariants: {\n size: 'md',\n },\n },\n)\n\nexport interface AvatarUser {\n name: string\n image?: string | null\n ring?: AvatarRing\n indicator?: 'lead' | 'admin' | React.ReactNode\n}\n\nexport interface AvatarGroupProps\n extends React.HTMLAttributes<HTMLDivElement>,\n VariantProps<typeof avatarSizeVariants> {\n users: AvatarUser[]\n max?: number\n showTooltip?: boolean\n /** Border color for the group avatars. @default 'surface-raised' */\n borderColor?: 'surface-base' | 'surface-raised'\n /** Callback when the \"+N\" overflow badge is clicked */\n onOverflowClick?: () => void\n /** Custom render function for each avatar */\n renderAvatar?: (user: AvatarUser, index: number) => React.ReactNode\n /** Direction avatars expand on hover. @default 'right' */\n expandDirection?: 'left' | 'right'\n /** How much avatars spread apart on hover. @default 'default' */\n expandAmount?: 'compact' | 'default' | 'wide'\n}\n\nconst AvatarGroup = React.forwardRef<HTMLDivElement, AvatarGroupProps>(\n (\n {\n users,\n max = 4,\n size,\n showTooltip = true,\n borderColor = 'surface-raised',\n onOverflowClick,\n renderAvatar,\n expandDirection = 'right',\n expandAmount = 'default',\n className,\n ...props\n },\n ref,\n ) => {\n const displayed = users.slice(0, max)\n const overflow = users.length - max\n\n const overlapMap = {\n xs: '-ml-ds-02',\n sm: '-ml-ds-02b',\n md: '-ml-ds-03',\n lg: '-ml-ds-04',\n xl: '-ml-ds-05',\n }\n const overlapClass = overlapMap[size ?? 'md']\n\n // Match Avatar fallback font sizes so the \"+N\" badge text is consistent\n const textSizeMap: Record<string, string> = {\n xs: 'text-[9px]',\n sm: 'text-body-xs',\n md: 'text-body-sm',\n lg: 'text-body-md',\n xl: 'text-heading-xs',\n }\n const textSizeClass = textSizeMap[size ?? 'md']\n\n // Indicator dot scales with avatar size (matches Avatar's statusDotSizeMap)\n const indicatorDotSizeMap: Record<string, string> = {\n xs: 'h-1 w-1',\n sm: 'h-1.5 w-1.5',\n md: 'h-2 w-2',\n lg: 'h-2.5 w-2.5',\n xl: 'h-3 w-3',\n }\n const indicatorDotClass = indicatorDotSizeMap[size ?? 'md']\n\n const borderClass =\n borderColor === 'surface-base'\n ? 'border-surface-base'\n : 'border-surface-raised'\n\n const [isHovered, setIsHovered] = React.useState(false)\n\n const overlapPxMap: Record<string, number> = {\n xs: 8, sm: 10, md: 12, lg: 16, xl: 20,\n }\n const resolvedSize = size ?? 'md'\n const overlapPx = overlapPxMap[resolvedSize]\n const expandMultiplier = { compact: 0.5, default: 1, wide: 1.5 }[expandAmount]\n const totalVisible = displayed.length + (overflow > 0 ? 1 : 0)\n\n function getExpandTransform(index: number): string {\n if (!isHovered) return 'translateX(0)'\n const shift = overlapPx * expandMultiplier\n if (expandDirection === 'left') {\n return `translateX(-${(totalVisible - 1 - index) * shift}px)`\n }\n return `translateX(${index * shift}px)`\n }\n\n const spotlightClasses =\n 'transition-opacity duration-300 ease-out hover:z-50 group-hover:[&:not(:hover)]:opacity-85'\n\n return (\n <TooltipProvider>\n <div\n ref={ref}\n role=\"group\"\n aria-label={`${users.length} team members`}\n tabIndex={0}\n className={cn('group flex items-center', className)}\n onMouseEnter={() => setIsHovered(true)}\n onMouseLeave={() => setIsHovered(false)}\n onFocus={() => setIsHovered(true)}\n onBlur={(e) => { if (!e.currentTarget.contains(e.relatedTarget)) setIsHovered(false) }}\n {...props}\n >\n {displayed.map((user, index) => {\n const initials = getInitials(user.name)\n\n const key = `${user.name}-${index}`\n\n if (renderAvatar) {\n // When renderAvatar is provided, the consumer owns the Avatar entirely.\n // Wrapper is positioning-only (overlap, z-index, spotlight) — no size/border/clip\n // so the consumer's Avatar renders at its natural size without being clipped.\n return (\n <div\n key={key}\n className={cn(\n 'shrink-0 rounded-pill',\n index > 0 && overlapClass,\n spotlightClasses,\n user.ring && user.ring !== 'none' && groupRingMap[user.ring],\n )}\n style={{ zIndex: displayed.length - index, transform: getExpandTransform(index) }}\n >\n {renderAvatar(user, index)}\n </div>\n )\n }\n\n const avatarNode = (\n <div\n key={key}\n className={cn(\n 'relative shrink-0 rounded-pill',\n index > 0 && overlapClass,\n spotlightClasses,\n user.ring && user.ring !== 'none' && groupRingMap[user.ring],\n )}\n style={{ zIndex: displayed.length - index, transform: getExpandTransform(index) }}\n >\n <Avatar\n size={size}\n className={borderClass}\n >\n {user.image && (\n <AvatarImage src={user.image} alt={user.name} />\n )}\n <AvatarFallback\n colorSeed={user.name}\n >\n {initials}\n </AvatarFallback>\n </Avatar>\n <AnimatePresence>\n {user.indicator && (\n <motion.span\n initial={{ scale: 0, opacity: 0 }}\n animate={{ scale: 1, opacity: 1 }}\n exit={{ scale: 0, opacity: 0 }}\n transition={springs.snappy}\n className={cn(\n 'absolute top-0 right-0 rounded-pill ring-1 ring-surface-raised',\n indicatorDotClass,\n user.indicator === 'lead' ? 'bg-accent-9' :\n user.indicator === 'admin' ? 'bg-accent-9' : '',\n )}\n >\n {typeof user.indicator !== 'string' && user.indicator}\n </motion.span>\n )}\n </AnimatePresence>\n </div>\n )\n\n if (!showTooltip) return avatarNode\n\n return (\n <Tooltip key={key}>\n <TooltipTrigger asChild>{avatarNode}</TooltipTrigger>\n <TooltipContent\n className=\"border-surface-border-strong bg-surface-base text-surface-fg\"\n sideOffset={6}\n >\n <p className=\"text-body-sm\">{user.name}</p>\n </TooltipContent>\n </Tooltip>\n )\n })}\n\n {overflow > 0 && (\n <Tooltip>\n <TooltipTrigger asChild>\n {onOverflowClick ? (\n <button\n type=\"button\"\n onClick={onOverflowClick}\n aria-label={`${overflow} more members`}\n className={cn(\n avatarSizeVariants({ size }),\n borderClass,\n overlapClass,\n `flex cursor-pointer items-center justify-center bg-accent-2 font-semibold text-accent-11 ${textSizeClass}`,\n 'hover:bg-accent-3 transition-colors duration-300 ease-out',\n )}\n style={{ zIndex: 0, transform: getExpandTransform(displayed.length) }}\n >\n +{overflow}\n </button>\n ) : (\n <div\n role=\"img\"\n aria-label={`${overflow} more members`}\n className={cn(\n avatarSizeVariants({ size }),\n borderClass,\n overlapClass,\n `flex cursor-default items-center justify-center bg-accent-2 font-semibold text-accent-11 ${textSizeClass}`,\n 'transition-[transform,opacity] duration-300 ease-out',\n )}\n style={{ zIndex: 0, transform: getExpandTransform(displayed.length) }}\n >\n +{overflow}\n </div>\n )}\n </TooltipTrigger>\n <TooltipContent\n className=\"border-surface-border-strong bg-surface-base text-surface-fg\"\n sideOffset={6}\n >\n <div className=\"flex flex-col gap-ds-01\">\n {users.slice(max).map((user, i) => (\n <p key={i} className=\"text-body-sm\">{user.name}</p>\n ))}\n </div>\n </TooltipContent>\n </Tooltip>\n )}\n </div>\n </TooltipProvider>\n )\n },\n)\nAvatarGroup.displayName = 'AvatarGroup'\n\nexport { AvatarGroup }\n"],"mappings":"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"}
1
+ {"version":3,"file":"avatar-group.js","names":[],"sources":["../../src/composed/avatar-group.tsx"],"sourcesContent":["'use client'\n\nimport { type VariantProps } from 'class-variance-authority'\nimport { motion, useReducedMotion } from 'framer-motion'\nimport * as React from 'react'\n\nimport {\n Avatar,\n AvatarFallback,\n AvatarImage,\n avatarVariants,\n type AvatarRing,\n} from '../ui/avatar'\nimport { springs } from '../ui/lib/motion'\nimport { cn } from '../ui/lib/utils'\nimport {\n Tooltip,\n TooltipContent,\n TooltipProvider,\n TooltipTrigger,\n} from '../ui/tooltip'\nimport { getInitials } from './lib/string-utils'\n\ntype Size = NonNullable<VariantProps<typeof avatarVariants>['size']>\n\n// Group-level ring. Applied here (not via Avatar's `ring` prop) because that adds\n// a ring-offset that gets clipped by the group's overflow; the offset surface is\n// derived from `borderColor` so it never seams against a surface-base blend.\nconst groupRingMap: Record<Exclude<AvatarRing, 'none'>, string> = {\n lead: 'ring-2 ring-accent-7',\n admin: 'ring-2 ring-warning-7',\n client: 'ring-2 ring-info-7',\n}\n\nexport interface AvatarUser {\n name: string\n image?: string | null\n ring?: AvatarRing\n /** Small top-right marker. `lead` = accent dot, `admin` = warning dot, or any node. */\n indicator?: 'lead' | 'admin' | React.ReactNode\n}\n\nexport interface AvatarGroupProps extends React.HTMLAttributes<HTMLDivElement> {\n users: AvatarUser[]\n max?: number\n size?: Size\n showTooltip?: boolean\n /** Border color for the group avatars. @default 'surface-raised' */\n borderColor?: 'surface-base' | 'surface-raised'\n /** Callback when the \"+N\" overflow badge is clicked (renders it as a button). */\n onOverflowClick?: () => void\n /** Custom render function for each avatar (consumer owns the Avatar). */\n renderAvatar?: (user: AvatarUser, index: number) => React.ReactNode\n /** Direction avatars expand on hover/focus. @default 'right' */\n expandDirection?: 'left' | 'right'\n /** How far avatars spread on hover/focus. @default 'default' */\n expandAmount?: 'compact' | 'default' | 'wide'\n /** Accessible label for the group. @default `${count} team members` */\n label?: string\n}\n\n// Overlap (negative margin) + spread distance, keyed off the same per-size scale.\nconst overlapMap: Record<Size, string> = {\n xs: '-ml-ds-02',\n sm: '-ml-ds-02b',\n md: '-ml-ds-03',\n lg: '-ml-ds-04',\n xl: '-ml-ds-05',\n}\nconst spreadPxMap: Record<Size, number> = {\n xs: 8, sm: 10, md: 12, lg: 16, xl: 20,\n}\nconst indicatorDotMap: Record<Size, string> = {\n xs: 'size-1', sm: 'size-1.5', md: 'size-2', lg: 'size-2.5', xl: 'size-3',\n}\n\nconst AvatarGroup = React.forwardRef<HTMLDivElement, AvatarGroupProps>(\n (\n {\n users,\n max = 4,\n size = 'md',\n showTooltip = true,\n borderColor = 'surface-raised',\n onOverflowClick,\n renderAvatar,\n expandDirection = 'right',\n expandAmount = 'default',\n label,\n className,\n onMouseEnter,\n onMouseLeave,\n onFocus,\n onBlur,\n ...props\n },\n ref,\n ) => {\n const reduced = useReducedMotion()\n const [active, setActive] = React.useState(false)\n\n // Empty group is not a focusable \"0 members\" target — render nothing.\n if (users.length === 0) return null\n\n const cap = Math.max(1, max)\n const displayed = users.slice(0, cap)\n const overflow = users.length - cap\n const overlapClass = overlapMap[size]\n const borderClass = borderColor === 'surface-base' ? 'border-surface-base' : 'border-surface-raised'\n const ringOffsetClass = borderColor === 'surface-base'\n ? 'ring-offset-1 ring-offset-surface-base'\n : 'ring-offset-1 ring-offset-surface-raised'\n\n const spreadPx = spreadPxMap[size]\n const spreadMult = { compact: 0.5, default: 1, wide: 1.5 }[expandAmount]\n const totalVisible = displayed.length + (overflow > 0 ? 1 : 0)\n\n // Spread offset per index. Zero under reduced-motion (no positional animation).\n const xFor = (index: number): number => {\n if (!active || reduced) return 0\n const shift = spreadPx * spreadMult\n return expandDirection === 'left' ? -(totalVisible - 1 - index) * shift : index * shift\n }\n\n // framer governs the transition; reduced-motion collapses it to instant.\n const spreadTransition = reduced ? { duration: 0 } : springs.snappy\n // Gentle dim of non-focused peers; instant under reduced-motion.\n const spotlight =\n 'transition-opacity duration-fast-02 ease-productive-standard motion-reduce:transition-none hover:z-30 focus-visible:z-30 group-hover:[&:not(:hover)]:opacity-80'\n\n const onEnter = (e: React.MouseEvent<HTMLDivElement>) => { setActive(true); onMouseEnter?.(e) }\n const onLeave = (e: React.MouseEvent<HTMLDivElement>) => { setActive(false); onMouseLeave?.(e) }\n const onGroupFocus = (e: React.FocusEvent<HTMLDivElement>) => { setActive(true); onFocus?.(e) }\n const onGroupBlur = (e: React.FocusEvent<HTMLDivElement>) => {\n if (!e.currentTarget.contains(e.relatedTarget)) setActive(false)\n onBlur?.(e)\n }\n\n return (\n <TooltipProvider>\n <div\n ref={ref}\n role=\"group\"\n aria-label={label ?? `${users.length} team members`}\n className={cn('group flex items-center', className)}\n onMouseEnter={onEnter}\n onMouseLeave={onLeave}\n onFocus={onGroupFocus}\n onBlur={onGroupBlur}\n {...props}\n >\n {displayed.map((user, index) => {\n const key = `${user.name}-${index}`\n const extraRing = user.ring && user.ring !== 'none'\n ? cn(groupRingMap[user.ring], ringOffsetClass)\n : undefined\n\n const inner = renderAvatar ? (\n renderAvatar(user, index)\n ) : (\n <Avatar size={size} className={borderClass}>\n {user.image && <AvatarImage src={user.image} alt=\"\" />}\n <AvatarFallback colorSeed={user.name}>{getInitials(user.name)}</AvatarFallback>\n {user.indicator && (\n <span\n aria-hidden=\"true\"\n className={cn(\n 'absolute top-0 right-0 rounded-pill ring-1 ring-surface-raised',\n indicatorDotMap[size],\n user.indicator === 'lead' ? 'bg-accent-9'\n : user.indicator === 'admin' ? 'bg-warning-9' : '',\n )}\n >\n {typeof user.indicator !== 'string' && user.indicator}\n </span>\n )}\n </Avatar>\n )\n\n // Each avatar is a focusable, labelled trigger so keyboard/AT users reach\n // the member name (via the tooltip) and get a visible focus ring.\n const node = (\n <motion.button\n type=\"button\"\n aria-label={user.name}\n animate={{ x: xFor(index) }}\n transition={spreadTransition}\n style={{ zIndex: displayed.length - index }}\n className={cn(\n 'relative shrink-0 rounded-pill focus-ring',\n index > 0 && overlapClass,\n spotlight,\n extraRing,\n )}\n >\n {inner}\n </motion.button>\n )\n\n if (!showTooltip) return <React.Fragment key={key}>{node}</React.Fragment>\n\n return (\n <Tooltip key={key}>\n <TooltipTrigger asChild>{node}</TooltipTrigger>\n <TooltipContent sideOffset={6}>\n <p className=\"text-body-sm\">{user.name}</p>\n </TooltipContent>\n </Tooltip>\n )\n })}\n\n {overflow > 0 && (\n <Tooltip>\n <TooltipTrigger asChild>\n <motion.button\n type=\"button\"\n onClick={onOverflowClick}\n aria-label={`${overflow} more ${overflow === 1 ? 'member' : 'members'}`}\n animate={{ x: xFor(displayed.length) }}\n transition={spreadTransition}\n style={{ zIndex: 0 }}\n className={cn(\n 'relative shrink-0 rounded-pill focus-ring',\n overlapClass,\n spotlight,\n !onOverflowClick && 'cursor-default',\n )}\n >\n <Avatar size={size} className={borderClass}>\n <AvatarFallback className=\"bg-accent-2 font-semibold text-accent-11\">\n +{overflow}\n </AvatarFallback>\n </Avatar>\n </motion.button>\n </TooltipTrigger>\n <TooltipContent sideOffset={6}>\n <div className=\"flex flex-col gap-ds-01\">\n {users.slice(cap).map((user, i) => (\n <p key={i} className=\"text-body-sm\">{user.name}</p>\n ))}\n </div>\n </TooltipContent>\n </Tooltip>\n )}\n </div>\n </TooltipProvider>\n )\n },\n)\nAvatarGroup.displayName = 'AvatarGroup'\n\nexport { AvatarGroup }\n"],"mappings":";;;;;;;;;;AA4BA,IAAM,IAA4D;CAChE,MAAM;CACN,OAAO;CACP,QAAQ;AACV,GA8BM,IAAmC;CACvC,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;AACN,GACM,IAAoC;CACxC,IAAI;CAAG,IAAI;CAAI,IAAI;CAAI,IAAI;CAAI,IAAI;AACrC,GACM,IAAwC;CAC5C,IAAI;CAAU,IAAI;CAAY,IAAI;CAAU,IAAI;CAAY,IAAI;AAClE,GAEM,IAAc,EAAM,YAEtB,EACE,UACA,SAAM,GACN,UAAO,MACP,iBAAc,IACd,iBAAc,kBACd,oBACA,iBACA,qBAAkB,SAClB,kBAAe,WACf,UACA,cACA,iBACA,iBACA,YACA,WACA,GAAG,KAEL,MACG;CACH,IAAM,IAAU,EAAiB,GAC3B,CAAC,GAAQ,KAAa,EAAM,SAAS,EAAK;CAGhD,IAAI,EAAM,WAAW,GAAG,OAAO;CAE/B,IAAM,IAAM,KAAK,IAAI,GAAG,CAAG,GACrB,IAAY,EAAM,MAAM,GAAG,CAAG,GAC9B,IAAW,EAAM,SAAS,GAC1B,IAAe,EAAW,IAC1B,IAAc,MAAgB,iBAAiB,wBAAwB,yBACvE,IAAkB,MAAgB,iBACpC,2CACA,4CAEE,IAAW,EAAY,IACvB,IAAa;EAAE,SAAS;EAAK,SAAS;EAAG,MAAM;CAAI,EAAE,IACrD,IAAe,EAAU,SAAU,MAAW,IAG9C,KAAQ,MAA0B;EACtC,IAAI,CAAC,KAAU,GAAS,OAAO;EAC/B,IAAM,IAAQ,IAAW;EACzB,OAAO,MAAoB,SAAS,EAAE,IAAe,IAAI,KAAS,IAAQ,IAAQ;CACpF,GAGM,IAAmB,IAAU,EAAE,UAAU,EAAE,IAAI,EAAQ,QAEvD,IACJ;CAUF,OACE,kBAAC,GAAD,EAAA,UACE,kBAAC,OAAD;EACO;EACL,MAAK;EACL,cAAY,KAAS,GAAG,EAAM,OAAO;EACrC,WAAW,EAAG,2BAA2B,CAAS;EAClD,eAfW,MAAwC;GAAmB,AAAjB,EAAU,EAAI,GAAG,IAAe,CAAC;EAAE;EAgBxF,eAfW,MAAwC;GAAoB,AAAlB,EAAU,EAAK,GAAG,IAAe,CAAC;EAAE;EAgBzF,UAfgB,MAAwC;GAAmB,AAAjB,EAAU,EAAI,GAAG,IAAU,CAAC;EAAE;EAgBxF,SAfe,MAAwC;GAE3D,AADK,EAAE,cAAc,SAAS,EAAE,aAAa,KAAG,EAAU,EAAK,GAC/D,IAAS,CAAC;EACZ;EAaM,GAAI;YATN,CAWG,EAAU,KAAK,GAAM,MAAU;GAC9B,IAAM,IAAM,GAAG,EAAK,KAAK,GAAG,KACtB,IAAY,EAAK,QAAQ,EAAK,SAAS,SACzC,EAAG,EAAa,EAAK,OAAO,CAAe,IAC3C,KAAA,GAEE,IAAQ,IACZ,EAAa,GAAM,CAAK,IAExB,kBAAC,GAAD;IAAc;IAAM,WAAW;cAA/B;KACG,EAAK,SAAS,kBAAC,GAAD;MAAa,KAAK,EAAK;MAAO,KAAI;KAAI,CAAA;KACrD,kBAAC,GAAD;MAAgB,WAAW,EAAK;gBAAO,EAAY,EAAK,IAAI;KAAkB,CAAA;KAC7E,EAAK,aACJ,kBAAC,QAAD;MACE,eAAY;MACZ,WAAW,EACT,kEACA,EAAgB,IAChB,EAAK,cAAc,SAAS,gBACxB,EAAK,cAAc,UAAU,iBAAiB,EACpD;gBAEC,OAAO,EAAK,aAAc,YAAY,EAAK;KACxC,CAAA;IAEF;OAKJ,IACJ,kBAAC,EAAO,QAAR;IACE,MAAK;IACL,cAAY,EAAK;IACjB,SAAS,EAAE,GAAG,EAAK,CAAK,EAAE;IAC1B,YAAY;IACZ,OAAO,EAAE,QAAQ,EAAU,SAAS,EAAM;IAC1C,WAAW,EACT,6CACA,IAAQ,KAAK,GACb,GACA,CACF;cAEC;GACY,CAAA;GAKjB,OAFK,IAGH,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD;IAAgB,SAAA;cAAS;GAAqB,CAAA,GAC9C,kBAAC,GAAD;IAAgB,YAAY;cAC1B,kBAAC,KAAD;KAAG,WAAU;eAAgB,EAAK;IAAQ,CAAA;GAC5B,CAAA,CACT,EAAA,GALK,CAKL,IARc,kBAAC,EAAM,UAAP,EAAA,UAA2B,EAAqB,GAA3B,CAA2B;EAU3E,CAAC,GAEA,IAAW,KACV,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD;GAAgB,SAAA;aACd,kBAAC,EAAO,QAAR;IACE,MAAK;IACL,SAAS;IACT,cAAY,GAAG,EAAS,QAAQ,MAAa,IAAI,WAAW;IAC5D,SAAS,EAAE,GAAG,EAAK,EAAU,MAAM,EAAE;IACrC,YAAY;IACZ,OAAO,EAAE,QAAQ,EAAE;IACnB,WAAW,EACT,6CACA,GACA,GACA,CAAC,KAAmB,gBACtB;cAEA,kBAAC,GAAD;KAAc;KAAM,WAAW;eAC7B,kBAAC,GAAD;MAAgB,WAAU;gBAA1B,CAAqE,KACjE,CACY;;IACV,CAAA;GACK,CAAA;EACD,CAAA,GAChB,kBAAC,GAAD;GAAgB,YAAY;aAC1B,kBAAC,OAAD;IAAK,WAAU;cACZ,EAAM,MAAM,CAAG,CAAC,CAAC,KAAK,GAAM,MAC3B,kBAAC,KAAD;KAAW,WAAU;eAAgB,EAAK;IAAQ,GAA1C,CAA0C,CACnD;GACE,CAAA;EACS,CAAA,CACT,EAAA,CAAA,CAER;IACU,CAAA;AAErB,CACF;AACA,EAAY,cAAc"}
@@ -1,31 +1,39 @@
1
1
  "use client";
2
+ import { Button } from '../ui/button';
2
3
  import { IconInput } from '../ui/lib/icon-input';
3
4
  import * as React from 'react';
5
+ type ButtonColor = React.ComponentProps<typeof Button>['color'];
4
6
  export interface BulkActionBarAction {
5
7
  label: string;
6
8
  icon?: IconInput;
7
9
  onClick: () => void;
8
- color?: 'accent' | 'error';
10
+ /** Any Button color. @default 'accent' (or 'error' for destructive). */
11
+ color?: ButtonColor;
9
12
  disabled?: boolean;
10
- /** Show inline confirmation before executing the action */
13
+ /** Show a pending spinner on the action (e.g. slow bulk op in flight). */
14
+ loading?: boolean;
15
+ /** Show inline confirmation before executing the action. */
11
16
  requiresConfirmation?: boolean;
12
- /** Custom confirmation message @default 'Are you sure?' */
17
+ /** Custom confirmation message. @default 'Are you sure?' */
13
18
  confirmMessage?: string;
14
19
  }
15
- export interface BulkActionBarProps {
20
+ export interface BulkActionBarProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'children' | 'color' | 'onDrag' | 'onDragStart' | 'onDragEnd' | 'onAnimationStart' | 'onAnimationEnd' | 'onAnimationIteration' | 'style'> {
16
21
  show: boolean;
17
22
  count: number;
18
23
  onClearSelection: () => void;
19
24
  actions: BulkActionBarAction[];
20
- /** Total number of items available for selection */
25
+ /** Total items available for selection (enables "Select all"). */
21
26
  totalCount?: number;
22
- /** Called when user clicks "Select all" */
27
+ /** Called when the user clicks "Select all". */
23
28
  onSelectAll?: () => void;
24
- className?: string;
25
- }
26
- declare function BulkActionBar({ show, count, onClearSelection, actions, totalCount, onSelectAll, className, }: BulkActionBarProps): React.ReactPortal | null;
27
- declare namespace BulkActionBar {
28
- var displayName: string;
29
29
  }
30
+ /**
31
+ * BulkActionBar — floating selection toolbar. Follows the ARIA toolbar model:
32
+ * a single tab stop with roving focus (Arrow keys / Home / End) across ALL
33
+ * controls (Select-all, actions, Clear), focus landing on the real buttons so
34
+ * Enter/Space activate them. Arrow direction mirrors under `dir="rtl"`. Escape
35
+ * clears the selection (or cancels a pending confirmation).
36
+ */
37
+ declare const BulkActionBar: React.ForwardRefExoticComponent<BulkActionBarProps & React.RefAttributes<HTMLDivElement>>;
30
38
  export { BulkActionBar };
31
39
  //# sourceMappingURL=bulk-action-bar.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"bulk-action-bar.d.ts","sourceRoot":"","sources":["../../src/composed/bulk-action-bar.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAM9B,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAA;AAQrD,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB,OAAO,EAAE,MAAM,IAAI,CAAA;IACnB,KAAK,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAA;IAC1B,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,2DAA2D;IAC3D,oBAAoB,CAAC,EAAE,OAAO,CAAA;IAC9B,2DAA2D;IAC3D,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,OAAO,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;IACb,gBAAgB,EAAE,MAAM,IAAI,CAAA;IAC5B,OAAO,EAAE,mBAAmB,EAAE,CAAA;IAC9B,oDAAoD;IACpD,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,2CAA2C;IAC3C,WAAW,CAAC,EAAE,MAAM,IAAI,CAAA;IACxB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAyED,iBAAS,aAAa,CAAC,EACrB,IAAI,EACJ,KAAK,EACL,gBAAgB,EAChB,OAAO,EACP,UAAU,EACV,WAAW,EACX,SAAS,GACV,EAAE,kBAAkB,4BAqGpB;kBA7GQ,aAAa;;;AAiHtB,OAAO,EAAE,aAAa,EAAE,CAAA"}
1
+ {"version":3,"file":"bulk-action-bar.d.ts","sourceRoot":"","sources":["../../src/composed/bulk-action-bar.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAI9B,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AAErC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAA;AAIrD,KAAK,WAAW,GAAG,KAAK,CAAC,cAAc,CAAC,OAAO,MAAM,CAAC,CAAC,OAAO,CAAC,CAAA;AAE/D,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB,OAAO,EAAE,MAAM,IAAI,CAAA;IACnB,wEAAwE;IACxE,KAAK,CAAC,EAAE,WAAW,CAAA;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,0EAA0E;IAC1E,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,4DAA4D;IAC5D,oBAAoB,CAAC,EAAE,OAAO,CAAA;IAC9B,4DAA4D;IAC5D,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB;AAED,MAAM,WAAW,kBACf,SAAQ,IAAI,CACV,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,EAEpC,UAAU,GAAG,OAAO,GAAG,QAAQ,GAAG,aAAa,GAAG,WAAW,GAAG,kBAAkB,GAAG,gBAAgB,GAAG,sBAAsB,GAAG,OAAO,CACzI;IACD,IAAI,EAAE,OAAO,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;IACb,gBAAgB,EAAE,MAAM,IAAI,CAAA;IAC5B,OAAO,EAAE,mBAAmB,EAAE,CAAA;IAC9B,kEAAkE;IAClE,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,gDAAgD;IAChD,WAAW,CAAC,EAAE,MAAM,IAAI,CAAA;CACzB;AAED;;;;;;GAMG;AACH,QAAA,MAAM,aAAa,2FAwJlB,CAAA;AAGD,OAAO,EAAE,aAAa,EAAE,CAAA"}
@@ -8,152 +8,123 @@ import * as a from "react";
8
8
  import { jsx as o, jsxs as s } from "react/jsx-runtime";
9
9
  import { createPortal as c } from "react-dom";
10
10
  import { IconX as l } from "@tabler/icons-react";
11
- import { AnimatePresence as u, motion as d } from "framer-motion";
11
+ import { AnimatePresence as u, motion as d, useReducedMotion as f } from "framer-motion";
12
12
  //#region src/composed/bulk-action-bar.tsx
13
- var f = a.forwardRef(function({ action: t, tabIndex: n }, r) {
14
- let [c, l] = a.useState(!1);
15
- return c ? /* @__PURE__ */ s(d.div, {
16
- ref: r,
17
- initial: {
18
- opacity: 0,
19
- scale: .95
20
- },
21
- animate: {
22
- opacity: 1,
23
- scale: 1
24
- },
25
- exit: {
26
- opacity: 0,
27
- scale: .95
28
- },
29
- transition: e.snappy,
30
- className: "flex items-center gap-ds-02",
31
- tabIndex: n,
32
- children: [
33
- /* @__PURE__ */ o("span", {
34
- className: "text-body-sm text-surface-fg-muted whitespace-nowrap",
35
- children: t.confirmMessage ?? "Are you sure?"
36
- }),
37
- /* @__PURE__ */ o(i, {
38
- variant: "solid",
39
- size: "sm",
40
- color: "error",
41
- onClick: () => {
42
- l(!1), t.onClick();
43
- },
44
- children: "Confirm"
45
- }),
46
- /* @__PURE__ */ o(i, {
47
- variant: "ghost",
48
- size: "sm",
49
- onClick: () => l(!1),
50
- children: "Cancel"
51
- })
52
- ]
53
- }) : /* @__PURE__ */ o(d.div, {
54
- ref: r,
55
- initial: {
56
- opacity: 0,
57
- scale: .95
58
- },
59
- animate: {
60
- opacity: 1,
61
- scale: 1
62
- },
63
- exit: {
64
- opacity: 0,
65
- scale: .95
66
- },
67
- transition: e.snappy,
68
- tabIndex: n,
69
- children: /* @__PURE__ */ o(i, {
70
- variant: "ghost",
71
- size: "sm",
72
- color: t.color === "error" ? "error" : "accent",
73
- disabled: t.disabled,
74
- onClick: t.requiresConfirmation ? () => l(!0) : t.onClick,
75
- startIcon: t.icon ?? void 0,
76
- tabIndex: -1,
77
- children: t.label
78
- })
79
- });
80
- });
81
- function p({ show: p, count: m, onClearSelection: h, actions: g, totalCount: _, onSelectAll: v, className: y }) {
82
- let [b, x] = a.useState(!1), [S, C] = a.useState(0), w = a.useRef([]);
13
+ var p = a.forwardRef(function({ show: p, count: m, onClearSelection: h, actions: g, totalCount: _, onSelectAll: v, className: y, ...b }, x) {
14
+ let S = f(), [C, w] = a.useState(!1), [T, E] = a.useState(0), [D, O] = a.useState(null), k = a.useRef([]), A = a.useRef(null), j = _ != null && _ > m && !!v, M = +!!j, N = M + g.length + 1;
83
15
  a.useEffect(() => {
84
- C(0);
16
+ w(!0);
17
+ }, []), a.useEffect(() => {
18
+ E(0), O(null);
85
19
  }, [g.length]), a.useEffect(() => {
86
- x(!0);
87
- }, []);
88
- function T(e) {
20
+ D != null && A.current?.focus();
21
+ }, [D]);
22
+ let P = (e) => {
23
+ let t = (e + N) % N;
24
+ E(t), k.current[t]?.focus();
25
+ };
26
+ function F(e) {
89
27
  if (e.key === "Escape") {
90
- e.preventDefault(), h();
28
+ e.preventDefault(), D == null ? h() : (O(null), P(T));
91
29
  return;
92
30
  }
93
- let t = g.length;
94
- if (t !== 0) {
95
- if (e.key === "ArrowRight") {
96
- e.preventDefault();
97
- let n = (S + 1) % t;
98
- C(n), w.current[n]?.focus();
99
- } else if (e.key === "ArrowLeft") {
100
- e.preventDefault();
101
- let n = (S - 1 + t) % t;
102
- C(n), w.current[n]?.focus();
103
- } else if (e.key === "Home") e.preventDefault(), C(0), w.current[0]?.focus();
104
- else if (e.key === "End") {
105
- e.preventDefault();
106
- let n = t - 1;
107
- C(n), w.current[n]?.focus();
108
- }
109
- }
31
+ if (D != null) return;
32
+ let t = e.currentTarget.dir === "rtl" || document.dir === "rtl", n = t ? "ArrowLeft" : "ArrowRight", r = t ? "ArrowRight" : "ArrowLeft";
33
+ e.key === n ? (e.preventDefault(), P(T + 1)) : e.key === r ? (e.preventDefault(), P(T - 1)) : e.key === "Home" ? (e.preventDefault(), P(0)) : e.key === "End" && (e.preventDefault(), P(N - 1));
110
34
  }
111
- return b ? c(/* @__PURE__ */ o(u, { children: p && /* @__PURE__ */ s(d.div, {
112
- initial: {
35
+ if (!C) return null;
36
+ let I = S ? { duration: 0 } : e.smooth;
37
+ return c(/* @__PURE__ */ o(u, { children: p && /* @__PURE__ */ s(d.div, {
38
+ ref: x,
39
+ initial: S ? { opacity: 0 } : {
113
40
  y: 100,
114
41
  opacity: 0
115
42
  },
116
- animate: {
43
+ animate: S ? { opacity: 1 } : {
117
44
  y: 0,
118
45
  opacity: 1
119
46
  },
120
- exit: {
47
+ exit: S ? { opacity: 0 } : {
121
48
  y: 100,
122
49
  opacity: 0
123
50
  },
124
- transition: e.snappy,
125
- className: t("fixed bottom-ds-06 left-1/2 z-sticky -translate-x-1/2", "flex items-center gap-ds-04 rounded-surface bg-surface-overlay px-ds-05 py-ds-03 shadow-floating", y),
51
+ transition: I,
52
+ className: t("fixed bottom-ds-06 start-1/2 z-sticky -translate-x-1/2", "flex items-center gap-ds-04 rounded-surface bg-surface-overlay px-ds-05 py-ds-03 shadow-floating", y),
126
53
  role: "toolbar",
127
54
  "aria-label": `${m} items selected`,
128
- onKeyDown: T,
55
+ onKeyDown: F,
56
+ ...b,
129
57
  children: [
130
58
  /* @__PURE__ */ s(r, {
131
59
  variant: "solid",
132
60
  size: "sm",
133
61
  children: [m, " selected"]
134
62
  }),
135
- _ != null && _ > m && v && /* @__PURE__ */ s(i, {
63
+ j && /* @__PURE__ */ s(i, {
64
+ ref: (e) => {
65
+ k.current[0] = e;
66
+ },
136
67
  variant: "link",
137
68
  size: "xs",
69
+ tabIndex: T === 0 ? 0 : -1,
138
70
  onClick: v,
139
71
  children: ["Select all ", _]
140
72
  }),
141
73
  /* @__PURE__ */ o("div", {
142
74
  className: "flex items-center gap-ds-02",
143
- children: /* @__PURE__ */ o(u, {
144
- mode: "popLayout",
145
- children: g.map((e, t) => /* @__PURE__ */ o(f, {
75
+ children: g.map((e, t) => {
76
+ let n = M + t;
77
+ return D === t ? /* @__PURE__ */ s("div", {
78
+ role: "group",
79
+ "aria-live": "assertive",
80
+ className: "flex items-center gap-ds-02",
81
+ children: [
82
+ /* @__PURE__ */ o("span", {
83
+ className: "whitespace-nowrap text-body-sm text-surface-fg-muted",
84
+ children: e.confirmMessage ?? "Are you sure?"
85
+ }),
86
+ /* @__PURE__ */ o(i, {
87
+ ref: A,
88
+ variant: "solid",
89
+ size: "sm",
90
+ color: e.color === "error" ? "error" : e.color ?? "accent",
91
+ onClick: () => {
92
+ O(null), e.onClick();
93
+ },
94
+ children: "Confirm"
95
+ }),
96
+ /* @__PURE__ */ o(i, {
97
+ variant: "ghost",
98
+ size: "sm",
99
+ onClick: () => {
100
+ O(null), P(n);
101
+ },
102
+ children: "Cancel"
103
+ })
104
+ ]
105
+ }, e.label) : /* @__PURE__ */ o(i, {
146
106
  ref: (e) => {
147
- w.current[t] = e;
107
+ k.current[n] = e;
148
108
  },
149
- action: e,
150
- tabIndex: t === S ? 0 : -1
151
- }, e.label))
109
+ variant: "ghost",
110
+ size: "sm",
111
+ color: e.color ?? "accent",
112
+ disabled: e.disabled,
113
+ loading: e.loading,
114
+ startIcon: e.icon ?? void 0,
115
+ tabIndex: T === n ? 0 : -1,
116
+ onClick: e.requiresConfirmation ? () => O(t) : e.onClick,
117
+ children: e.label
118
+ }, e.label);
152
119
  })
153
120
  }),
154
121
  /* @__PURE__ */ o(i, {
122
+ ref: (e) => {
123
+ k.current[N - 1] = e;
124
+ },
155
125
  variant: "ghost",
156
126
  size: "icon-sm",
127
+ tabIndex: T === N - 1 ? 0 : -1,
157
128
  onClick: h,
158
129
  "aria-label": "Clear selection",
159
130
  children: /* @__PURE__ */ o(n, {
@@ -162,8 +133,8 @@ function p({ show: p, count: m, onClearSelection: h, actions: g, totalCount: _,
162
133
  })
163
134
  })
164
135
  ]
165
- }) }), document.body) : null;
166
- }
136
+ }) }), document.body);
137
+ });
167
138
  p.displayName = "BulkActionBar";
168
139
  //#endregion
169
140
  export { p as BulkActionBar };
@@ -1 +1 @@
1
- {"version":3,"file":"bulk-action-bar.js","names":[],"sources":["../../src/composed/bulk-action-bar.tsx"],"sourcesContent":["'use client'\n\nimport { IconX } from '@tabler/icons-react'\nimport { AnimatePresence, motion } from 'framer-motion'\nimport * as React from 'react'\nimport { createPortal } from 'react-dom'\n\nimport { Badge } from '../ui/badge'\nimport { Button } from '../ui/button'\nimport { Icon } from '../ui/icon'\nimport type { IconInput } from '../ui/lib/icon-input'\nimport { springs } from '../ui/lib/motion'\nimport { cn } from '../ui/lib/utils'\n\n// ============================================================\n// Types\n// ============================================================\n\nexport interface BulkActionBarAction {\n label: string\n icon?: IconInput\n onClick: () => void\n color?: 'accent' | 'error'\n disabled?: boolean\n /** Show inline confirmation before executing the action */\n requiresConfirmation?: boolean\n /** Custom confirmation message @default 'Are you sure?' */\n confirmMessage?: string\n}\n\nexport interface BulkActionBarProps {\n show: boolean\n count: number\n onClearSelection: () => void\n actions: BulkActionBarAction[]\n /** Total number of items available for selection */\n totalCount?: number\n /** Called when user clicks \"Select all\" */\n onSelectAll?: () => void\n className?: string\n}\n\n// ============================================================\n// ActionButton — handles inline confirmation\n// ============================================================\n\nconst ActionButton = React.forwardRef<HTMLDivElement, { action: BulkActionBarAction; tabIndex?: number }>(function ActionButton({ action, tabIndex }, ref) {\n const [confirming, setConfirming] = React.useState(false)\n\n if (confirming) {\n return (\n <motion.div\n ref={ref}\n initial={{ opacity: 0, scale: 0.95 }}\n animate={{ opacity: 1, scale: 1 }}\n exit={{ opacity: 0, scale: 0.95 }}\n transition={springs.snappy}\n className=\"flex items-center gap-ds-02\"\n tabIndex={tabIndex}\n >\n <span className=\"text-body-sm text-surface-fg-muted whitespace-nowrap\">\n {action.confirmMessage ?? 'Are you sure?'}\n </span>\n <Button\n variant=\"solid\"\n size=\"sm\"\n color=\"error\"\n onClick={() => {\n setConfirming(false)\n action.onClick()\n }}\n >\n Confirm\n </Button>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => setConfirming(false)}\n >\n Cancel\n </Button>\n </motion.div>\n )\n }\n\n return (\n <motion.div\n ref={ref}\n initial={{ opacity: 0, scale: 0.95 }}\n animate={{ opacity: 1, scale: 1 }}\n exit={{ opacity: 0, scale: 0.95 }}\n transition={springs.snappy}\n tabIndex={tabIndex}\n >\n <Button\n variant=\"ghost\"\n size=\"sm\"\n color={action.color === 'error' ? 'error' : 'accent'}\n disabled={action.disabled}\n onClick={action.requiresConfirmation ? () => setConfirming(true) : action.onClick}\n startIcon={action.icon ?? undefined}\n tabIndex={-1}\n >\n {action.label}\n </Button>\n </motion.div>\n )\n})\n\n// ============================================================\n// BulkActionBar\n// ============================================================\n\nfunction BulkActionBar({\n show,\n count,\n onClearSelection,\n actions,\n totalCount,\n onSelectAll,\n className,\n}: BulkActionBarProps) {\n const [mounted, setMounted] = React.useState(false)\n const [focusedIndex, setFocusedIndex] = React.useState(0)\n const actionRefs = React.useRef<(HTMLDivElement | null)[]>([])\n\n // Reset focused index when actions change\n React.useEffect(() => {\n setFocusedIndex(0)\n }, [actions.length])\n\n React.useEffect(() => {\n setMounted(true)\n }, [])\n\n function handleKeyDown(e: React.KeyboardEvent) {\n if (e.key === 'Escape') {\n e.preventDefault()\n onClearSelection()\n return\n }\n\n const count = actions.length\n if (count === 0) return\n\n if (e.key === 'ArrowRight') {\n e.preventDefault()\n const next = (focusedIndex + 1) % count\n setFocusedIndex(next)\n actionRefs.current[next]?.focus()\n } else if (e.key === 'ArrowLeft') {\n e.preventDefault()\n const prev = (focusedIndex - 1 + count) % count\n setFocusedIndex(prev)\n actionRefs.current[prev]?.focus()\n } else if (e.key === 'Home') {\n e.preventDefault()\n setFocusedIndex(0)\n actionRefs.current[0]?.focus()\n } else if (e.key === 'End') {\n e.preventDefault()\n const last = count - 1\n setFocusedIndex(last)\n actionRefs.current[last]?.focus()\n }\n }\n\n if (!mounted) return null\n\n return createPortal(\n <AnimatePresence>\n {show && (\n <motion.div\n initial={{ y: 100, opacity: 0 }}\n animate={{ y: 0, opacity: 1 }}\n exit={{ y: 100, opacity: 0 }}\n transition={springs.snappy}\n className={cn(\n 'fixed bottom-ds-06 left-1/2 z-sticky -translate-x-1/2',\n 'flex items-center gap-ds-04 rounded-surface bg-surface-overlay px-ds-05 py-ds-03 shadow-floating',\n className,\n )}\n role=\"toolbar\"\n aria-label={`${count} items selected`}\n onKeyDown={handleKeyDown}\n >\n <Badge variant=\"solid\" size=\"sm\">\n {count} selected\n </Badge>\n\n {totalCount != null && totalCount > count && onSelectAll && (\n <Button variant=\"link\" size=\"xs\" onClick={onSelectAll}>\n Select all {totalCount}\n </Button>\n )}\n\n <div className=\"flex items-center gap-ds-02\">\n <AnimatePresence mode=\"popLayout\">\n {actions.map((action, i) => (\n <ActionButton\n key={action.label}\n ref={(el: HTMLDivElement | null) => { actionRefs.current[i] = el }}\n action={action}\n tabIndex={i === focusedIndex ? 0 : -1}\n />\n ))}\n </AnimatePresence>\n </div>\n\n <Button\n variant=\"ghost\"\n size=\"icon-sm\"\n onClick={onClearSelection}\n aria-label=\"Clear selection\"\n >\n <Icon icon={IconX} size=\"sm\" />\n </Button>\n </motion.div>\n )}\n </AnimatePresence>,\n document.body,\n )\n}\n\nBulkActionBar.displayName = 'BulkActionBar'\n\nexport { BulkActionBar }\n"],"mappings":"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"}
1
+ {"version":3,"file":"bulk-action-bar.js","names":[],"sources":["../../src/composed/bulk-action-bar.tsx"],"sourcesContent":["'use client'\n\nimport { IconX } from '@tabler/icons-react'\nimport { AnimatePresence, motion, useReducedMotion } from 'framer-motion'\nimport * as React from 'react'\nimport { createPortal } from 'react-dom'\n\nimport { Badge } from '../ui/badge'\nimport { Button } from '../ui/button'\nimport { Icon } from '../ui/icon'\nimport type { IconInput } from '../ui/lib/icon-input'\nimport { springs } from '../ui/lib/motion'\nimport { cn } from '../ui/lib/utils'\n\ntype ButtonColor = React.ComponentProps<typeof Button>['color']\n\nexport interface BulkActionBarAction {\n label: string\n icon?: IconInput\n onClick: () => void\n /** Any Button color. @default 'accent' (or 'error' for destructive). */\n color?: ButtonColor\n disabled?: boolean\n /** Show a pending spinner on the action (e.g. slow bulk op in flight). */\n loading?: boolean\n /** Show inline confirmation before executing the action. */\n requiresConfirmation?: boolean\n /** Custom confirmation message. @default 'Are you sure?' */\n confirmMessage?: string\n}\n\nexport interface BulkActionBarProps\n extends Omit<\n React.HTMLAttributes<HTMLDivElement>,\n // Keys whose types collide with framer-motion's HTMLMotionProps.\n 'children' | 'color' | 'onDrag' | 'onDragStart' | 'onDragEnd' | 'onAnimationStart' | 'onAnimationEnd' | 'onAnimationIteration' | 'style'\n > {\n show: boolean\n count: number\n onClearSelection: () => void\n actions: BulkActionBarAction[]\n /** Total items available for selection (enables \"Select all\"). */\n totalCount?: number\n /** Called when the user clicks \"Select all\". */\n onSelectAll?: () => void\n}\n\n/**\n * BulkActionBar — floating selection toolbar. Follows the ARIA toolbar model:\n * a single tab stop with roving focus (Arrow keys / Home / End) across ALL\n * controls (Select-all, actions, Clear), focus landing on the real buttons so\n * Enter/Space activate them. Arrow direction mirrors under `dir=\"rtl\"`. Escape\n * clears the selection (or cancels a pending confirmation).\n */\nconst BulkActionBar = React.forwardRef<HTMLDivElement, BulkActionBarProps>(\n function BulkActionBar(\n { show, count, onClearSelection, actions, totalCount, onSelectAll, className, ...props },\n forwardedRef,\n ) {\n const reduced = useReducedMotion()\n const [mounted, setMounted] = React.useState(false)\n const [focusedIndex, setFocusedIndex] = React.useState(0)\n const [confirming, setConfirming] = React.useState<number | null>(null)\n const controlRefs = React.useRef<Array<HTMLButtonElement | null>>([])\n const confirmRef = React.useRef<HTMLButtonElement | null>(null)\n\n const hasSelectAll = totalCount != null && totalCount > count && !!onSelectAll\n const selectAllOffset = hasSelectAll ? 1 : 0\n const total = selectAllOffset + actions.length + 1 // + Clear\n\n React.useEffect(() => { setMounted(true) }, [])\n React.useEffect(() => { setFocusedIndex(0); setConfirming(null) }, [actions.length])\n // Move focus to Confirm when a confirmation opens.\n React.useEffect(() => {\n if (confirming != null) confirmRef.current?.focus()\n }, [confirming])\n\n const focusAt = (i: number) => {\n const clamped = (i + total) % total\n setFocusedIndex(clamped)\n controlRefs.current[clamped]?.focus()\n }\n\n function handleKeyDown(e: React.KeyboardEvent<HTMLDivElement>) {\n if (e.key === 'Escape') {\n e.preventDefault()\n if (confirming != null) { setConfirming(null); focusAt(focusedIndex) }\n else onClearSelection()\n return\n }\n if (confirming != null) return // roving suspended during confirm\n const rtl = e.currentTarget.dir === 'rtl' || document.dir === 'rtl'\n const fwd = rtl ? 'ArrowLeft' : 'ArrowRight'\n const back = rtl ? 'ArrowRight' : 'ArrowLeft'\n if (e.key === fwd) { e.preventDefault(); focusAt(focusedIndex + 1) }\n else if (e.key === back) { e.preventDefault(); focusAt(focusedIndex - 1) }\n else if (e.key === 'Home') { e.preventDefault(); focusAt(0) }\n else if (e.key === 'End') { e.preventDefault(); focusAt(total - 1) }\n }\n\n if (!mounted) return null\n\n const slideTransition = reduced ? { duration: 0 } : springs.smooth\n\n return createPortal(\n <AnimatePresence>\n {show && (\n <motion.div\n ref={forwardedRef}\n initial={reduced ? { opacity: 0 } : { y: 100, opacity: 0 }}\n animate={reduced ? { opacity: 1 } : { y: 0, opacity: 1 }}\n exit={reduced ? { opacity: 0 } : { y: 100, opacity: 0 }}\n transition={slideTransition}\n className={cn(\n 'fixed bottom-ds-06 start-1/2 z-sticky -translate-x-1/2',\n 'flex items-center gap-ds-04 rounded-surface bg-surface-overlay px-ds-05 py-ds-03 shadow-floating',\n className,\n )}\n role=\"toolbar\"\n aria-label={`${count} items selected`}\n onKeyDown={handleKeyDown}\n {...props}\n >\n <Badge variant=\"solid\" size=\"sm\">{count} selected</Badge>\n\n {hasSelectAll && (\n <Button\n ref={(el) => { controlRefs.current[0] = el }}\n variant=\"link\"\n size=\"xs\"\n tabIndex={focusedIndex === 0 ? 0 : -1}\n onClick={onSelectAll}\n >\n Select all {totalCount}\n </Button>\n )}\n\n <div className=\"flex items-center gap-ds-02\">\n {actions.map((action, i) => {\n const controlIndex = selectAllOffset + i\n const isConfirming = confirming === i\n if (isConfirming) {\n return (\n <div\n key={action.label}\n role=\"group\"\n aria-live=\"assertive\"\n className=\"flex items-center gap-ds-02\"\n >\n <span className=\"whitespace-nowrap text-body-sm text-surface-fg-muted\">\n {action.confirmMessage ?? 'Are you sure?'}\n </span>\n <Button\n ref={confirmRef}\n variant=\"solid\"\n size=\"sm\"\n color={action.color === 'error' ? 'error' : (action.color ?? 'accent')}\n onClick={() => { setConfirming(null); action.onClick() }}\n >\n Confirm\n </Button>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => { setConfirming(null); focusAt(controlIndex) }}\n >\n Cancel\n </Button>\n </div>\n )\n }\n return (\n <Button\n key={action.label}\n ref={(el) => { controlRefs.current[controlIndex] = el }}\n variant=\"ghost\"\n size=\"sm\"\n color={action.color ?? 'accent'}\n disabled={action.disabled}\n loading={action.loading}\n startIcon={action.icon ?? undefined}\n tabIndex={focusedIndex === controlIndex ? 0 : -1}\n onClick={action.requiresConfirmation ? () => setConfirming(i) : action.onClick}\n >\n {action.label}\n </Button>\n )\n })}\n </div>\n\n <Button\n ref={(el) => { controlRefs.current[total - 1] = el }}\n variant=\"ghost\"\n size=\"icon-sm\"\n tabIndex={focusedIndex === total - 1 ? 0 : -1}\n onClick={onClearSelection}\n aria-label=\"Clear selection\"\n >\n <Icon icon={IconX} size=\"sm\" />\n </Button>\n </motion.div>\n )}\n </AnimatePresence>,\n document.body,\n )\n },\n)\nBulkActionBar.displayName = 'BulkActionBar'\n\nexport { BulkActionBar }\n"],"mappings":"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"}
@@ -3,10 +3,10 @@ import { IconProvider as e } from "../ui/icon-context.js";
3
3
  import { springs as t, tweens as n } from "../ui/lib/motion.js";
4
4
  import { cn as r } from "../ui/lib/utils.js";
5
5
  import { Icon as i } from "../ui/icon.js";
6
- import { normalizeIcon as a } from "../_chunks/normalize-icon.js";
7
- import { Dialog as o, DialogContentRaw as s, DialogDescription as c, DialogOverlay as l, DialogPortal as ee, DialogTitle as u } from "../ui/dialog.js";
8
- import { VisuallyHidden as te } from "../ui/visually-hidden.js";
9
- import { useMotion as ne } from "../_chunks/motion-provider.js";
6
+ import { useMotion as a } from "../_chunks/motion-provider.js";
7
+ import { normalizeIcon as o } from "../_chunks/normalize-icon.js";
8
+ import { Dialog as s, DialogContentRaw as c, DialogDescription as l, DialogOverlay as ee, DialogPortal as u, DialogTitle as te } from "../ui/dialog.js";
9
+ import { VisuallyHidden as ne } from "../ui/visually-hidden.js";
10
10
  import { getIsMac as d, getModifierDisplay as f, matchesKeybinding as p } from "../_chunks/keybinding.js";
11
11
  import * as m from "react";
12
12
  import { jsx as h, jsxs as g } from "react/jsx-runtime";
@@ -28,7 +28,7 @@ var b = m.forwardRef(function({ groups: b = [], placeholder: x = "Search or jump
28
28
  let R = m.useCallback((e) => {
29
29
  let t = typeof e == "function" ? e(L.current) : e;
30
30
  N || F(t), E?.(t);
31
- }, [N, E]), [z, B] = m.useState(""), [V, H] = m.useState(0), U = m.useRef(null), W = m.useRef(null), G = m.useId(), K = `command-palette-listbox-${G}`, { reducedMotion: q } = ne(), J = { duration: 0 }, ue = m.useMemo(() => d(), []), Y = m.useMemo(() => {
31
+ }, [N, E]), [z, B] = m.useState(""), [V, H] = m.useState(0), U = m.useRef(null), W = m.useRef(null), G = m.useId(), K = `command-palette-listbox-${G}`, { reducedMotion: q } = a(), J = { duration: 0 }, ue = m.useMemo(() => d(), []), Y = m.useMemo(() => {
32
32
  if (!z.trim()) return b;
33
33
  let e = z.toLowerCase();
34
34
  return b.map((t) => ({
@@ -97,18 +97,18 @@ var b = m.forwardRef(function({ groups: b = [], placeholder: x = "Search or jump
97
97
  label: "Close"
98
98
  }
99
99
  ];
100
- return /* @__PURE__ */ h(o, {
100
+ return /* @__PURE__ */ h(s, {
101
101
  open: I,
102
102
  onOpenChange: m.useCallback((e) => {
103
103
  R(e);
104
104
  }, [R]),
105
- children: /* @__PURE__ */ g(ee, { children: [/* @__PURE__ */ h(l, { className: "fixed inset-0 z-overlay bg-overlay data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0" }), /* @__PURE__ */ g(s, {
105
+ children: /* @__PURE__ */ g(u, { children: [/* @__PURE__ */ h(ee, { className: "fixed inset-0 z-overlay bg-overlay data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0" }), /* @__PURE__ */ g(c, {
106
106
  ref: M,
107
107
  ...j,
108
108
  className: r("fixed left-1/2 top-[20%] z-modal w-full max-w-[560px] -translate-x-1/2", "overflow-hidden rounded-overlay-lg bg-surface-overlay shadow-overlay", "duration-moderate-02 data-[state=open]:animate-in data-[state=closed]:animate-out", "data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0", "data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95", "data-[state=closed]:slide-out-to-left-1/2 data-[state=open]:slide-in-from-left-1/2", "data-[state=closed]:slide-out-to-top-2 data-[state=open]:slide-in-from-top-2", A),
109
109
  onKeyDown: de,
110
110
  children: [
111
- /* @__PURE__ */ g(te, { children: [/* @__PURE__ */ h(u, { children: "Command Palette" }), /* @__PURE__ */ h(c, { children: "Search or jump to pages, projects, tasks, and actions" })] }),
111
+ /* @__PURE__ */ g(ne, { children: [/* @__PURE__ */ h(te, { children: "Command Palette" }), /* @__PURE__ */ h(l, { children: "Search or jump to pages, projects, tasks, and actions" })] }),
112
112
  /* @__PURE__ */ g("div", {
113
113
  className: "flex items-center gap-ds-04 border-b border-surface-border-strong px-ds-05 py-ds-04",
114
114
  children: [
@@ -167,7 +167,7 @@ var b = m.forwardRef(function({ groups: b = [], placeholder: x = "Search or jump
167
167
  className: "text-body-md text-surface-fg-subtle",
168
168
  children: S
169
169
  })
170
- }), Y.map((o, s) => /* @__PURE__ */ g(v.div, {
170
+ }), Y.map((a, s) => /* @__PURE__ */ g(v.div, {
171
171
  initial: Q ?? { opacity: 0 },
172
172
  animate: { opacity: 1 },
173
173
  transition: q ? J : {
@@ -179,16 +179,16 @@ var b = m.forwardRef(function({ groups: b = [], placeholder: x = "Search or jump
179
179
  className: "px-ds-03 pb-ds-02 pt-ds-03",
180
180
  children: /* @__PURE__ */ h("span", {
181
181
  className: "text-label-xs font-semibold uppercase tracking-wider text-surface-fg-subtle",
182
- children: o.label
182
+ children: a.label
183
183
  })
184
- }), o.items.map((n) => {
185
- let o = pe.get(n.id) ?? 0, s = o === V;
184
+ }), a.items.map((n) => {
185
+ let a = pe.get(n.id) ?? 0, s = a === V;
186
186
  return /* @__PURE__ */ g(v.button, {
187
187
  id: `command-item-${G}-${n.id}`,
188
188
  type: "button",
189
189
  role: "option",
190
190
  "aria-selected": s,
191
- "data-command-index": o,
191
+ "data-command-index": a,
192
192
  initial: Q ?? {
193
193
  opacity: 0,
194
194
  y: 4
@@ -199,12 +199,12 @@ var b = m.forwardRef(function({ groups: b = [], placeholder: x = "Search or jump
199
199
  },
200
200
  transition: q ? J : {
201
201
  ...t.snappy,
202
- delay: o * .03
202
+ delay: a * .03
203
203
  },
204
204
  onClick: () => {
205
205
  n.onSelect(), R(!1);
206
206
  },
207
- onMouseEnter: () => H(o),
207
+ onMouseEnter: () => H(a),
208
208
  className: r("flex w-full items-center gap-ds-04 rounded-surface px-ds-03 py-ds-03 text-left transition-[color,background-color] duration-fast-02 ease-productive-standard", s ? "bg-surface-raised-hover text-surface-fg" : "text-surface-fg-muted hover:bg-surface-raised"),
209
209
  children: [
210
210
  n.icon && /* @__PURE__ */ h("span", {
@@ -212,7 +212,7 @@ var b = m.forwardRef(function({ groups: b = [], placeholder: x = "Search or jump
212
212
  "aria-hidden": "true",
213
213
  children: /* @__PURE__ */ h(e, {
214
214
  size: "sm",
215
- children: a(n.icon)
215
+ children: o(n.icon)
216
216
  })
217
217
  }),
218
218
  /* @__PURE__ */ g("div", {
@@ -248,7 +248,7 @@ var b = m.forwardRef(function({ groups: b = [], placeholder: x = "Search or jump
248
248
  ]
249
249
  }, n.id);
250
250
  })]
251
- }, o.label))]
251
+ }, a.label))]
252
252
  }),
253
253
  $ !== !1 && /* @__PURE__ */ h(v.div, {
254
254
  initial: Q ?? { opacity: 0 },