@humain/ui 2.2.6 → 2.2.9

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 (159) hide show
  1. package/dist/index101.js +2 -2
  2. package/dist/index101.js.map +1 -1
  3. package/dist/index103.js +3 -3
  4. package/dist/index103.js.map +1 -1
  5. package/dist/index108.js +1 -1
  6. package/dist/index108.js.map +1 -1
  7. package/dist/index117.js +1 -1
  8. package/dist/index117.js.map +1 -1
  9. package/dist/index122.js +6 -6
  10. package/dist/index122.js.map +1 -1
  11. package/dist/index126.js +1 -1
  12. package/dist/index126.js.map +1 -1
  13. package/dist/index130.js +2 -2
  14. package/dist/index130.js.map +1 -1
  15. package/dist/index146.js +4 -4
  16. package/dist/index146.js.map +1 -1
  17. package/dist/index152.js +1 -1
  18. package/dist/index152.js.map +1 -1
  19. package/dist/index154.js +2 -2
  20. package/dist/index154.js.map +1 -1
  21. package/dist/index166.js +1 -1
  22. package/dist/index166.js.map +1 -1
  23. package/dist/index168.js +1 -1
  24. package/dist/index168.js.map +1 -1
  25. package/dist/index169.js +1 -1
  26. package/dist/index169.js.map +1 -1
  27. package/dist/index173.js +2 -2
  28. package/dist/index173.js.map +1 -1
  29. package/dist/index175.js +4 -4
  30. package/dist/index175.js.map +1 -1
  31. package/dist/index176.js +2 -2
  32. package/dist/index176.js.map +1 -1
  33. package/dist/index177.js +2 -2
  34. package/dist/index177.js.map +1 -1
  35. package/dist/index184.js +1 -1
  36. package/dist/index184.js.map +1 -1
  37. package/dist/index191.js +3 -3
  38. package/dist/index191.js.map +1 -1
  39. package/dist/index192.js +2 -2
  40. package/dist/index192.js.map +1 -1
  41. package/dist/index201.js +2 -2
  42. package/dist/index201.js.map +1 -1
  43. package/dist/index204.js +4 -4
  44. package/dist/index204.js.map +1 -1
  45. package/dist/index228.js +1 -1
  46. package/dist/index228.js.map +1 -1
  47. package/dist/index229.js +1 -1
  48. package/dist/index229.js.map +1 -1
  49. package/dist/index24.js +2 -2
  50. package/dist/index24.js.map +1 -1
  51. package/dist/index5.js +1 -1
  52. package/dist/index5.js.map +1 -1
  53. package/dist/styles.css +1 -1
  54. package/dist/wc/AICodeBlock.js +41 -41
  55. package/dist/wc/AICodeBlock.js.map +1 -1
  56. package/dist/wc/AIMermaidDiagram.js +7 -7
  57. package/dist/wc/AIMermaidDiagram.js.map +1 -1
  58. package/dist/wc/AIMessage.js +6 -6
  59. package/dist/wc/AIMessage.js.map +1 -1
  60. package/dist/wc/AISource.js +2 -2
  61. package/dist/wc/AISource.js.map +1 -1
  62. package/dist/wc/AIToolCall.js +1 -1
  63. package/dist/wc/AIToolCall.js.map +1 -1
  64. package/dist/wc/Breadcrumb.js +43 -43
  65. package/dist/wc/Breadcrumb.js.map +1 -1
  66. package/dist/wc/DropdownMenu.js +9 -9
  67. package/dist/wc/DropdownMenu.js.map +1 -1
  68. package/dist/wc/Kbd.js +22 -22
  69. package/dist/wc/Kbd.js.map +1 -1
  70. package/dist/wc/button.js +7 -7
  71. package/dist/wc/button.js.map +1 -1
  72. package/dist/wc/close-button.js +19 -19
  73. package/dist/wc/close-button.js.map +1 -1
  74. package/dist/wc/hf-ai-prompt-suggestion.js +14 -14
  75. package/dist/wc/hf-ai-prompt-suggestion.js.map +1 -1
  76. package/dist/wc/hf-ai-reasoning-block.js +13 -13
  77. package/dist/wc/hf-ai-reasoning-block.js.map +1 -1
  78. package/dist/wc/hf-ai-steps.js +53 -53
  79. package/dist/wc/hf-ai-steps.js.map +1 -1
  80. package/dist/wc/hf-ai-system-message.js +26 -26
  81. package/dist/wc/hf-ai-system-message.js.map +1 -1
  82. package/dist/wc/hf-code-snippet.js +35 -35
  83. package/dist/wc/hf-code-snippet.js.map +1 -1
  84. package/dist/wc/hf-command-menu.js +39 -39
  85. package/dist/wc/hf-command-menu.js.map +1 -1
  86. package/dist/wc/hf-data-table.js +3 -3
  87. package/dist/wc/hf-data-table.js.map +1 -1
  88. package/dist/wc/hf-display-value.js +50 -50
  89. package/dist/wc/hf-display-value.js.map +1 -1
  90. package/dist/wc/hf-nav-account-menu.js +5 -5
  91. package/dist/wc/hf-nav-account-menu.js.map +1 -1
  92. package/dist/wc/hf-rich-textarea.js +1 -1
  93. package/dist/wc/hf-rich-textarea.js.map +1 -1
  94. package/dist/wc/hf-steps.js +8 -8
  95. package/dist/wc/hf-steps.js.map +1 -1
  96. package/dist/wc/markdown-renderer.js +1 -1
  97. package/dist/wc/markdown-renderer.js.map +1 -1
  98. package/dist/wc/selection-group.js +26 -26
  99. package/dist/wc/selection-group.js.map +1 -1
  100. package/dist/wc/syntax-highlight.js +4 -4
  101. package/dist/wc/syntax-highlight.js.map +1 -1
  102. package/dist/wc/workflow-step-renderer.js +51 -51
  103. package/dist/wc/workflow-step-renderer.js.map +1 -1
  104. package/dist/wc-react/AICodeBlock.js +17 -17
  105. package/dist/wc-react/AICodeBlock.js.map +1 -1
  106. package/dist/wc-react/AIMermaidDiagram.js +16 -16
  107. package/dist/wc-react/AIMermaidDiagram.js.map +1 -1
  108. package/dist/wc-react/AIMessage.js +7 -7
  109. package/dist/wc-react/AIMessage.js.map +1 -1
  110. package/dist/wc-react/AISource.js +41 -41
  111. package/dist/wc-react/AISource.js.map +1 -1
  112. package/dist/wc-react/AIToolCall.js +6 -6
  113. package/dist/wc-react/AIToolCall.js.map +1 -1
  114. package/dist/wc-react/Breadcrumb.js +18 -18
  115. package/dist/wc-react/Breadcrumb.js.map +1 -1
  116. package/dist/wc-react/DropdownMenu.js +27 -27
  117. package/dist/wc-react/DropdownMenu.js.map +1 -1
  118. package/dist/wc-react/Kbd.js +17 -17
  119. package/dist/wc-react/Kbd.js.map +1 -1
  120. package/dist/wc-react/button.js +12 -12
  121. package/dist/wc-react/button.js.map +1 -1
  122. package/dist/wc-react/close-button.js +19 -19
  123. package/dist/wc-react/close-button.js.map +1 -1
  124. package/dist/wc-react/hf-ai-prompt-suggestion.js +1 -1
  125. package/dist/wc-react/hf-ai-prompt-suggestion.js.map +1 -1
  126. package/dist/wc-react/hf-ai-reasoning-block.js +1 -1
  127. package/dist/wc-react/hf-ai-reasoning-block.js.map +1 -1
  128. package/dist/wc-react/hf-ai-steps.js +33 -33
  129. package/dist/wc-react/hf-ai-steps.js.map +1 -1
  130. package/dist/wc-react/hf-ai-system-message.js +9 -9
  131. package/dist/wc-react/hf-ai-system-message.js.map +1 -1
  132. package/dist/wc-react/hf-code-snippet.js +3 -3
  133. package/dist/wc-react/hf-code-snippet.js.map +1 -1
  134. package/dist/wc-react/hf-command-menu.js +56 -56
  135. package/dist/wc-react/hf-command-menu.js.map +1 -1
  136. package/dist/wc-react/hf-data-table.js +3 -3
  137. package/dist/wc-react/hf-data-table.js.map +1 -1
  138. package/dist/wc-react/hf-display-value.js +58 -58
  139. package/dist/wc-react/hf-display-value.js.map +1 -1
  140. package/dist/wc-react/hf-nav-account-menu.js +7 -7
  141. package/dist/wc-react/hf-nav-account-menu.js.map +1 -1
  142. package/dist/wc-react/hf-rich-textarea.js +5 -5
  143. package/dist/wc-react/hf-rich-textarea.js.map +1 -1
  144. package/dist/wc-react/hf-steps.js +2 -2
  145. package/dist/wc-react/hf-steps.js.map +1 -1
  146. package/dist/wc-react/markdown-renderer.js +1 -1
  147. package/dist/wc-react/markdown-renderer.js.map +1 -1
  148. package/dist/wc-react/selection-group.js +7 -7
  149. package/dist/wc-react/selection-group.js.map +1 -1
  150. package/dist/wc-react/syntax-highlight.js +4 -4
  151. package/dist/wc-react/syntax-highlight.js.map +1 -1
  152. package/dist/wc-react/workflow-step-renderer.js +44 -44
  153. package/dist/wc-react/workflow-step-renderer.js.map +1 -1
  154. package/package.json +1 -1
  155. package/skills/humain-ui/SKILL.md +1 -1
  156. package/skills/humain-ui-wc/SKILL.md +1 -1
  157. package/skills/humain-ui-wc.skill +0 -0
  158. package/skills/humain-ui.skill +0 -0
  159. package/src/tokens.css +4 -0
@@ -1 +1 @@
1
- {"version":3,"file":"index201.js","names":[],"sources":["../src/components/organisms/content/Steps/Steps.tsx"],"sourcesContent":["import { cva } from 'class-variance-authority';\nimport { Check } from 'lucide-react';\nimport * as React from 'react';\nimport { createSafeContext } from '@/lib/create-safe-context';\nimport { cn, extractText } from '@/lib/utils';\n\n/* -----------------------------------------------------------------------------\n * Types\n * -------------------------------------------------------------------------- */\n\nexport type StepStatus = 'complete' | 'active' | 'incomplete';\n\nexport interface StepData {\n label: string;\n subtext?: string;\n}\n\nexport interface StepsProps {\n /** Steps data for flat API */\n steps?: StepData[];\n /** Current step index (0-based) for flat API */\n currentStep?: number;\n /** Orientation of the steps */\n orientation?: 'horizontal' | 'vertical';\n /** Shape of step indicators */\n shape?: 'rounded' | 'round';\n /** Type of bullet content */\n bulletType?: 'text' | 'icon';\n /** Callback when a step is clicked */\n onStepClick?: (index: number) => void;\n /** Children for compound API */\n children?: React.ReactNode;\n /** Additional className */\n className?: string;\n}\n\nexport interface StepsItemProps {\n /** Override auto-calculated status */\n status?: StepStatus;\n /** Click handler for this step */\n onClick?: () => void;\n /** Step label content */\n children: React.ReactNode;\n /** Additional className */\n className?: string;\n}\n\nexport interface StepsSubtextProps {\n children: React.ReactNode;\n className?: string;\n}\n\n/* -----------------------------------------------------------------------------\n * Variants\n * -------------------------------------------------------------------------- */\n\nconst stepIndicatorVariants = cva(\n 'flex items-center justify-center shrink-0 size-[38px] font-medium text-lg transition-all duration-200 ease-out motion-reduce:transition-none',\n {\n variants: {\n shape: {\n rounded: 'rounded-lg',\n round: 'rounded-full',\n },\n status: {\n complete: 'bg-primary text-primary-foreground shadow-sm',\n active: 'bg-background border-2 border-primary text-primary shadow-sm',\n incomplete: 'bg-accent text-muted-foreground',\n },\n },\n defaultVariants: {\n shape: 'rounded',\n status: 'incomplete',\n },\n },\n);\n\nconst stepConnectorVariants = cva(\n 'shrink-0 transition-colors duration-200 ease-out motion-reduce:transition-none',\n {\n variants: {\n orientation: {\n // Horizontal: fluid width fills available space; mt-[18px] centers 2px line with 38px indicator\n horizontal: 'h-0.5 flex-1 min-w-4 mx-2 mt-[18px]',\n // Vertical: fixed size, centered under 38px indicator\n vertical: 'w-0.5 h-[30px] my-1 ml-[18px]',\n },\n status: {\n complete: 'bg-primary',\n incomplete: 'bg-border',\n },\n },\n defaultVariants: {\n orientation: 'horizontal',\n status: 'incomplete',\n },\n },\n);\n\nconst stepLabelVariants = cva('text-base leading-6', {\n variants: {\n status: {\n complete: 'text-card-foreground',\n active: 'text-card-foreground',\n incomplete: 'text-muted-foreground',\n },\n },\n defaultVariants: {\n status: 'incomplete',\n },\n});\n\nconst stepSubtextVariants = cva('text-sm leading-5 text-muted-foreground');\n\n/* -----------------------------------------------------------------------------\n * Context\n * -------------------------------------------------------------------------- */\n\ninterface StepsContextValue {\n orientation: 'horizontal' | 'vertical';\n shape: 'rounded' | 'round';\n bulletType: 'text' | 'icon';\n onStepClick?: (index: number) => void;\n getStepStatus: (index: number) => StepStatus;\n}\n\nconst [StepsContext, useStepsContext] =\n createSafeContext<StepsContextValue>('Steps');\n\n/** Per-item index context — injected by Steps parent via Children.map or flat API */\nconst StepIndexContext = React.createContext<number>(0);\n\n/* -----------------------------------------------------------------------------\n * Sub-components\n * -------------------------------------------------------------------------- */\n\ninterface StepIndicatorProps {\n index: number;\n status: StepStatus;\n shape: 'rounded' | 'round';\n bulletType: 'text' | 'icon';\n}\n\nfunction StepIndicatorContent({\n index,\n status,\n shape,\n bulletType,\n}: StepIndicatorProps) {\n if (bulletType === 'icon') {\n if (status === 'complete') {\n return <Check className=\"size-[22px] delight-check-draw\" />;\n }\n if (status === 'active') {\n return (\n <div\n className={cn(\n 'size-5 bg-primary',\n shape === 'rounded' ? 'rounded-sm' : 'rounded-full',\n )}\n />\n );\n }\n\n return <div className=\"size-1.5 rounded-full bg-current\" />;\n }\n\n return index + 1;\n}\n\nfunction StepIndicator({\n index,\n status,\n shape,\n bulletType,\n}: StepIndicatorProps) {\n return (\n <div\n data-slot=\"steps-indicator\"\n aria-hidden=\"true\"\n className={cn(\n stepIndicatorVariants({ shape, status }),\n status === 'complete' && 'delight-check-bounce',\n status === 'active' && 'delight-pulse-once',\n )}\n >\n <StepIndicatorContent\n index={index}\n status={status}\n shape={shape}\n bulletType={bulletType}\n />\n </div>\n );\n}\n\nStepIndicator.displayName = 'StepIndicator';\n\ninterface StepConnectorProps {\n orientation: 'horizontal' | 'vertical';\n isComplete: boolean;\n}\n\nfunction StepConnector({ orientation, isComplete }: StepConnectorProps) {\n return (\n <div\n data-slot=\"steps-connector\"\n aria-hidden=\"true\"\n className={cn(\n stepConnectorVariants({\n orientation,\n status: isComplete ? 'complete' : 'incomplete',\n }),\n isComplete && 'delight-connector-fill',\n )}\n />\n );\n}\n\nStepConnector.displayName = 'StepConnector';\n\nfunction StepsSubtext({ children, className }: StepsSubtextProps) {\n return (\n <span\n data-slot=\"steps-subtext\"\n className={cn(stepSubtextVariants(), className)}\n >\n {children}\n </span>\n );\n}\n\nStepsSubtext.displayName = 'Steps.Subtext';\n\nfunction StepsItem({\n status: statusOverride,\n onClick,\n children,\n className,\n}: StepsItemProps) {\n const ctx = useStepsContext();\n const index = React.useContext(StepIndexContext);\n const status = statusOverride ?? ctx.getStepStatus(index);\n const isFirst = index === 0;\n const handleClick =\n onClick ?? (ctx.onStepClick ? () => ctx.onStepClick?.(index) : undefined);\n\n // Extract subtext from children\n let label: React.ReactNode = null;\n let subtext: React.ReactNode = null;\n\n React.Children.forEach(children, (child) => {\n if (React.isValidElement(child) && child.type === StepsSubtext) {\n subtext = child;\n } else if (child != null && child !== false) {\n label = child;\n }\n });\n\n // Connector colored based on previous step's completion (source step, not destination)\n const prevStepStatus = !isFirst ? ctx.getStepStatus(index - 1) : undefined;\n const connector = !isFirst && (\n <StepConnector\n orientation={ctx.orientation}\n isComplete={prevStepStatus === 'complete'}\n />\n );\n\n const isHorizontal = ctx.orientation === 'horizontal';\n\n // Build indicator element\n const indicator = (\n <StepIndicator\n index={index}\n status={status}\n shape={ctx.shape}\n bulletType={ctx.bulletType}\n />\n );\n\n // Build label element\n // In horizontal mode, w-0 ensures the label doesn't affect the indicator column width.\n // The text overflows visually (centered under the 38px indicator) but the layout\n // width stays fixed, keeping all connectors equally spaced (matching Figma spec).\n const labelElement = (\n <div\n data-slot=\"steps-label\"\n className={cn(\n 'flex flex-col',\n isHorizontal\n ? 'items-center gap-0.5 text-center w-0 whitespace-nowrap'\n : 'items-start gap-0.5 ml-2.5',\n )}\n >\n <span className={stepLabelVariants({ status })}>{label}</span>\n {subtext}\n </div>\n );\n\n // Layout differs by orientation:\n // - Horizontal: connector + (indicator column), items-start so indicators align at top\n // - Vertical: connector above, indicator + label in row\n const content = isHorizontal ? (\n <div className=\"flex w-full items-start\">\n {connector}\n <div className=\"flex flex-col items-center\">\n {indicator}\n {labelElement}\n </div>\n </div>\n ) : (\n <div className=\"flex flex-col items-start\">\n {connector}\n <div className=\"flex items-center\">\n {indicator}\n {labelElement}\n </div>\n </div>\n );\n\n const labelText = React.useMemo(() => extractText(label), [label]);\n const statusSuffix =\n status === 'complete'\n ? ', completed'\n : status === 'active'\n ? ', current'\n : '';\n\n return (\n <li\n data-slot=\"steps-item\"\n aria-current={status === 'active' ? 'step' : undefined}\n aria-label={\n !handleClick && labelText\n ? `Step ${index + 1}: ${labelText}${statusSuffix}`\n : undefined\n }\n className={cn(\n isHorizontal && !isFirst && 'flex-1',\n !handleClick && className,\n )}\n >\n {handleClick ? (\n <button\n type=\"button\"\n onClick={handleClick}\n aria-label={`Step ${index + 1}: ${labelText || ''}${statusSuffix}`}\n className={cn(\n 'cursor-pointer',\n isHorizontal && 'w-full',\n className,\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-2 focus-visible:ring-offset-background rounded-sm',\n )}\n >\n {content}\n </button>\n ) : (\n content\n )}\n </li>\n );\n}\n\nStepsItem.displayName = 'Steps.Item';\n\n/* -----------------------------------------------------------------------------\n * Main Component\n * -------------------------------------------------------------------------- */\n\n/**\n * Steps displays a multi-step progress indicator for wizards and workflows.\n * Supports horizontal/vertical orientation, numbered or icon bullets, and clickable steps.\n *\n * @llms Wizard/workflow progress with horizontal/vertical layout, numbered or icon steps\n * @example\n * ```tsx\n * <Steps\n * steps={[{ label: 'Details' }, { label: 'Payment' }, { label: 'Confirm' }]}\n * currentStep={1}\n * orientation=\"horizontal\"\n * />\n * ```\n */\nfunction Steps({\n steps,\n currentStep = 0,\n orientation = 'horizontal',\n shape = 'rounded',\n bulletType = 'text',\n onStepClick,\n children,\n className,\n}: StepsProps) {\n const getStepStatus = React.useCallback(\n (index: number): StepStatus => {\n if (index < currentStep) return 'complete';\n if (index === currentStep) return 'active';\n return 'incomplete';\n },\n [currentStep],\n );\n\n const contextValue = React.useMemo<StepsContextValue>(\n () => ({\n orientation,\n shape,\n bulletType,\n onStepClick,\n getStepStatus,\n }),\n [orientation, shape, bulletType, onStepClick, getStepStatus],\n );\n\n // Determine if using flat API or compound API\n const useCompoundAPI = !steps && React.Children.count(children) > 0;\n\n const renderFlatAPI = () => {\n if (!steps || steps.length === 0) return null;\n\n return steps.map((step, index) => (\n <StepIndexContext.Provider key={`${index}-${step.label}`} value={index}>\n <StepsItem>\n {step.label}\n {step.subtext && <StepsSubtext>{step.subtext}</StepsSubtext>}\n </StepsItem>\n </StepIndexContext.Provider>\n ));\n };\n\n const renderCompoundAPI = () => {\n return React.Children.map(children, (child, index) => (\n <StepIndexContext.Provider value={index}>\n {child}\n </StepIndexContext.Provider>\n ));\n };\n\n return (\n <StepsContext.Provider value={contextValue}>\n <nav\n aria-label=\"Progress steps\"\n data-slot=\"steps\"\n // biome-ignore lint/a11y/noNoninteractiveTabindex: Focusable scroll region satisfies axe scrollable-region-focusable.\n tabIndex={0}\n className={cn(\n 'overflow-x-auto focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring',\n className,\n )}\n >\n <ol\n data-slot=\"steps-list\"\n className={cn(\n 'flex',\n orientation === 'horizontal'\n ? 'flex-row items-start px-4'\n : 'flex-col items-start',\n )}\n >\n {useCompoundAPI ? renderCompoundAPI() : renderFlatAPI()}\n </ol>\n </nav>\n </StepsContext.Provider>\n );\n}\n\nSteps.displayName = 'Steps';\n\n/* -----------------------------------------------------------------------------\n * Compound Export\n * -------------------------------------------------------------------------- */\n\n/**\n * @llms Wizard/workflow progress with horizontal/vertical layout, numbered or icon steps\n */\nexport const StepsCompound = Object.assign(Steps, {\n Item: StepsItem,\n Subtext: StepsSubtext,\n});\n\nexport {\n StepsCompound as Steps,\n StepsItem,\n StepsSubtext,\n stepConnectorVariants,\n stepIndicatorVariants,\n stepLabelVariants,\n stepSubtextVariants,\n};\n"],"mappings":";;;;;;;AAwDA,IAAM,wBAAwB,IAC5B,gJACA;CACE,UAAU;EACR,OAAO;GACL,SAAS;GACT,OAAO;EACT;EACA,QAAQ;GACN,UAAU;GACV,QAAQ;GACR,YAAY;EACd;CACF;CACA,iBAAiB;EACf,OAAO;EACP,QAAQ;CACV;AACF,CACF;AAEA,IAAM,wBAAwB,IAC5B,kFACA;CACE,UAAU;EACR,aAAa;GAEX,YAAY;GAEZ,UAAU;EACZ;EACA,QAAQ;GACN,UAAU;GACV,YAAY;EACd;CACF;CACA,iBAAiB;EACf,aAAa;EACb,QAAQ;CACV;AACF,CACF;AAEA,IAAM,oBAAoB,IAAI,uBAAuB;CACnD,UAAU,EACR,QAAQ;EACN,UAAU;EACV,QAAQ;EACR,YAAY;CACd,EACF;CACA,iBAAiB,EACf,QAAQ,aACV;AACF,CAAC;AAED,IAAM,sBAAsB,IAAI,yCAAyC;AAczE,IAAM,CAAC,cAAc,mBACnB,kBAAqC,OAAO;;AAG9C,IAAM,mBAAmB,QAAM,cAAsB,CAAC;AAatD,SAAS,qBAAqB,EAC5B,OACA,QACA,OACA,cACqB;CACrB,IAAI,eAAe,QAAQ;EACzB,IAAI,WAAW,YACb,OAAO,oBAAC,OAAD,EAAO,WAAU,iCAAkC,CAAA;EAE5D,IAAI,WAAW,UACb,OACE,oBAAC,OAAD,EACE,WAAW,GACT,qBACA,UAAU,YAAY,eAAe,cACvC,EACD,CAAA;EAIL,OAAO,oBAAC,OAAD,EAAK,WAAU,mCAAoC,CAAA;CAC5D;CAEA,OAAO,QAAQ;AACjB;AAEA,SAAS,cAAc,EACrB,OACA,QACA,OACA,cACqB;CACrB,OACE,oBAAC,OAAD;EACE,aAAU;EACV,eAAY;EACZ,WAAW,GACT,sBAAsB;GAAE;GAAO;EAAO,CAAC,GACvC,WAAW,cAAc,wBACzB,WAAW,YAAY,oBACzB;YAEA,oBAAC,sBAAD;GACS;GACC;GACD;GACK;EACb,CAAA;CACE,CAAA;AAET;AAEA,cAAc,cAAc;AAO5B,SAAS,cAAc,EAAE,aAAa,cAAkC;CACtE,OACE,oBAAC,OAAD;EACE,aAAU;EACV,eAAY;EACZ,WAAW,GACT,sBAAsB;GACpB;GACA,QAAQ,aAAa,aAAa;EACpC,CAAC,GACD,cAAc,wBAChB;CACD,CAAA;AAEL;AAEA,cAAc,cAAc;AAE5B,SAAS,aAAa,EAAE,UAAU,aAAgC;CAChE,OACE,oBAAC,QAAD;EACE,aAAU;EACV,WAAW,GAAG,oBAAoB,GAAG,SAAS;EAE7C;CACG,CAAA;AAEV;AAEA,aAAa,cAAc;AAE3B,SAAS,UAAU,EACjB,QAAQ,gBACR,SACA,UACA,aACiB;CACjB,MAAM,MAAM,gBAAgB;CAC5B,MAAM,QAAQ,QAAM,WAAW,gBAAgB;CAC/C,MAAM,SAAS,kBAAkB,IAAI,cAAc,KAAK;CACxD,MAAM,UAAU,UAAU;CAC1B,MAAM,cACJ,YAAY,IAAI,oBAAoB,IAAI,cAAc,KAAK,IAAI,KAAA;CAGjE,IAAI,QAAyB;CAC7B,IAAI,UAA2B;CAE/B,QAAM,SAAS,QAAQ,WAAW,UAAU;EAC1C,IAAI,QAAM,eAAe,KAAK,KAAK,MAAM,SAAS,cAChD,UAAU;OACL,IAAI,SAAS,QAAQ,UAAU,OACpC,QAAQ;CAEZ,CAAC;CAGD,MAAM,iBAAiB,CAAC,UAAU,IAAI,cAAc,QAAQ,CAAC,IAAI,KAAA;CACjE,MAAM,YAAY,CAAC,WACjB,oBAAC,eAAD;EACE,aAAa,IAAI;EACjB,YAAY,mBAAmB;CAChC,CAAA;CAGH,MAAM,eAAe,IAAI,gBAAgB;CAGzC,MAAM,YACJ,oBAAC,eAAD;EACS;EACC;EACR,OAAO,IAAI;EACX,YAAY,IAAI;CACjB,CAAA;CAOH,MAAM,eACJ,qBAAC,OAAD;EACE,aAAU;EACV,WAAW,GACT,iBACA,eACI,2DACA,4BACN;YAPF,CASE,oBAAC,QAAD;GAAM,WAAW,kBAAkB,EAAE,OAAO,CAAC;aAAI;EAAY,CAAA,GAC5D,OACE;;CAMP,MAAM,UAAU,eACd,qBAAC,OAAD;EAAK,WAAU;YAAf,CACG,WACD,qBAAC,OAAD;GAAK,WAAU;aAAf,CACG,WACA,YACE;IACF;MAEL,qBAAC,OAAD;EAAK,WAAU;YAAf,CACG,WACD,qBAAC,OAAD;GAAK,WAAU;aAAf,CACG,WACA,YACE;IACF;;CAGP,MAAM,YAAY,QAAM,cAAc,YAAY,KAAK,GAAG,CAAC,KAAK,CAAC;CACjE,MAAM,eACJ,WAAW,aACP,gBACA,WAAW,WACT,cACA;CAER,OACE,oBAAC,MAAD;EACE,aAAU;EACV,gBAAc,WAAW,WAAW,SAAS,KAAA;EAC7C,cACE,CAAC,eAAe,YACZ,QAAQ,QAAQ,EAAE,IAAI,YAAY,iBAClC,KAAA;EAEN,WAAW,GACT,gBAAgB,CAAC,WAAW,UAC5B,CAAC,eAAe,SAClB;YAEC,cACC,oBAAC,UAAD;GACE,MAAK;GACL,SAAS;GACT,cAAY,QAAQ,QAAQ,EAAE,IAAI,aAAa,KAAK;GACpD,WAAW,GACT,kBACA,gBAAgB,UAChB,WACA,wJACF;aAEC;EACK,CAAA,IAER;CAEA,CAAA;AAER;AAEA,UAAU,cAAc;;;;;;;;;;;;;;;AAoBxB,SAAS,MAAM,EACb,OACA,cAAc,GACd,cAAc,cACd,QAAQ,WACR,aAAa,QACb,aACA,UACA,aACa;CACb,MAAM,gBAAgB,QAAM,aACzB,UAA8B;EAC7B,IAAI,QAAQ,aAAa,OAAO;EAChC,IAAI,UAAU,aAAa,OAAO;EAClC,OAAO;CACT,GACA,CAAC,WAAW,CACd;CAEA,MAAM,eAAe,QAAM,eAClB;EACL;EACA;EACA;EACA;EACA;CACF,IACA;EAAC;EAAa;EAAO;EAAY;EAAa;CAAa,CAC7D;CAGA,MAAM,iBAAiB,CAAC,SAAS,QAAM,SAAS,MAAM,QAAQ,IAAI;CAElE,MAAM,sBAAsB;EAC1B,IAAI,CAAC,SAAS,MAAM,WAAW,GAAG,OAAO;EAEzC,OAAO,MAAM,KAAK,MAAM,UACtB,oBAAC,iBAAiB,UAAlB;GAA0D,OAAO;aAC/D,qBAAC,WAAD,EAAA,UAAA,CACG,KAAK,OACL,KAAK,WAAW,oBAAC,cAAD,EAAA,UAAe,KAAK,QAAsB,CAAA,CAClD,EAAA,CAAA;EACc,GALK,GAAG,MAAM,GAAG,KAAK,OAKtB,CAC5B;CACH;CAEA,MAAM,0BAA0B;EAC9B,OAAO,QAAM,SAAS,IAAI,WAAW,OAAO,UAC1C,oBAAC,iBAAiB,UAAlB;GAA2B,OAAO;aAC/B;EACwB,CAAA,CAC5B;CACH;CAEA,OACE,oBAAC,aAAa,UAAd;EAAuB,OAAO;YAC5B,oBAAC,OAAD;GACE,cAAW;GACX,aAAU;GAEV,UAAU;GACV,WAAW,GACT,qGACA,SACF;aAEA,oBAAC,MAAD;IACE,aAAU;IACV,WAAW,GACT,QACA,gBAAgB,eACZ,8BACA,sBACN;cAEC,iBAAiB,kBAAkB,IAAI,cAAc;GACpD,CAAA;EACD,CAAA;CACgB,CAAA;AAE3B;AAEA,MAAM,cAAc;;;;AASpB,IAAa,gBAAgB,OAAO,OAAO,OAAO;CAChD,MAAM;CACN,SAAS;AACX,CAAC"}
1
+ {"version":3,"file":"index201.js","names":[],"sources":["../src/components/organisms/content/Steps/Steps.tsx"],"sourcesContent":["import { cva } from 'class-variance-authority';\nimport { Check } from 'lucide-react';\nimport * as React from 'react';\nimport { createSafeContext } from '@/lib/create-safe-context';\nimport { cn, extractText } from '@/lib/utils';\n\n/* -----------------------------------------------------------------------------\n * Types\n * -------------------------------------------------------------------------- */\n\nexport type StepStatus = 'complete' | 'active' | 'incomplete';\n\nexport interface StepData {\n label: string;\n subtext?: string;\n}\n\nexport interface StepsProps {\n /** Steps data for flat API */\n steps?: StepData[];\n /** Current step index (0-based) for flat API */\n currentStep?: number;\n /** Orientation of the steps */\n orientation?: 'horizontal' | 'vertical';\n /** Shape of step indicators */\n shape?: 'rounded' | 'round';\n /** Type of bullet content */\n bulletType?: 'text' | 'icon';\n /** Callback when a step is clicked */\n onStepClick?: (index: number) => void;\n /** Children for compound API */\n children?: React.ReactNode;\n /** Additional className */\n className?: string;\n}\n\nexport interface StepsItemProps {\n /** Override auto-calculated status */\n status?: StepStatus;\n /** Click handler for this step */\n onClick?: () => void;\n /** Step label content */\n children: React.ReactNode;\n /** Additional className */\n className?: string;\n}\n\nexport interface StepsSubtextProps {\n children: React.ReactNode;\n className?: string;\n}\n\n/* -----------------------------------------------------------------------------\n * Variants\n * -------------------------------------------------------------------------- */\n\nconst stepIndicatorVariants = cva(\n 'flex items-center justify-center shrink-0 size-[38px] font-medium text-lg transition-all duration-200 ease-out motion-reduce:transition-none',\n {\n variants: {\n shape: {\n rounded: 'rounded-lg',\n round: 'rounded-full',\n },\n status: {\n complete: 'bg-primary text-primary-foreground shadow-sm',\n active: 'bg-background border-2 border-primary text-primary shadow-sm',\n incomplete: 'bg-accent text-muted-foreground',\n },\n },\n defaultVariants: {\n shape: 'rounded',\n status: 'incomplete',\n },\n },\n);\n\nconst stepConnectorVariants = cva(\n 'shrink-0 transition-colors duration-200 ease-out motion-reduce:transition-none',\n {\n variants: {\n orientation: {\n // Horizontal: fluid width fills available space; mt-[18px] centers 2px line with 38px indicator\n horizontal: 'h-0.5 flex-1 min-w-4 mx-2 mt-[18px]',\n // Vertical: fixed size, centered under 38px indicator\n vertical: 'w-0.5 h-[30px] my-1 ml-[18px]',\n },\n status: {\n complete: 'bg-primary',\n incomplete: 'bg-border',\n },\n },\n defaultVariants: {\n orientation: 'horizontal',\n status: 'incomplete',\n },\n },\n);\n\nconst stepLabelVariants = cva('text-base leading-6', {\n variants: {\n status: {\n complete: 'text-card-foreground',\n active: 'text-card-foreground',\n incomplete: 'text-secondary-foreground',\n },\n },\n defaultVariants: {\n status: 'incomplete',\n },\n});\n\nconst stepSubtextVariants = cva('text-sm leading-5 text-secondary-foreground');\n\n/* -----------------------------------------------------------------------------\n * Context\n * -------------------------------------------------------------------------- */\n\ninterface StepsContextValue {\n orientation: 'horizontal' | 'vertical';\n shape: 'rounded' | 'round';\n bulletType: 'text' | 'icon';\n onStepClick?: (index: number) => void;\n getStepStatus: (index: number) => StepStatus;\n}\n\nconst [StepsContext, useStepsContext] =\n createSafeContext<StepsContextValue>('Steps');\n\n/** Per-item index context — injected by Steps parent via Children.map or flat API */\nconst StepIndexContext = React.createContext<number>(0);\n\n/* -----------------------------------------------------------------------------\n * Sub-components\n * -------------------------------------------------------------------------- */\n\ninterface StepIndicatorProps {\n index: number;\n status: StepStatus;\n shape: 'rounded' | 'round';\n bulletType: 'text' | 'icon';\n}\n\nfunction StepIndicatorContent({\n index,\n status,\n shape,\n bulletType,\n}: StepIndicatorProps) {\n if (bulletType === 'icon') {\n if (status === 'complete') {\n return <Check className=\"size-[22px] delight-check-draw\" />;\n }\n if (status === 'active') {\n return (\n <div\n className={cn(\n 'size-5 bg-primary',\n shape === 'rounded' ? 'rounded-sm' : 'rounded-full',\n )}\n />\n );\n }\n\n return <div className=\"size-1.5 rounded-full bg-current\" />;\n }\n\n return index + 1;\n}\n\nfunction StepIndicator({\n index,\n status,\n shape,\n bulletType,\n}: StepIndicatorProps) {\n return (\n <div\n data-slot=\"steps-indicator\"\n aria-hidden=\"true\"\n className={cn(\n stepIndicatorVariants({ shape, status }),\n status === 'complete' && 'delight-check-bounce',\n status === 'active' && 'delight-pulse-once',\n )}\n >\n <StepIndicatorContent\n index={index}\n status={status}\n shape={shape}\n bulletType={bulletType}\n />\n </div>\n );\n}\n\nStepIndicator.displayName = 'StepIndicator';\n\ninterface StepConnectorProps {\n orientation: 'horizontal' | 'vertical';\n isComplete: boolean;\n}\n\nfunction StepConnector({ orientation, isComplete }: StepConnectorProps) {\n return (\n <div\n data-slot=\"steps-connector\"\n aria-hidden=\"true\"\n className={cn(\n stepConnectorVariants({\n orientation,\n status: isComplete ? 'complete' : 'incomplete',\n }),\n isComplete && 'delight-connector-fill',\n )}\n />\n );\n}\n\nStepConnector.displayName = 'StepConnector';\n\nfunction StepsSubtext({ children, className }: StepsSubtextProps) {\n return (\n <span\n data-slot=\"steps-subtext\"\n className={cn(stepSubtextVariants(), className)}\n >\n {children}\n </span>\n );\n}\n\nStepsSubtext.displayName = 'Steps.Subtext';\n\nfunction StepsItem({\n status: statusOverride,\n onClick,\n children,\n className,\n}: StepsItemProps) {\n const ctx = useStepsContext();\n const index = React.useContext(StepIndexContext);\n const status = statusOverride ?? ctx.getStepStatus(index);\n const isFirst = index === 0;\n const handleClick =\n onClick ?? (ctx.onStepClick ? () => ctx.onStepClick?.(index) : undefined);\n\n // Extract subtext from children\n let label: React.ReactNode = null;\n let subtext: React.ReactNode = null;\n\n React.Children.forEach(children, (child) => {\n if (React.isValidElement(child) && child.type === StepsSubtext) {\n subtext = child;\n } else if (child != null && child !== false) {\n label = child;\n }\n });\n\n // Connector colored based on previous step's completion (source step, not destination)\n const prevStepStatus = !isFirst ? ctx.getStepStatus(index - 1) : undefined;\n const connector = !isFirst && (\n <StepConnector\n orientation={ctx.orientation}\n isComplete={prevStepStatus === 'complete'}\n />\n );\n\n const isHorizontal = ctx.orientation === 'horizontal';\n\n // Build indicator element\n const indicator = (\n <StepIndicator\n index={index}\n status={status}\n shape={ctx.shape}\n bulletType={ctx.bulletType}\n />\n );\n\n // Build label element\n // In horizontal mode, w-0 ensures the label doesn't affect the indicator column width.\n // The text overflows visually (centered under the 38px indicator) but the layout\n // width stays fixed, keeping all connectors equally spaced (matching Figma spec).\n const labelElement = (\n <div\n data-slot=\"steps-label\"\n className={cn(\n 'flex flex-col',\n isHorizontal\n ? 'items-center gap-0.5 text-center w-0 whitespace-nowrap'\n : 'items-start gap-0.5 ml-2.5',\n )}\n >\n <span className={stepLabelVariants({ status })}>{label}</span>\n {subtext}\n </div>\n );\n\n // Layout differs by orientation:\n // - Horizontal: connector + (indicator column), items-start so indicators align at top\n // - Vertical: connector above, indicator + label in row\n const content = isHorizontal ? (\n <div className=\"flex w-full items-start\">\n {connector}\n <div className=\"flex flex-col items-center\">\n {indicator}\n {labelElement}\n </div>\n </div>\n ) : (\n <div className=\"flex flex-col items-start\">\n {connector}\n <div className=\"flex items-center\">\n {indicator}\n {labelElement}\n </div>\n </div>\n );\n\n const labelText = React.useMemo(() => extractText(label), [label]);\n const statusSuffix =\n status === 'complete'\n ? ', completed'\n : status === 'active'\n ? ', current'\n : '';\n\n return (\n <li\n data-slot=\"steps-item\"\n aria-current={status === 'active' ? 'step' : undefined}\n aria-label={\n !handleClick && labelText\n ? `Step ${index + 1}: ${labelText}${statusSuffix}`\n : undefined\n }\n className={cn(\n isHorizontal && !isFirst && 'flex-1',\n !handleClick && className,\n )}\n >\n {handleClick ? (\n <button\n type=\"button\"\n onClick={handleClick}\n aria-label={`Step ${index + 1}: ${labelText || ''}${statusSuffix}`}\n className={cn(\n 'cursor-pointer',\n isHorizontal && 'w-full',\n className,\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-2 focus-visible:ring-offset-background rounded-sm',\n )}\n >\n {content}\n </button>\n ) : (\n content\n )}\n </li>\n );\n}\n\nStepsItem.displayName = 'Steps.Item';\n\n/* -----------------------------------------------------------------------------\n * Main Component\n * -------------------------------------------------------------------------- */\n\n/**\n * Steps displays a multi-step progress indicator for wizards and workflows.\n * Supports horizontal/vertical orientation, numbered or icon bullets, and clickable steps.\n *\n * @llms Wizard/workflow progress with horizontal/vertical layout, numbered or icon steps\n * @example\n * ```tsx\n * <Steps\n * steps={[{ label: 'Details' }, { label: 'Payment' }, { label: 'Confirm' }]}\n * currentStep={1}\n * orientation=\"horizontal\"\n * />\n * ```\n */\nfunction Steps({\n steps,\n currentStep = 0,\n orientation = 'horizontal',\n shape = 'rounded',\n bulletType = 'text',\n onStepClick,\n children,\n className,\n}: StepsProps) {\n const getStepStatus = React.useCallback(\n (index: number): StepStatus => {\n if (index < currentStep) return 'complete';\n if (index === currentStep) return 'active';\n return 'incomplete';\n },\n [currentStep],\n );\n\n const contextValue = React.useMemo<StepsContextValue>(\n () => ({\n orientation,\n shape,\n bulletType,\n onStepClick,\n getStepStatus,\n }),\n [orientation, shape, bulletType, onStepClick, getStepStatus],\n );\n\n // Determine if using flat API or compound API\n const useCompoundAPI = !steps && React.Children.count(children) > 0;\n\n const renderFlatAPI = () => {\n if (!steps || steps.length === 0) return null;\n\n return steps.map((step, index) => (\n <StepIndexContext.Provider key={`${index}-${step.label}`} value={index}>\n <StepsItem>\n {step.label}\n {step.subtext && <StepsSubtext>{step.subtext}</StepsSubtext>}\n </StepsItem>\n </StepIndexContext.Provider>\n ));\n };\n\n const renderCompoundAPI = () => {\n return React.Children.map(children, (child, index) => (\n <StepIndexContext.Provider value={index}>\n {child}\n </StepIndexContext.Provider>\n ));\n };\n\n return (\n <StepsContext.Provider value={contextValue}>\n <nav\n aria-label=\"Progress steps\"\n data-slot=\"steps\"\n // biome-ignore lint/a11y/noNoninteractiveTabindex: Focusable scroll region satisfies axe scrollable-region-focusable.\n tabIndex={0}\n className={cn(\n 'overflow-x-auto focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring',\n className,\n )}\n >\n <ol\n data-slot=\"steps-list\"\n className={cn(\n 'flex',\n orientation === 'horizontal'\n ? 'flex-row items-start px-4'\n : 'flex-col items-start',\n )}\n >\n {useCompoundAPI ? renderCompoundAPI() : renderFlatAPI()}\n </ol>\n </nav>\n </StepsContext.Provider>\n );\n}\n\nSteps.displayName = 'Steps';\n\n/* -----------------------------------------------------------------------------\n * Compound Export\n * -------------------------------------------------------------------------- */\n\n/**\n * @llms Wizard/workflow progress with horizontal/vertical layout, numbered or icon steps\n */\nexport const StepsCompound = Object.assign(Steps, {\n Item: StepsItem,\n Subtext: StepsSubtext,\n});\n\nexport {\n StepsCompound as Steps,\n StepsItem,\n StepsSubtext,\n stepConnectorVariants,\n stepIndicatorVariants,\n stepLabelVariants,\n stepSubtextVariants,\n};\n"],"mappings":"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"}
package/dist/index204.js CHANGED
@@ -41,7 +41,7 @@ function FooterNavIcon({ children, className }) {
41
41
  FooterNavIcon.displayName = "CommandMenu.FooterNavIcon";
42
42
  function FooterNavText({ children, className }) {
43
43
  return /* @__PURE__ */ jsx("span", {
44
- className: cn("text-sm font-semibold text-text-quaternary", className),
44
+ className: cn("text-sm font-semibold text-secondary-foreground", className),
45
45
  children
46
46
  });
47
47
  }
@@ -50,19 +50,19 @@ var defaultFooterHints = [
50
50
  {
51
51
  keys: /* @__PURE__ */ jsxs("div", {
52
52
  className: "flex items-center gap-1",
53
- children: [/* @__PURE__ */ jsx(FooterNavIcon, { children: /* @__PURE__ */ jsx(ArrowUp, { className: "size-2.5 text-text-quaternary" }) }), /* @__PURE__ */ jsx(FooterNavIcon, { children: /* @__PURE__ */ jsx(ArrowDown, { className: "size-2.5 text-text-quaternary" }) })]
53
+ children: [/* @__PURE__ */ jsx(FooterNavIcon, { children: /* @__PURE__ */ jsx(ArrowUp, { className: "size-2.5 text-secondary-foreground" }) }), /* @__PURE__ */ jsx(FooterNavIcon, { children: /* @__PURE__ */ jsx(ArrowDown, { className: "size-2.5 text-secondary-foreground" }) })]
54
54
  }),
55
55
  label: "to navigate"
56
56
  },
57
57
  {
58
- keys: /* @__PURE__ */ jsx(FooterNavIcon, { children: /* @__PURE__ */ jsx(CornerDownLeft, { className: "size-2.5 text-text-quaternary" }) }),
58
+ keys: /* @__PURE__ */ jsx(FooterNavIcon, { children: /* @__PURE__ */ jsx(CornerDownLeft, { className: "size-2.5 text-secondary-foreground" }) }),
59
59
  label: "to select"
60
60
  },
61
61
  {
62
62
  keys: /* @__PURE__ */ jsx(FooterNavIcon, {
63
63
  className: "px-1.5 py-1",
64
64
  children: /* @__PURE__ */ jsx("span", {
65
- className: "text-xs font-semibold text-text-quaternary",
65
+ className: "text-xs font-semibold text-secondary-foreground",
66
66
  children: "esc"
67
67
  })
68
68
  }),
@@ -1 +1 @@
1
- {"version":3,"file":"index204.js","names":[],"sources":["../src/components/organisms/menus/CommandMenu/CommandMenu.tsx"],"sourcesContent":["'use client';\n\nimport {\n ArrowDown,\n ArrowUp,\n CornerDownLeft,\n Search,\n Settings,\n} from 'lucide-react';\nimport * as React from 'react';\nimport { Button, ClearButton } from '@/components/atoms/buttons/Button';\nimport { Avatar } from '@/components/molecules/data/Avatar';\nimport { Kbd } from '@/components/molecules/data/Kbd';\nimport {\n Command,\n CommandDialog,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList,\n CommandSeparator,\n} from '@/components/ui/command';\nimport { cn } from '@/lib/utils';\n\nconst DEFAULT_COMMAND_MENU_MAX_HEIGHT = 336;\nconst DEFAULT_COMMAND_MENU_PLACEHOLDER = 'Type a command or search...';\nconst COMMAND_MENU_SHELL_CLASS_NAME =\n 'w-full max-w-[508px] overflow-hidden rounded-xl border border-input bg-background shadow-lg';\n\nfunction getCommandMenuMaxHeight(maxHeight: number): number {\n return Number.isFinite(maxHeight) && maxHeight >= 0\n ? maxHeight\n : DEFAULT_COMMAND_MENU_MAX_HEIGHT;\n}\n\n// ============================================\n// Types\n// ============================================\n\nexport interface CommandMenuOption {\n /** Unique identifier for the option */\n id: string;\n /** Display label for the option */\n label: string;\n /** Optional subtitle (e.g., @username, email) */\n subtitle?: string;\n /** Optional icon to display (mutually exclusive with avatar) */\n icon?: React.ReactNode;\n /** Optional avatar configuration */\n avatar?: {\n src?: string;\n fallback?: string;\n };\n /** Whether the option is disabled */\n disabled?: boolean;\n /** Keyboard shortcut to display */\n shortcut?: string;\n}\n\nexport interface CommandMenuGroup {\n /** Unique identifier for the group */\n id: string;\n /** Group label/heading */\n label: string;\n /** Options in this group */\n options: CommandMenuOption[];\n}\n\nexport interface CommandMenuFooterHint {\n /** Icon or keyboard key indicator */\n keys: React.ReactNode;\n /** Text describing the action */\n label: string;\n}\n\nexport interface CommandMenuProps {\n /** Whether the command menu is open */\n open?: boolean;\n /** Callback when open state changes */\n onOpenChange?: (open: boolean) => void;\n /** Placeholder text for the search input */\n placeholder?: string;\n /** Text to show when no results found */\n emptyText?: string;\n /** Empty state content (replaces emptyText when provided) */\n emptyState?: React.ReactNode;\n /** Flat list of options */\n options?: CommandMenuOption[];\n /** Grouped options */\n groups?: CommandMenuGroup[];\n /** Callback when an option is selected */\n onSelect?: (id: string, option: CommandMenuOption) => void;\n /** Whether to show keyboard shortcut badge in input */\n showShortcut?: boolean;\n /** Keyboard shortcut text to display (auto-detects platform when omitted) */\n shortcutText?: string;\n /** Whether to show the footer with navigation hints */\n showFooter?: boolean;\n /** Custom footer hints */\n footerHints?: CommandMenuFooterHint[];\n /** Whether to show settings button in footer */\n showSettingsButton?: boolean;\n /** Callback when settings button is clicked */\n onSettingsClick?: () => void;\n /** Additional class name for the dialog */\n className?: string;\n /** Maximum height of the list */\n maxHeight?: number;\n /** Custom filter function */\n filter?: (value: string, search: string) => number;\n /** Children for custom content */\n children?: React.ReactNode;\n}\n\n// ============================================\n// Platform detection\n// ============================================\n\nfunction usePlatformShortcut() {\n const [shortcut, setShortcut] = React.useState('\\u2318/');\n React.useEffect(() => {\n if (!/Mac|iPhone|iPad/i.test(navigator.userAgent)) {\n setShortcut('Ctrl /');\n }\n }, []);\n return shortcut;\n}\n\n// ============================================\n// Keyboard Shortcut Badge (uses Kbd wrapper)\n// ============================================\n\nfunction CommandShortcutBadge({\n children,\n className,\n}: {\n children: React.ReactNode;\n className?: string;\n}) {\n return (\n <Kbd variant=\"solid\" size=\"sm\" className={cn('shadow-xs', className)}>\n {children}\n </Kbd>\n );\n}\nCommandShortcutBadge.displayName = 'CommandMenu.ShortcutBadge';\n\n// ============================================\n// Footer Navigation Icon (uses Kbd wrapper)\n// ============================================\n\nfunction FooterNavIcon({\n children,\n className,\n}: {\n children: React.ReactNode;\n className?: string;\n}) {\n return (\n <Kbd variant=\"footer\" size=\"sm\" className={cn('p-1.5', className)}>\n {children}\n </Kbd>\n );\n}\nFooterNavIcon.displayName = 'CommandMenu.FooterNavIcon';\n\nfunction FooterNavText({\n children,\n className,\n}: {\n children: React.ReactNode;\n className?: string;\n}) {\n return (\n <span\n className={cn('text-sm font-semibold text-text-quaternary', className)}\n >\n {children}\n </span>\n );\n}\nFooterNavText.displayName = 'CommandMenu.FooterNavText';\n\n// ============================================\n// Default Footer Hints\n// ============================================\n\nconst defaultFooterHints: CommandMenuFooterHint[] = [\n {\n keys: (\n <div className=\"flex items-center gap-1\">\n <FooterNavIcon>\n <ArrowUp className=\"size-2.5 text-text-quaternary\" />\n </FooterNavIcon>\n <FooterNavIcon>\n <ArrowDown className=\"size-2.5 text-text-quaternary\" />\n </FooterNavIcon>\n </div>\n ),\n label: 'to navigate',\n },\n {\n keys: (\n <FooterNavIcon>\n <CornerDownLeft className=\"size-2.5 text-text-quaternary\" />\n </FooterNavIcon>\n ),\n label: 'to select',\n },\n {\n keys: (\n <FooterNavIcon className=\"px-1.5 py-1\">\n <span className=\"text-xs font-semibold text-text-quaternary\">esc</span>\n </FooterNavIcon>\n ),\n label: 'to close',\n },\n];\n\n// ============================================\n// Command Menu Footer\n// ============================================\n\nexport interface CommandMenuFooterProps {\n hints?: CommandMenuFooterHint[];\n showSettingsButton?: boolean;\n onSettingsClick?: () => void;\n className?: string;\n}\n\nfunction CommandMenuFooter({\n hints = defaultFooterHints,\n showSettingsButton = false,\n onSettingsClick,\n className,\n}: CommandMenuFooterProps) {\n return (\n <div\n data-slot=\"command-menu-footer\"\n className={cn(\n 'flex items-center gap-3 border-t border-border bg-card/80 py-2 pe-2 ps-[18px] supports-backdrop-filter:backdrop-blur',\n className,\n )}\n >\n <div className=\"hidden flex-1 items-start gap-4 [@media(hover:hover)]:flex\">\n {hints.map((hint) => (\n <div key={hint.label} className=\"flex items-center gap-2\">\n {hint.keys}\n <FooterNavText>{hint.label}</FooterNavText>\n </div>\n ))}\n </div>\n {showSettingsButton && (\n <Button\n appearance=\"ghost\"\n variant=\"secondary\"\n size=\"icon\"\n className=\"group ms-auto rounded-full bg-muted\"\n onClick={onSettingsClick}\n aria-label=\"Settings\"\n >\n <Settings className=\"size-5 text-muted-foreground transition-transform duration-300 ease-out group-hover:rotate-90 motion-reduce:transition-none\" />\n </Button>\n )}\n </div>\n );\n}\nCommandMenuFooter.displayName = 'CommandMenu.Footer';\n\n// ============================================\n// Command Menu Item\n// ============================================\n\nexport interface CommandMenuItemProps\n extends Omit<\n React.ComponentProps<typeof CommandItem>,\n 'onSelect' | 'showCheckIndicator' | 'value'\n > {\n option: CommandMenuOption;\n onSelect?: (id: string, option: CommandMenuOption) => void;\n}\n\nfunction CommandMenuItem({\n option,\n onSelect,\n className,\n ...props\n}: CommandMenuItemProps) {\n return (\n <CommandItem\n value={option.id}\n disabled={option.disabled}\n showCheckIndicator={false}\n onSelect={() => onSelect?.(option.id, option)}\n className={cn(\n 'flex cursor-pointer items-center gap-2 transition-colors duration-150 motion-reduce:transition-none',\n className,\n )}\n {...props}\n >\n {option.avatar && (\n <Avatar\n src={option.avatar.src}\n fallback={option.avatar.fallback || option.label.charAt(0)}\n size=\"sm\"\n className=\"size-6 shrink-0\"\n />\n )}\n {option.icon && !option.avatar && (\n <span className=\"flex size-4 shrink-0 items-center justify-center text-muted-foreground [&_svg]:size-4\">\n {option.icon}\n </span>\n )}\n <div className=\"flex min-w-0 flex-1 items-center gap-2 text-sm leading-5\">\n <span className=\"min-w-0 truncate font-normal text-foreground\">\n {option.label}\n </span>\n {option.subtitle && (\n <span className=\"min-w-0 truncate font-normal text-muted-foreground\">\n {option.subtitle}\n </span>\n )}\n </div>\n {option.shortcut && (\n <CommandShortcutBadge className=\"transition-colors duration-150 group-data-[selected=true]/command-item:bg-primary/10 group-data-[selected=true]/command-item:text-primary\">\n {option.shortcut}\n </CommandShortcutBadge>\n )}\n </CommandItem>\n );\n}\nCommandMenuItem.displayName = 'CommandMenu.Item';\n\n// ============================================\n// Command Menu Group Header\n// ============================================\n\nfunction CommandMenuGroupHeader({\n children,\n className,\n ...props\n}: React.ComponentProps<'h3'>) {\n return (\n <h3\n data-slot=\"command-menu-group-header\"\n className={cn(\n 'px-2 py-1.5 text-xs font-medium text-muted-foreground',\n className,\n )}\n {...props}\n >\n {children}\n </h3>\n );\n}\nCommandMenuGroupHeader.displayName = 'CommandMenu.GroupHeader';\n\n// ============================================\n// Shared Command Menu Body (internal)\n// ============================================\n\ninterface CommandMenuBodyProps {\n children?: React.ReactNode;\n groups: CommandMenuGroup[];\n options: CommandMenuOption[];\n onSelect?: (id: string, option: CommandMenuOption) => void;\n onClose?: () => void;\n placeholder: string;\n emptyText: string;\n emptyState?: React.ReactNode;\n showShortcut: boolean;\n shortcutText: string;\n showFooter: boolean;\n footerHints?: CommandMenuFooterHint[];\n showSettingsButton: boolean;\n onSettingsClick?: () => void;\n maxHeight: number;\n filter?: (value: string, search: string) => number;\n}\n\ninterface CommandMenuBodyContentProps {\n children?: React.ReactNode;\n groups: CommandMenuGroup[];\n options: CommandMenuOption[];\n optionRenderer: (option: CommandMenuOption) => React.ReactNode;\n}\n\ninterface CommandMenuGroupSectionProps {\n group: CommandMenuGroup;\n optionRenderer: (option: CommandMenuOption) => React.ReactNode;\n}\n\nfunction CommandMenuGroupSection({\n group,\n optionRenderer,\n}: CommandMenuGroupSectionProps) {\n const headingId = React.useId();\n\n return (\n <CommandGroup aria-labelledby={headingId} className=\"px-2 py-1\">\n <CommandMenuGroupHeader id={headingId}>\n {group.label}\n </CommandMenuGroupHeader>\n <div className=\"flex flex-col\">{group.options.map(optionRenderer)}</div>\n </CommandGroup>\n );\n}\nCommandMenuGroupSection.displayName = 'CommandMenu.GroupSection';\n\nfunction CommandMenuBodyContent({\n children,\n groups,\n options,\n optionRenderer,\n}: CommandMenuBodyContentProps) {\n if (children) return children;\n\n if (groups.length > 0) {\n return groups.map((group, index) => (\n <React.Fragment key={group.id}>\n {index > 0 && <CommandSeparator className=\"mx-0\" />}\n <CommandMenuGroupSection\n group={group}\n optionRenderer={optionRenderer}\n />\n </React.Fragment>\n ));\n }\n\n return <div className=\"flex flex-col p-2\">{options.map(optionRenderer)}</div>;\n}\n\nfunction CommandMenuBody({\n children,\n groups,\n options,\n onSelect,\n onClose,\n placeholder,\n emptyText,\n emptyState,\n showShortcut,\n shortcutText,\n showFooter,\n footerHints,\n showSettingsButton,\n onSettingsClick,\n maxHeight,\n filter,\n}: CommandMenuBodyProps) {\n const safeMaxHeight = getCommandMenuMaxHeight(maxHeight);\n const renderOption = (option: CommandMenuOption) => (\n <CommandMenuItem key={option.id} option={option} onSelect={onSelect} />\n );\n\n return (\n <Command\n filter={filter}\n className=\"rounded-none border-0 shadow-none\"\n data-slot=\"command-menu\"\n >\n <search\n aria-label=\"Command menu search\"\n className=\"block border-b border-input bg-background\"\n >\n <CommandInput\n render={({ clearSearch, value, ...inputProps }) => {\n const canClose = typeof onClose === 'function';\n const clearOrClose = () => {\n if (value) {\n clearSearch();\n return;\n }\n onClose?.();\n };\n\n return (\n <div\n data-slot=\"command-menu-input\"\n cmdk-input-wrapper=\"\"\n className=\"flex h-11 items-center gap-2 px-3\"\n >\n <Search\n className=\"size-4 shrink-0 text-muted-foreground opacity-50\"\n aria-hidden=\"true\"\n />\n <input\n {...inputProps}\n value={value}\n placeholder={placeholder}\n aria-label={placeholder}\n className=\"min-w-0 flex-1 bg-transparent text-sm leading-5 text-foreground outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50\"\n />\n {showShortcut && (\n <CommandShortcutBadge>{shortcutText}</CommandShortcutBadge>\n )}\n <ClearButton\n size=\"icon-xs\"\n className=\"-me-1 rounded-sm p-0 opacity-50 hover:opacity-80 focus-visible:ring-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:size-4\"\n disabled={!value && !canClose}\n aria-label={\n value\n ? 'Clear search'\n : canClose\n ? 'Close command menu'\n : 'Clear search'\n }\n onClick={clearOrClose}\n />\n </div>\n );\n }}\n />\n </search>\n\n <CommandList\n style={{ maxHeight: safeMaxHeight }}\n className=\"overflow-y-auto p-0\"\n >\n <CommandEmpty className=\"py-6 text-center text-sm text-muted-foreground animate-in fade-in-0 duration-200 motion-reduce:animate-none\">\n {emptyState || emptyText}\n </CommandEmpty>\n <CommandMenuBodyContent\n groups={groups}\n options={options}\n optionRenderer={renderOption}\n >\n {children}\n </CommandMenuBodyContent>\n </CommandList>\n\n {showFooter && (\n <CommandMenuFooter\n hints={footerHints}\n showSettingsButton={showSettingsButton}\n onSettingsClick={onSettingsClick}\n />\n )}\n </Command>\n );\n}\nCommandMenuBody.displayName = 'CommandMenu.Body';\n\n// ============================================\n// Main Command Menu Component\n// ============================================\n\nfunction CommandMenu({\n open,\n onOpenChange,\n placeholder = DEFAULT_COMMAND_MENU_PLACEHOLDER,\n emptyText = 'No results found.',\n emptyState,\n options = [],\n groups = [],\n onSelect,\n showShortcut = false,\n shortcutText,\n showFooter = false,\n footerHints,\n showSettingsButton = false,\n onSettingsClick,\n className,\n maxHeight = DEFAULT_COMMAND_MENU_MAX_HEIGHT,\n filter,\n children,\n}: CommandMenuProps) {\n const platformShortcut = usePlatformShortcut();\n const resolvedShortcut = shortcutText ?? platformShortcut;\n\n return (\n <CommandDialog\n open={open}\n onOpenChange={onOpenChange}\n className={cn('max-w-[508px] sm:max-w-[508px]', className)}\n >\n <CommandMenuBody\n placeholder={placeholder}\n emptyText={emptyText}\n emptyState={emptyState}\n options={options}\n groups={groups}\n onSelect={onSelect}\n onClose={() => onOpenChange?.(false)}\n showShortcut={showShortcut}\n shortcutText={resolvedShortcut}\n showFooter={showFooter}\n footerHints={footerHints}\n showSettingsButton={showSettingsButton}\n onSettingsClick={onSettingsClick}\n maxHeight={maxHeight}\n filter={filter}\n >\n {children}\n </CommandMenuBody>\n </CommandDialog>\n );\n}\nCommandMenu.displayName = 'CommandMenu';\n\n// ============================================\n// Standalone Command Menu (non-dialog version)\n// ============================================\n\nexport interface CommandMenuPanelProps\n extends Omit<CommandMenuProps, 'open' | 'onOpenChange'> {\n /** Additional class name */\n className?: string;\n}\n\nfunction CommandMenuPanel({\n placeholder = DEFAULT_COMMAND_MENU_PLACEHOLDER,\n emptyText = 'No results found.',\n emptyState,\n options = [],\n groups = [],\n onSelect,\n showShortcut = false,\n shortcutText,\n showFooter = false,\n footerHints,\n showSettingsButton = false,\n onSettingsClick,\n className,\n maxHeight = DEFAULT_COMMAND_MENU_MAX_HEIGHT,\n filter,\n children,\n}: CommandMenuPanelProps) {\n const platformShortcut = usePlatformShortcut();\n const resolvedShortcut = shortcutText ?? platformShortcut;\n\n return (\n <div\n data-slot=\"command-menu-panel\"\n className={cn(COMMAND_MENU_SHELL_CLASS_NAME, className)}\n >\n <CommandMenuBody\n placeholder={placeholder}\n emptyText={emptyText}\n emptyState={emptyState}\n options={options}\n groups={groups}\n onSelect={onSelect}\n showShortcut={showShortcut}\n shortcutText={resolvedShortcut}\n showFooter={showFooter}\n footerHints={footerHints}\n showSettingsButton={showSettingsButton}\n onSettingsClick={onSettingsClick}\n maxHeight={maxHeight}\n filter={filter}\n >\n {children}\n </CommandMenuBody>\n </div>\n );\n}\nCommandMenuPanel.displayName = 'CommandMenu.Panel';\n\n// ============================================\n// Exports\n// ============================================\n\nexport {\n CommandMenu,\n CommandMenuFooter,\n CommandMenuGroupHeader,\n CommandMenuItem,\n CommandMenuPanel,\n CommandShortcutBadge,\n defaultFooterHints,\n FooterNavIcon,\n FooterNavText,\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"index204.js","names":[],"sources":["../src/components/organisms/menus/CommandMenu/CommandMenu.tsx"],"sourcesContent":["'use client';\n\nimport {\n ArrowDown,\n ArrowUp,\n CornerDownLeft,\n Search,\n Settings,\n} from 'lucide-react';\nimport * as React from 'react';\nimport { Button, ClearButton } from '@/components/atoms/buttons/Button';\nimport { Avatar } from '@/components/molecules/data/Avatar';\nimport { Kbd } from '@/components/molecules/data/Kbd';\nimport {\n Command,\n CommandDialog,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList,\n CommandSeparator,\n} from '@/components/ui/command';\nimport { cn } from '@/lib/utils';\n\nconst DEFAULT_COMMAND_MENU_MAX_HEIGHT = 336;\nconst DEFAULT_COMMAND_MENU_PLACEHOLDER = 'Type a command or search...';\nconst COMMAND_MENU_SHELL_CLASS_NAME =\n 'w-full max-w-[508px] overflow-hidden rounded-xl border border-input bg-background shadow-lg';\n\nfunction getCommandMenuMaxHeight(maxHeight: number): number {\n return Number.isFinite(maxHeight) && maxHeight >= 0\n ? maxHeight\n : DEFAULT_COMMAND_MENU_MAX_HEIGHT;\n}\n\n// ============================================\n// Types\n// ============================================\n\nexport interface CommandMenuOption {\n /** Unique identifier for the option */\n id: string;\n /** Display label for the option */\n label: string;\n /** Optional subtitle (e.g., @username, email) */\n subtitle?: string;\n /** Optional icon to display (mutually exclusive with avatar) */\n icon?: React.ReactNode;\n /** Optional avatar configuration */\n avatar?: {\n src?: string;\n fallback?: string;\n };\n /** Whether the option is disabled */\n disabled?: boolean;\n /** Keyboard shortcut to display */\n shortcut?: string;\n}\n\nexport interface CommandMenuGroup {\n /** Unique identifier for the group */\n id: string;\n /** Group label/heading */\n label: string;\n /** Options in this group */\n options: CommandMenuOption[];\n}\n\nexport interface CommandMenuFooterHint {\n /** Icon or keyboard key indicator */\n keys: React.ReactNode;\n /** Text describing the action */\n label: string;\n}\n\nexport interface CommandMenuProps {\n /** Whether the command menu is open */\n open?: boolean;\n /** Callback when open state changes */\n onOpenChange?: (open: boolean) => void;\n /** Placeholder text for the search input */\n placeholder?: string;\n /** Text to show when no results found */\n emptyText?: string;\n /** Empty state content (replaces emptyText when provided) */\n emptyState?: React.ReactNode;\n /** Flat list of options */\n options?: CommandMenuOption[];\n /** Grouped options */\n groups?: CommandMenuGroup[];\n /** Callback when an option is selected */\n onSelect?: (id: string, option: CommandMenuOption) => void;\n /** Whether to show keyboard shortcut badge in input */\n showShortcut?: boolean;\n /** Keyboard shortcut text to display (auto-detects platform when omitted) */\n shortcutText?: string;\n /** Whether to show the footer with navigation hints */\n showFooter?: boolean;\n /** Custom footer hints */\n footerHints?: CommandMenuFooterHint[];\n /** Whether to show settings button in footer */\n showSettingsButton?: boolean;\n /** Callback when settings button is clicked */\n onSettingsClick?: () => void;\n /** Additional class name for the dialog */\n className?: string;\n /** Maximum height of the list */\n maxHeight?: number;\n /** Custom filter function */\n filter?: (value: string, search: string) => number;\n /** Children for custom content */\n children?: React.ReactNode;\n}\n\n// ============================================\n// Platform detection\n// ============================================\n\nfunction usePlatformShortcut() {\n const [shortcut, setShortcut] = React.useState('\\u2318/');\n React.useEffect(() => {\n if (!/Mac|iPhone|iPad/i.test(navigator.userAgent)) {\n setShortcut('Ctrl /');\n }\n }, []);\n return shortcut;\n}\n\n// ============================================\n// Keyboard Shortcut Badge (uses Kbd wrapper)\n// ============================================\n\nfunction CommandShortcutBadge({\n children,\n className,\n}: {\n children: React.ReactNode;\n className?: string;\n}) {\n return (\n <Kbd variant=\"solid\" size=\"sm\" className={cn('shadow-xs', className)}>\n {children}\n </Kbd>\n );\n}\nCommandShortcutBadge.displayName = 'CommandMenu.ShortcutBadge';\n\n// ============================================\n// Footer Navigation Icon (uses Kbd wrapper)\n// ============================================\n\nfunction FooterNavIcon({\n children,\n className,\n}: {\n children: React.ReactNode;\n className?: string;\n}) {\n return (\n <Kbd variant=\"footer\" size=\"sm\" className={cn('p-1.5', className)}>\n {children}\n </Kbd>\n );\n}\nFooterNavIcon.displayName = 'CommandMenu.FooterNavIcon';\n\nfunction FooterNavText({\n children,\n className,\n}: {\n children: React.ReactNode;\n className?: string;\n}) {\n return (\n <span\n className={cn(\n 'text-sm font-semibold text-secondary-foreground',\n className,\n )}\n >\n {children}\n </span>\n );\n}\nFooterNavText.displayName = 'CommandMenu.FooterNavText';\n\n// ============================================\n// Default Footer Hints\n// ============================================\n\nconst defaultFooterHints: CommandMenuFooterHint[] = [\n {\n keys: (\n <div className=\"flex items-center gap-1\">\n <FooterNavIcon>\n <ArrowUp className=\"size-2.5 text-secondary-foreground\" />\n </FooterNavIcon>\n <FooterNavIcon>\n <ArrowDown className=\"size-2.5 text-secondary-foreground\" />\n </FooterNavIcon>\n </div>\n ),\n label: 'to navigate',\n },\n {\n keys: (\n <FooterNavIcon>\n <CornerDownLeft className=\"size-2.5 text-secondary-foreground\" />\n </FooterNavIcon>\n ),\n label: 'to select',\n },\n {\n keys: (\n <FooterNavIcon className=\"px-1.5 py-1\">\n <span className=\"text-xs font-semibold text-secondary-foreground\">\n esc\n </span>\n </FooterNavIcon>\n ),\n label: 'to close',\n },\n];\n\n// ============================================\n// Command Menu Footer\n// ============================================\n\nexport interface CommandMenuFooterProps {\n hints?: CommandMenuFooterHint[];\n showSettingsButton?: boolean;\n onSettingsClick?: () => void;\n className?: string;\n}\n\nfunction CommandMenuFooter({\n hints = defaultFooterHints,\n showSettingsButton = false,\n onSettingsClick,\n className,\n}: CommandMenuFooterProps) {\n return (\n <div\n data-slot=\"command-menu-footer\"\n className={cn(\n 'flex items-center gap-3 border-t border-border bg-card/80 py-2 pe-2 ps-[18px] supports-backdrop-filter:backdrop-blur',\n className,\n )}\n >\n <div className=\"hidden flex-1 items-start gap-4 [@media(hover:hover)]:flex\">\n {hints.map((hint) => (\n <div key={hint.label} className=\"flex items-center gap-2\">\n {hint.keys}\n <FooterNavText>{hint.label}</FooterNavText>\n </div>\n ))}\n </div>\n {showSettingsButton && (\n <Button\n appearance=\"ghost\"\n variant=\"secondary\"\n size=\"icon\"\n className=\"group ms-auto rounded-full bg-muted\"\n onClick={onSettingsClick}\n aria-label=\"Settings\"\n >\n <Settings className=\"size-5 text-muted-foreground transition-transform duration-300 ease-out group-hover:rotate-90 motion-reduce:transition-none\" />\n </Button>\n )}\n </div>\n );\n}\nCommandMenuFooter.displayName = 'CommandMenu.Footer';\n\n// ============================================\n// Command Menu Item\n// ============================================\n\nexport interface CommandMenuItemProps\n extends Omit<\n React.ComponentProps<typeof CommandItem>,\n 'onSelect' | 'showCheckIndicator' | 'value'\n > {\n option: CommandMenuOption;\n onSelect?: (id: string, option: CommandMenuOption) => void;\n}\n\nfunction CommandMenuItem({\n option,\n onSelect,\n className,\n ...props\n}: CommandMenuItemProps) {\n return (\n <CommandItem\n value={option.id}\n disabled={option.disabled}\n showCheckIndicator={false}\n onSelect={() => onSelect?.(option.id, option)}\n className={cn(\n 'flex cursor-pointer items-center gap-2 transition-colors duration-150 motion-reduce:transition-none',\n className,\n )}\n {...props}\n >\n {option.avatar && (\n <Avatar\n src={option.avatar.src}\n fallback={option.avatar.fallback || option.label.charAt(0)}\n size=\"sm\"\n className=\"size-6 shrink-0\"\n />\n )}\n {option.icon && !option.avatar && (\n <span className=\"flex size-4 shrink-0 items-center justify-center text-muted-foreground [&_svg]:size-4\">\n {option.icon}\n </span>\n )}\n <div className=\"flex min-w-0 flex-1 items-center gap-2 text-sm leading-5\">\n <span className=\"min-w-0 truncate font-normal text-foreground\">\n {option.label}\n </span>\n {option.subtitle && (\n <span className=\"min-w-0 truncate font-normal text-muted-foreground\">\n {option.subtitle}\n </span>\n )}\n </div>\n {option.shortcut && (\n <CommandShortcutBadge className=\"transition-colors duration-150 group-data-[selected=true]/command-item:bg-primary/10 group-data-[selected=true]/command-item:text-primary\">\n {option.shortcut}\n </CommandShortcutBadge>\n )}\n </CommandItem>\n );\n}\nCommandMenuItem.displayName = 'CommandMenu.Item';\n\n// ============================================\n// Command Menu Group Header\n// ============================================\n\nfunction CommandMenuGroupHeader({\n children,\n className,\n ...props\n}: React.ComponentProps<'h3'>) {\n return (\n <h3\n data-slot=\"command-menu-group-header\"\n className={cn(\n 'px-2 py-1.5 text-xs font-medium text-muted-foreground',\n className,\n )}\n {...props}\n >\n {children}\n </h3>\n );\n}\nCommandMenuGroupHeader.displayName = 'CommandMenu.GroupHeader';\n\n// ============================================\n// Shared Command Menu Body (internal)\n// ============================================\n\ninterface CommandMenuBodyProps {\n children?: React.ReactNode;\n groups: CommandMenuGroup[];\n options: CommandMenuOption[];\n onSelect?: (id: string, option: CommandMenuOption) => void;\n onClose?: () => void;\n placeholder: string;\n emptyText: string;\n emptyState?: React.ReactNode;\n showShortcut: boolean;\n shortcutText: string;\n showFooter: boolean;\n footerHints?: CommandMenuFooterHint[];\n showSettingsButton: boolean;\n onSettingsClick?: () => void;\n maxHeight: number;\n filter?: (value: string, search: string) => number;\n}\n\ninterface CommandMenuBodyContentProps {\n children?: React.ReactNode;\n groups: CommandMenuGroup[];\n options: CommandMenuOption[];\n optionRenderer: (option: CommandMenuOption) => React.ReactNode;\n}\n\ninterface CommandMenuGroupSectionProps {\n group: CommandMenuGroup;\n optionRenderer: (option: CommandMenuOption) => React.ReactNode;\n}\n\nfunction CommandMenuGroupSection({\n group,\n optionRenderer,\n}: CommandMenuGroupSectionProps) {\n const headingId = React.useId();\n\n return (\n <CommandGroup aria-labelledby={headingId} className=\"px-2 py-1\">\n <CommandMenuGroupHeader id={headingId}>\n {group.label}\n </CommandMenuGroupHeader>\n <div className=\"flex flex-col\">{group.options.map(optionRenderer)}</div>\n </CommandGroup>\n );\n}\nCommandMenuGroupSection.displayName = 'CommandMenu.GroupSection';\n\nfunction CommandMenuBodyContent({\n children,\n groups,\n options,\n optionRenderer,\n}: CommandMenuBodyContentProps) {\n if (children) return children;\n\n if (groups.length > 0) {\n return groups.map((group, index) => (\n <React.Fragment key={group.id}>\n {index > 0 && <CommandSeparator className=\"mx-0\" />}\n <CommandMenuGroupSection\n group={group}\n optionRenderer={optionRenderer}\n />\n </React.Fragment>\n ));\n }\n\n return <div className=\"flex flex-col p-2\">{options.map(optionRenderer)}</div>;\n}\n\nfunction CommandMenuBody({\n children,\n groups,\n options,\n onSelect,\n onClose,\n placeholder,\n emptyText,\n emptyState,\n showShortcut,\n shortcutText,\n showFooter,\n footerHints,\n showSettingsButton,\n onSettingsClick,\n maxHeight,\n filter,\n}: CommandMenuBodyProps) {\n const safeMaxHeight = getCommandMenuMaxHeight(maxHeight);\n const renderOption = (option: CommandMenuOption) => (\n <CommandMenuItem key={option.id} option={option} onSelect={onSelect} />\n );\n\n return (\n <Command\n filter={filter}\n className=\"rounded-none border-0 shadow-none\"\n data-slot=\"command-menu\"\n >\n <search\n aria-label=\"Command menu search\"\n className=\"block border-b border-input bg-background\"\n >\n <CommandInput\n render={({ clearSearch, value, ...inputProps }) => {\n const canClose = typeof onClose === 'function';\n const clearOrClose = () => {\n if (value) {\n clearSearch();\n return;\n }\n onClose?.();\n };\n\n return (\n <div\n data-slot=\"command-menu-input\"\n cmdk-input-wrapper=\"\"\n className=\"flex h-11 items-center gap-2 px-3\"\n >\n <Search\n className=\"size-4 shrink-0 text-muted-foreground opacity-50\"\n aria-hidden=\"true\"\n />\n <input\n {...inputProps}\n value={value}\n placeholder={placeholder}\n aria-label={placeholder}\n className=\"min-w-0 flex-1 bg-transparent text-sm leading-5 text-foreground outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50\"\n />\n {showShortcut && (\n <CommandShortcutBadge>{shortcutText}</CommandShortcutBadge>\n )}\n <ClearButton\n size=\"icon-xs\"\n className=\"-me-1 rounded-sm p-0 opacity-50 hover:opacity-80 focus-visible:ring-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:size-4\"\n disabled={!value && !canClose}\n aria-label={\n value\n ? 'Clear search'\n : canClose\n ? 'Close command menu'\n : 'Clear search'\n }\n onClick={clearOrClose}\n />\n </div>\n );\n }}\n />\n </search>\n\n <CommandList\n style={{ maxHeight: safeMaxHeight }}\n className=\"overflow-y-auto p-0\"\n >\n <CommandEmpty className=\"py-6 text-center text-sm text-muted-foreground animate-in fade-in-0 duration-200 motion-reduce:animate-none\">\n {emptyState || emptyText}\n </CommandEmpty>\n <CommandMenuBodyContent\n groups={groups}\n options={options}\n optionRenderer={renderOption}\n >\n {children}\n </CommandMenuBodyContent>\n </CommandList>\n\n {showFooter && (\n <CommandMenuFooter\n hints={footerHints}\n showSettingsButton={showSettingsButton}\n onSettingsClick={onSettingsClick}\n />\n )}\n </Command>\n );\n}\nCommandMenuBody.displayName = 'CommandMenu.Body';\n\n// ============================================\n// Main Command Menu Component\n// ============================================\n\nfunction CommandMenu({\n open,\n onOpenChange,\n placeholder = DEFAULT_COMMAND_MENU_PLACEHOLDER,\n emptyText = 'No results found.',\n emptyState,\n options = [],\n groups = [],\n onSelect,\n showShortcut = false,\n shortcutText,\n showFooter = false,\n footerHints,\n showSettingsButton = false,\n onSettingsClick,\n className,\n maxHeight = DEFAULT_COMMAND_MENU_MAX_HEIGHT,\n filter,\n children,\n}: CommandMenuProps) {\n const platformShortcut = usePlatformShortcut();\n const resolvedShortcut = shortcutText ?? platformShortcut;\n\n return (\n <CommandDialog\n open={open}\n onOpenChange={onOpenChange}\n className={cn('max-w-[508px] sm:max-w-[508px]', className)}\n >\n <CommandMenuBody\n placeholder={placeholder}\n emptyText={emptyText}\n emptyState={emptyState}\n options={options}\n groups={groups}\n onSelect={onSelect}\n onClose={() => onOpenChange?.(false)}\n showShortcut={showShortcut}\n shortcutText={resolvedShortcut}\n showFooter={showFooter}\n footerHints={footerHints}\n showSettingsButton={showSettingsButton}\n onSettingsClick={onSettingsClick}\n maxHeight={maxHeight}\n filter={filter}\n >\n {children}\n </CommandMenuBody>\n </CommandDialog>\n );\n}\nCommandMenu.displayName = 'CommandMenu';\n\n// ============================================\n// Standalone Command Menu (non-dialog version)\n// ============================================\n\nexport interface CommandMenuPanelProps\n extends Omit<CommandMenuProps, 'open' | 'onOpenChange'> {\n /** Additional class name */\n className?: string;\n}\n\nfunction CommandMenuPanel({\n placeholder = DEFAULT_COMMAND_MENU_PLACEHOLDER,\n emptyText = 'No results found.',\n emptyState,\n options = [],\n groups = [],\n onSelect,\n showShortcut = false,\n shortcutText,\n showFooter = false,\n footerHints,\n showSettingsButton = false,\n onSettingsClick,\n className,\n maxHeight = DEFAULT_COMMAND_MENU_MAX_HEIGHT,\n filter,\n children,\n}: CommandMenuPanelProps) {\n const platformShortcut = usePlatformShortcut();\n const resolvedShortcut = shortcutText ?? platformShortcut;\n\n return (\n <div\n data-slot=\"command-menu-panel\"\n className={cn(COMMAND_MENU_SHELL_CLASS_NAME, className)}\n >\n <CommandMenuBody\n placeholder={placeholder}\n emptyText={emptyText}\n emptyState={emptyState}\n options={options}\n groups={groups}\n onSelect={onSelect}\n showShortcut={showShortcut}\n shortcutText={resolvedShortcut}\n showFooter={showFooter}\n footerHints={footerHints}\n showSettingsButton={showSettingsButton}\n onSettingsClick={onSettingsClick}\n maxHeight={maxHeight}\n filter={filter}\n >\n {children}\n </CommandMenuBody>\n </div>\n );\n}\nCommandMenuPanel.displayName = 'CommandMenu.Panel';\n\n// ============================================\n// Exports\n// ============================================\n\nexport {\n CommandMenu,\n CommandMenuFooter,\n CommandMenuGroupHeader,\n CommandMenuItem,\n CommandMenuPanel,\n CommandShortcutBadge,\n defaultFooterHints,\n FooterNavIcon,\n FooterNavText,\n};\n"],"mappings":";;;;;;;;;;AAyBA,IAAM,kCAAkC;AACxC,IAAM,mCAAmC;AACzC,IAAM,gCACJ;AAEF,SAAS,wBAAwB,WAA2B;CAC1D,OAAO,OAAO,SAAS,SAAS,KAAK,aAAa,IAC9C,YACA;AACN;AAqFA,SAAS,sBAAsB;CAC7B,MAAM,CAAC,UAAU,eAAe,QAAM,SAAS,IAAS;CACxD,QAAM,gBAAgB;EACpB,IAAI,CAAC,mBAAmB,KAAK,UAAU,SAAS,GAC9C,YAAY,QAAQ;CAExB,GAAG,CAAC,CAAC;CACL,OAAO;AACT;AAMA,SAAS,qBAAqB,EAC5B,UACA,aAIC;CACD,OACE,oBAAC,KAAD;EAAK,SAAQ;EAAQ,MAAK;EAAK,WAAW,GAAG,aAAa,SAAS;EAChE;CACE,CAAA;AAET;AACA,qBAAqB,cAAc;AAMnC,SAAS,cAAc,EACrB,UACA,aAIC;CACD,OACE,oBAAC,KAAD;EAAK,SAAQ;EAAS,MAAK;EAAK,WAAW,GAAG,SAAS,SAAS;EAC7D;CACE,CAAA;AAET;AACA,cAAc,cAAc;AAE5B,SAAS,cAAc,EACrB,UACA,aAIC;CACD,OACE,oBAAC,QAAD;EACE,WAAW,GACT,mDACA,SACF;EAEC;CACG,CAAA;AAEV;AACA,cAAc,cAAc;AAM5B,IAAM,qBAA8C;CAClD;EACE,MACE,qBAAC,OAAD;GAAK,WAAU;aAAf,CACE,oBAAC,eAAD,EAAA,UACE,oBAAC,SAAD,EAAS,WAAU,qCAAsC,CAAA,EAC5C,CAAA,GACf,oBAAC,eAAD,EAAA,UACE,oBAAC,WAAD,EAAW,WAAU,qCAAsC,CAAA,EAC9C,CAAA,CACZ;;EAEP,OAAO;CACT;CACA;EACE,MACE,oBAAC,eAAD,EAAA,UACE,oBAAC,gBAAD,EAAgB,WAAU,qCAAsC,CAAA,EACnD,CAAA;EAEjB,OAAO;CACT;CACA;EACE,MACE,oBAAC,eAAD;GAAe,WAAU;aACvB,oBAAC,QAAD;IAAM,WAAU;cAAkD;GAE5D,CAAA;EACO,CAAA;EAEjB,OAAO;CACT;AACF;AAaA,SAAS,kBAAkB,EACzB,QAAQ,oBACR,qBAAqB,OACrB,iBACA,aACyB;CACzB,OACE,qBAAC,OAAD;EACE,aAAU;EACV,WAAW,GACT,wHACA,SACF;YALF,CAOE,oBAAC,OAAD;GAAK,WAAU;aACZ,MAAM,KAAK,SACV,qBAAC,OAAD;IAAsB,WAAU;cAAhC,CACG,KAAK,MACN,oBAAC,eAAD,EAAA,UAAgB,KAAK,MAAqB,CAAA,CACvC;MAHK,KAAK,KAGV,CACN;EACE,CAAA,GACJ,sBACC,oBAAC,QAAD;GACE,YAAW;GACX,SAAQ;GACR,MAAK;GACL,WAAU;GACV,SAAS;GACT,cAAW;aAEX,oBAAC,UAAD,EAAU,WAAU,8HAA+H,CAAA;EAC7I,CAAA,CAEP;;AAET;AACA,kBAAkB,cAAc;AAehC,SAAS,gBAAgB,EACvB,QACA,UACA,WACA,GAAG,SACoB;CACvB,OACE,qBAAC,aAAD;EACE,OAAO,OAAO;EACd,UAAU,OAAO;EACjB,oBAAoB;EACpB,gBAAgB,WAAW,OAAO,IAAI,MAAM;EAC5C,WAAW,GACT,uGACA,SACF;EACA,GAAI;YATN;GAWG,OAAO,UACN,oBAAC,QAAD;IACE,KAAK,OAAO,OAAO;IACnB,UAAU,OAAO,OAAO,YAAY,OAAO,MAAM,OAAO,CAAC;IACzD,MAAK;IACL,WAAU;GACX,CAAA;GAEF,OAAO,QAAQ,CAAC,OAAO,UACtB,oBAAC,QAAD;IAAM,WAAU;cACb,OAAO;GACJ,CAAA;GAER,qBAAC,OAAD;IAAK,WAAU;cAAf,CACE,oBAAC,QAAD;KAAM,WAAU;eACb,OAAO;IACJ,CAAA,GACL,OAAO,YACN,oBAAC,QAAD;KAAM,WAAU;eACb,OAAO;IACJ,CAAA,CAEL;;GACJ,OAAO,YACN,oBAAC,sBAAD;IAAsB,WAAU;cAC7B,OAAO;GACY,CAAA;EAEb;;AAEjB;AACA,gBAAgB,cAAc;AAM9B,SAAS,uBAAuB,EAC9B,UACA,WACA,GAAG,SAC0B;CAC7B,OACE,oBAAC,MAAD;EACE,aAAU;EACV,WAAW,GACT,yDACA,SACF;EACA,GAAI;EAEH;CACC,CAAA;AAER;AACA,uBAAuB,cAAc;AAqCrC,SAAS,wBAAwB,EAC/B,OACA,kBAC+B;CAC/B,MAAM,YAAY,QAAM,MAAM;CAE9B,OACE,qBAAC,cAAD;EAAc,mBAAiB;EAAW,WAAU;YAApD,CACE,oBAAC,wBAAD;GAAwB,IAAI;aACzB,MAAM;EACe,CAAA,GACxB,oBAAC,OAAD;GAAK,WAAU;aAAiB,MAAM,QAAQ,IAAI,cAAc;EAAO,CAAA,CAC3D;;AAElB;AACA,wBAAwB,cAAc;AAEtC,SAAS,uBAAuB,EAC9B,UACA,QACA,SACA,kBAC8B;CAC9B,IAAI,UAAU,OAAO;CAErB,IAAI,OAAO,SAAS,GAClB,OAAO,OAAO,KAAK,OAAO,UACxB,qBAAC,QAAM,UAAP,EAAA,UAAA,CACG,QAAQ,KAAK,oBAAC,kBAAD,EAAkB,WAAU,OAAQ,CAAA,GAClD,oBAAC,yBAAD;EACS;EACS;CACjB,CAAA,CACa,EAAA,GANK,MAAM,EAMX,CACjB;CAGH,OAAO,oBAAC,OAAD;EAAK,WAAU;YAAqB,QAAQ,IAAI,cAAc;CAAO,CAAA;AAC9E;AAEA,SAAS,gBAAgB,EACvB,UACA,QACA,SACA,UACA,SACA,aACA,WACA,YACA,cACA,cACA,YACA,aACA,oBACA,iBACA,WACA,UACuB;CACvB,MAAM,gBAAgB,wBAAwB,SAAS;CACvD,MAAM,gBAAgB,WACpB,oBAAC,iBAAD;EAAyC;EAAkB;CAAW,GAAhD,OAAO,EAAyC;CAGxE,OACE,qBAAC,kBAAD;EACU;EACR,WAAU;EACV,aAAU;YAHZ;GAKE,oBAAC,UAAD;IACE,cAAW;IACX,WAAU;cAEV,oBAAC,cAAD,EACE,SAAS,EAAE,aAAa,OAAO,GAAG,iBAAiB;KACjD,MAAM,WAAW,OAAO,YAAY;KACpC,MAAM,qBAAqB;MACzB,IAAI,OAAO;OACT,YAAY;OACZ;MACF;MACA,UAAU;KACZ;KAEA,OACE,qBAAC,OAAD;MACE,aAAU;MACV,sBAAmB;MACnB,WAAU;gBAHZ;OAKE,oBAAC,QAAD;QACE,WAAU;QACV,eAAY;OACb,CAAA;OACD,oBAAC,SAAD;QACE,GAAI;QACG;QACM;QACb,cAAY;QACZ,WAAU;OACX,CAAA;OACA,gBACC,oBAAC,sBAAD,EAAA,UAAuB,aAAmC,CAAA;OAE5D,oBAAC,aAAD;QACE,MAAK;QACL,WAAU;QACV,UAAU,CAAC,SAAS,CAAC;QACrB,cACE,QACI,iBACA,WACE,uBACA;QAER,SAAS;OACV,CAAA;MACE;;IAET,EACD,CAAA;GACK,CAAA;GAER,qBAAC,aAAD;IACE,OAAO,EAAE,WAAW,cAAc;IAClC,WAAU;cAFZ,CAIE,oBAAC,cAAD;KAAc,WAAU;eACrB,cAAc;IACH,CAAA,GACd,oBAAC,wBAAD;KACU;KACC;KACT,gBAAgB;KAEf;IACqB,CAAA,CACb;;GAEZ,cACC,oBAAC,mBAAD;IACE,OAAO;IACa;IACH;GAClB,CAAA;EAEI;;AAEb;AACA,gBAAgB,cAAc;AAM9B,SAAS,YAAY,EACnB,MACA,cACA,cAAc,kCACd,YAAY,qBACZ,YACA,UAAU,CAAC,GACX,SAAS,CAAC,GACV,UACA,eAAe,OACf,cACA,aAAa,OACb,aACA,qBAAqB,OACrB,iBACA,WACA,YAAY,iCACZ,QACA,YACmB;CACnB,MAAM,mBAAmB,oBAAoB;CAC7C,MAAM,mBAAmB,gBAAgB;CAEzC,OACE,oBAAC,eAAD;EACQ;EACQ;EACd,WAAW,GAAG,kCAAkC,SAAS;YAEzD,oBAAC,iBAAD;GACe;GACF;GACC;GACH;GACD;GACE;GACV,eAAe,eAAe,KAAK;GACrB;GACd,cAAc;GACF;GACC;GACO;GACH;GACN;GACH;GAEP;EACc,CAAA;CACJ,CAAA;AAEnB;AACA,YAAY,cAAc;AAY1B,SAAS,iBAAiB,EACxB,cAAc,kCACd,YAAY,qBACZ,YACA,UAAU,CAAC,GACX,SAAS,CAAC,GACV,UACA,eAAe,OACf,cACA,aAAa,OACb,aACA,qBAAqB,OACrB,iBACA,WACA,YAAY,iCACZ,QACA,YACwB;CACxB,MAAM,mBAAmB,oBAAoB;CAC7C,MAAM,mBAAmB,gBAAgB;CAEzC,OACE,oBAAC,OAAD;EACE,aAAU;EACV,WAAW,GAAG,+BAA+B,SAAS;YAEtD,oBAAC,iBAAD;GACe;GACF;GACC;GACH;GACD;GACE;GACI;GACd,cAAc;GACF;GACC;GACO;GACH;GACN;GACH;GAEP;EACc,CAAA;CACd,CAAA;AAET;AACA,iBAAiB,cAAc"}
package/dist/index228.js CHANGED
@@ -84,7 +84,7 @@ function NavAccountMenuTrigger({ avatar, name, email, badge, showLogoutButton, o
84
84
  }), /* @__PURE__ */ jsx("button", {
85
85
  type: "button",
86
86
  onClick: handleLogoutClick,
87
- className: "shrink-0 rounded-md p-1.5 text-text-quaternary transition-colors duration-200 ease-smooth hover:bg-muted hover:text-secondary-foreground focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring motion-reduce:transition-none",
87
+ className: "shrink-0 rounded-md p-1.5 text-muted-foreground transition-colors duration-200 ease-smooth hover:bg-muted hover:text-secondary-foreground focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring motion-reduce:transition-none",
88
88
  "aria-label": "Sign out",
89
89
  children: /* @__PURE__ */ jsx(LogOut, { className: "size-5" })
90
90
  })]
@@ -1 +1 @@
1
- {"version":3,"file":"index228.js","names":[],"sources":["../src/components/templates/NavAccountMenu/NavAccountMenu.tsx"],"sourcesContent":["'use client';\n\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { ChevronRight, LogOut } from 'lucide-react';\nimport * as React from 'react';\nimport { Switch } from '@/components/atoms/forms/Switch/Switch';\nimport { Kbd } from '@/components/molecules/data/Kbd';\nimport {\n PopoverRoot as PopoverBase,\n PopoverPopup as PopoverContentBase,\n PopoverTrigger as PopoverTriggerBase,\n} from '@/components/organisms/overlays/Popover';\nimport { useControllableState } from '@/hooks/use-controllable-state';\nimport { createSafeContext } from '@/lib/create-safe-context';\nimport { cn } from '@/lib/utils';\n\n// ============================================\n// Context for NavAccountMenu\n// ============================================\n\ninterface NavAccountMenuContextValue {\n type: 'card' | 'simple';\n open: boolean;\n onOpenChange: (open: boolean) => void;\n}\n\nconst [NavAccountMenuContext, useNavAccountMenuContext] =\n createSafeContext<NavAccountMenuContextValue>('NavAccountMenu');\n\n// ============================================\n// NavAccountMenu (Root)\n// ============================================\n\nexport interface NavAccountMenuProps {\n /** Trigger variant style */\n type?: 'card' | 'simple';\n /** Controlled open state */\n open?: boolean;\n /** Callback when open state changes */\n onOpenChange?: (open: boolean) => void;\n /** Initial open state for uncontrolled mode */\n defaultOpen?: boolean;\n /** Children (trigger + content) */\n children: React.ReactNode;\n}\n\nfunction NavAccountMenu({\n type = 'card',\n open: controlledOpen,\n defaultOpen = false,\n onOpenChange,\n children,\n}: NavAccountMenuProps) {\n const [open, handleOpenChange] = useControllableState({\n value: controlledOpen,\n defaultValue: defaultOpen,\n onChange: onOpenChange,\n });\n\n const contextValue = React.useMemo(\n () => ({\n type,\n open,\n onOpenChange: handleOpenChange,\n }),\n [type, open, handleOpenChange],\n );\n\n return (\n <NavAccountMenuContext.Provider value={contextValue}>\n <PopoverBase open={open} onOpenChange={handleOpenChange}>\n <div data-slot=\"nav-account-menu\">{children}</div>\n </PopoverBase>\n </NavAccountMenuContext.Provider>\n );\n}\n\n// ============================================\n// NavAccountMenuTrigger\n// ============================================\n\nconst triggerVariants = cva(\n 'flex items-center gap-4 w-full text-left cursor-pointer transition-colors duration-200 ease-smooth outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring motion-reduce:transition-none',\n {\n variants: {\n type: {\n card: 'bg-surface-1 border border-border rounded-xl shadow-xs p-3 hover:bg-surface-2',\n simple: 'border border-border px-2 py-3 hover:bg-surface-2 rounded-lg',\n },\n },\n defaultVariants: {\n type: 'card',\n },\n },\n);\n\nexport interface NavAccountMenuTriggerProps\n extends VariantProps<typeof triggerVariants> {\n /** Avatar element (use Avatar component) */\n avatar?: React.ReactNode;\n /** User display name */\n name: string;\n /** User email address */\n email?: string;\n /** Optional badge after name (e.g., \"External\" tag) */\n badge?: React.ReactNode;\n /** Show logout button instead of chevron (for 'simple' type) */\n showLogoutButton?: boolean;\n /** Logout callback for simple variant */\n onLogout?: () => void;\n /** Show only avatar without name/email - useful for collapsed sidebar */\n compact?: boolean;\n /** Additional className */\n className?: string;\n}\n\nfunction NavAccountMenuTrigger({\n avatar,\n name,\n email,\n badge,\n showLogoutButton,\n onLogout,\n compact = false,\n className,\n}: NavAccountMenuTriggerProps) {\n const { type, open } = useNavAccountMenuContext();\n\n const handleLogoutClick = (e: React.MouseEvent) => {\n e.stopPropagation();\n onLogout?.();\n };\n\n const avatarContent = avatar ? (\n <div className=\"shrink-0\">{avatar}</div>\n ) : null;\n const accountDetails = !compact ? (\n <div className=\"flex min-w-0 flex-1 flex-col\">\n <div className=\"flex min-w-0 items-center gap-2\">\n <span className=\"min-w-0 truncate text-sm font-semibold text-foreground\">\n {name}\n </span>\n {badge && <span className=\"shrink-0\">{badge}</span>}\n </div>\n {email && (\n <span className=\"truncate text-sm text-muted-foreground\">{email}</span>\n )}\n </div>\n ) : null;\n\n if (type === 'simple' && showLogoutButton && !compact) {\n return (\n <div\n data-slot=\"nav-account-menu-trigger\"\n className={cn(triggerVariants({ type }), 'group/trigger', className)}\n >\n <PopoverTriggerBase\n render={\n <button\n type=\"button\"\n aria-haspopup=\"true\"\n className=\"flex min-w-0 flex-1 items-center gap-4 text-left outline-none\"\n />\n }\n >\n {avatarContent}\n {accountDetails}\n </PopoverTriggerBase>\n <button\n type=\"button\"\n onClick={handleLogoutClick}\n className=\"shrink-0 rounded-md p-1.5 text-text-quaternary transition-colors duration-200 ease-smooth hover:bg-muted hover:text-secondary-foreground focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring motion-reduce:transition-none\"\n aria-label=\"Sign out\"\n >\n <LogOut className=\"size-5\" />\n </button>\n </div>\n );\n }\n\n return (\n <PopoverTriggerBase\n render={\n <button\n type=\"button\"\n data-slot=\"nav-account-menu-trigger\"\n aria-haspopup=\"true\"\n aria-label={compact ? `${name} account menu` : undefined}\n className={cn(\n triggerVariants({ type }),\n 'group/trigger',\n compact ? 'w-auto justify-center' : 'max-w-[280px]',\n className,\n )}\n />\n }\n >\n {avatarContent}\n {!compact && (\n <>\n {accountDetails}\n <ChevronRight\n className={cn(\n 'size-4 shrink-0 text-muted-foreground transition-transform duration-200 ease-smooth motion-reduce:transition-none',\n open ? 'rotate-180' : 'rtl:rotate-180',\n )}\n />\n </>\n )}\n </PopoverTriggerBase>\n );\n}\n\n// ============================================\n// NavAccountMenuContent\n// ============================================\n\nexport interface NavAccountMenuContentProps {\n /** Popover side positioning */\n side?: 'top' | 'right' | 'bottom' | 'left';\n /** Popover alignment */\n align?: 'start' | 'center' | 'end';\n /** Side offset */\n sideOffset?: number;\n /** Children */\n children: React.ReactNode;\n /** Additional className */\n className?: string;\n}\n\nfunction NavAccountMenuContent({\n side = 'right',\n align = 'end',\n sideOffset = 8,\n children,\n className,\n}: NavAccountMenuContentProps) {\n return (\n <PopoverContentBase\n side={side}\n align={align}\n sideOffset={sideOffset}\n aria-label=\"Account menu\"\n data-slot=\"nav-account-menu-content\"\n className={cn(\n 'w-[300px] max-w-[calc(100vw-2rem)] p-0 gap-0 bg-popover border border-border rounded-[14px] overflow-hidden',\n 'shadow-[0px_12px_16px_-4px_color-mix(in_srgb,var(--foreground)_8%,transparent),0px_4px_6px_-2px_color-mix(in_srgb,var(--foreground)_3%,transparent),0px_2px_2px_-1px_color-mix(in_srgb,var(--foreground)_4%,transparent)]',\n 'data-open:animate-in data-closed:animate-out',\n 'data-closed:fade-out-0 data-open:fade-in-0',\n 'data-closed:zoom-out-95 data-open:zoom-in-95',\n 'data-[side=bottom]:slide-in-from-top-2',\n 'data-[side=left]:slide-in-from-right-2',\n 'data-[side=right]:slide-in-from-left-2',\n 'data-[side=top]:slide-in-from-bottom-2',\n 'duration-200 motion-reduce:animate-none',\n className,\n )}\n >\n <div className=\"flex flex-col py-2\" role=\"menu\" aria-label=\"Account menu\">\n {children}\n </div>\n </PopoverContentBase>\n );\n}\n\n// ============================================\n// NavAccountMenuHeader\n// ============================================\n\nexport interface NavAccountMenuHeaderProps {\n /** Header title (e.g. \"Profile\") */\n title: string;\n /** Subtitle text or custom React node (e.g. \"Last login 22 May, 2026 11:30pm\") */\n subtitle?: React.ReactNode;\n /** Additional className */\n className?: string;\n}\n\nfunction NavAccountMenuHeader({\n title,\n subtitle,\n className,\n}: NavAccountMenuHeaderProps) {\n return (\n <div\n data-slot=\"nav-account-menu-header\"\n className={cn('px-6 pb-3 delight-fade-in', className)}\n >\n <p className=\"text-base font-semibold text-foreground\">{title}</p>\n {subtitle &&\n (typeof subtitle === 'string' ? (\n <p className=\"mt-2 text-sm text-muted-foreground\">{subtitle}</p>\n ) : (\n <div className=\"mt-2\">{subtitle}</div>\n ))}\n </div>\n );\n}\n\n// ============================================\n// NavAccountMenuSection\n// ============================================\n\nexport interface NavAccountMenuSectionProps {\n /** Optional section header label */\n label?: string;\n /** Show top border separator between sections */\n bordered?: boolean;\n /** Section content */\n children: React.ReactNode;\n /** Additional className */\n className?: string;\n}\n\nfunction NavAccountMenuSection({\n label,\n bordered = false,\n children,\n className,\n}: NavAccountMenuSectionProps) {\n return (\n <section\n data-slot=\"nav-account-menu-section\"\n aria-label={label}\n className={cn(\n 'flex flex-col gap-1 py-1.5',\n bordered && 'border-t border-border',\n className,\n )}\n >\n {label && (\n <div className=\"px-3 pt-1.5 pb-1\">\n <span className=\"text-xs font-semibold text-muted-foreground\">\n {label}\n </span>\n </div>\n )}\n {children}\n </section>\n );\n}\n\n// ============================================\n// NavAccountMenuItem\n// ============================================\n\n/**\n * Props passed to the render function for custom menu item rendering.\n */\nexport interface NavAccountMenuItemRenderProps {\n /** Combined className for styling */\n className: string;\n /** Click handler that closes menu and triggers onSelect */\n onClick: () => void;\n /** Menu item content (icon, label, shortcut) */\n children: React.ReactNode;\n}\n\n/**\n * Render prop type for polymorphic rendering.\n * Accepts a function that receives props and returns an element.\n */\ntype NavAccountMenuItemRenderFn = (\n props: NavAccountMenuItemRenderProps,\n) => React.ReactElement;\n\nexport interface NavAccountMenuItemProps {\n /** Left icon (20px) */\n icon?: React.ReactNode;\n /** Keyboard shortcut display */\n shortcut?: string;\n /** Destructive styling (red) */\n destructive?: boolean;\n /** Disabled state */\n disabled?: boolean;\n /** Selection callback */\n onSelect?: () => void;\n /**\n * Render prop for polymorphic rendering.\n * Use this to render the menu item as a different element (e.g., link).\n * @example\n * <NavAccountMenuItem\n * icon={<User01 />}\n * render={(props) => <a {...props} href=\"/profile\" />}\n * >\n * View profile\n * </NavAccountMenuItem>\n */\n render?: NavAccountMenuItemRenderFn;\n /** Label text */\n children: React.ReactNode;\n /** Additional className */\n className?: string;\n}\n\nfunction NavAccountMenuItem({\n icon,\n shortcut,\n destructive = false,\n disabled = false,\n onSelect,\n render,\n children,\n className,\n}: NavAccountMenuItemProps) {\n const { onOpenChange } = useNavAccountMenuContext();\n\n const handleClick = () => {\n if (disabled) return;\n onSelect?.();\n onOpenChange(false);\n };\n\n const content = (\n <div className=\"flex flex-1 gap-2 items-center overflow-hidden p-2 rounded-md transition-[background-color] duration-200 ease-smooth delight-selection-press motion-reduce:transition-none\">\n <div className=\"flex flex-1 gap-2 items-center min-w-0\">\n {icon && (\n <span\n className={cn(\n 'shrink-0 [&>svg]:size-4 transition-transform duration-200 ease-smooth group-hover/menuitem:translate-x-0.5 motion-reduce:transition-none',\n destructive ? 'text-destructive' : 'text-foreground',\n )}\n >\n {icon}\n </span>\n )}\n <span\n className={cn(\n 'flex-1 text-sm truncate',\n destructive ? 'text-destructive' : 'text-secondary-foreground',\n )}\n >\n {children}\n </span>\n </div>\n {shortcut && (\n <Kbd variant=\"outline\" size=\"xs\" className=\"shrink-0\">\n {shortcut}\n </Kbd>\n )}\n </div>\n );\n\n const baseClassName = cn(\n 'group/menuitem flex items-center px-1.5 py-0 w-full text-left cursor-pointer outline-none',\n 'hover:[&>div]:bg-muted focus-visible:[&>div]:bg-muted',\n 'focus-visible:outline-2 focus-visible:outline-offset-[-2px] focus-visible:outline-ring',\n disabled && 'pointer-events-none opacity-50',\n className,\n );\n\n if (render) {\n return render({\n className: baseClassName,\n onClick: handleClick,\n children: content,\n });\n }\n\n return (\n <button\n type=\"button\"\n role=\"menuitem\"\n data-slot=\"nav-account-menu-item\"\n className={baseClassName}\n onClick={handleClick}\n disabled={disabled}\n aria-disabled={disabled || undefined}\n >\n {content}\n </button>\n );\n}\n\n// ============================================\n// NavAccountMenuAccount\n// ============================================\n\nexport interface NavAccountMenuAccountProps {\n /** Avatar element */\n avatar?: React.ReactNode;\n /** Account display name */\n name: string;\n /** Account email */\n email: string;\n /** Whether this account is currently selected */\n selected?: boolean;\n /** Selection callback */\n onSelect?: () => void;\n /** Additional className */\n className?: string;\n}\n\nfunction NavAccountMenuAccount({\n avatar,\n name,\n email,\n selected = false,\n onSelect,\n className,\n}: NavAccountMenuAccountProps) {\n return (\n <div\n data-slot=\"nav-account-menu-account\"\n className={cn('flex items-center px-1.5 py-0 w-full', className)}\n >\n <button\n type=\"button\"\n role=\"menuitemradio\"\n aria-checked={selected}\n aria-label={`Switch to ${name} (${email})`}\n className={cn(\n 'relative flex flex-1 gap-2 items-center overflow-hidden px-2 py-1.5 rounded-md cursor-pointer outline-none',\n 'hover:bg-muted focus-visible:bg-muted',\n 'transition-colors duration-200 ease-smooth motion-reduce:transition-none',\n 'focus-visible:outline-2 focus-visible:outline-offset-[-2px] focus-visible:outline-ring',\n 'text-left',\n selected && 'bg-surface-2',\n )}\n onClick={onSelect}\n >\n {avatar && <div className=\"shrink-0\">{avatar}</div>}\n <div className=\"flex flex-col min-w-0 flex-1\">\n <span className=\"text-sm font-semibold text-foreground truncate\">\n {name}\n </span>\n <span className=\"text-sm text-muted-foreground truncate\">\n {email}\n </span>\n </div>\n {/* Radio indicator */}\n <div\n aria-hidden=\"true\"\n className={cn(\n 'size-4 rounded-full border-2 shrink-0 flex items-center justify-center transition-colors duration-200 ease-smooth motion-reduce:transition-none',\n selected\n ? 'bg-primary border-primary'\n : 'border-border bg-transparent',\n )}\n >\n {selected && (\n <div className=\"size-1.5 rounded-full bg-background delight-check-bounce\" />\n )}\n </div>\n </button>\n </div>\n );\n}\n\n// ============================================\n// NavAccountMenuSeparator\n// ============================================\n\nexport interface NavAccountMenuSeparatorProps {\n /** Additional className */\n className?: string;\n}\n\nfunction NavAccountMenuSeparator({ className }: NavAccountMenuSeparatorProps) {\n return (\n <hr\n data-slot=\"nav-account-menu-separator\"\n className={cn('h-px border-0 bg-border mx-5', className)}\n />\n );\n}\n\n// ============================================\n// NavAccountMenuFooter\n// ============================================\n\nexport interface NavAccountMenuFooterProps {\n /** Footer content (typically buttons) */\n children: React.ReactNode;\n /** Additional className */\n className?: string;\n}\n\nfunction NavAccountMenuFooter({\n children,\n className,\n}: NavAccountMenuFooterProps) {\n return (\n <div\n data-slot=\"nav-account-menu-footer\"\n className={cn('flex items-center justify-center px-5 pt-4', className)}\n >\n {children}\n </div>\n );\n}\n\n// ============================================\n// NavAccountMenuThemeSwitch (uses Switch theme variant)\n// ============================================\n\nexport interface NavAccountMenuThemeSwitchProps {\n /** Switch theme variant to render */\n variant?:\n | 'theme-gradient'\n | 'theme-switch'\n | 'theme-pill'\n | 'theme-segmented';\n /** Switch size */\n size?: 'sm' | 'md' | 'lg';\n /** Controlled checked state (dark = checked) */\n checked?: boolean;\n /** Callback when checked state changes */\n onCheckedChange?: (checked: boolean) => void;\n /** Optional label displayed next to the switch (e.g. \"Light Mode\") */\n label?: string;\n /** Additional className */\n className?: string;\n}\n\nfunction NavAccountMenuThemeSwitch({\n variant = 'theme-gradient',\n size = 'sm',\n checked,\n onCheckedChange,\n label,\n className,\n}: NavAccountMenuThemeSwitchProps) {\n const switchId = React.useId();\n const labelId = label ? `${switchId}-label` : undefined;\n\n return (\n <div\n data-slot=\"nav-account-menu-theme-switch\"\n className={cn('flex items-center px-1.5 py-0', className)}\n >\n <div className=\"flex items-center gap-2.5 p-2\">\n <Switch\n id={switchId}\n variant={variant}\n size={size}\n checked={checked}\n onCheckedChange={onCheckedChange}\n aria-labelledby={labelId}\n aria-label={label ? undefined : 'Theme selector'}\n />\n {label && (\n <label\n htmlFor={switchId}\n id={labelId}\n className=\"cursor-pointer text-sm text-secondary-foreground\"\n >\n {label}\n </label>\n )}\n </div>\n </div>\n );\n}\n\n// ============================================\n// Display Names\n// ============================================\n\nNavAccountMenu.displayName = 'NavAccountMenu';\nNavAccountMenuTrigger.displayName = 'NavAccountMenuTrigger';\nNavAccountMenuContent.displayName = 'NavAccountMenuContent';\nNavAccountMenuHeader.displayName = 'NavAccountMenuHeader';\nNavAccountMenuSection.displayName = 'NavAccountMenuSection';\nNavAccountMenuItem.displayName = 'NavAccountMenuItem';\nNavAccountMenuAccount.displayName = 'NavAccountMenuAccount';\nNavAccountMenuSeparator.displayName = 'NavAccountMenuSeparator';\nNavAccountMenuFooter.displayName = 'NavAccountMenuFooter';\nNavAccountMenuThemeSwitch.displayName = 'NavAccountMenuThemeSwitch';\n\n// ============================================\n// Exports\n// ============================================\n\nexport {\n NavAccountMenu,\n NavAccountMenuAccount,\n NavAccountMenuContent,\n NavAccountMenuFooter,\n NavAccountMenuHeader,\n NavAccountMenuItem,\n NavAccountMenuSection,\n NavAccountMenuSeparator,\n NavAccountMenuThemeSwitch,\n NavAccountMenuTrigger,\n triggerVariants as navAccountMenuTriggerVariants,\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"index228.js","names":[],"sources":["../src/components/templates/NavAccountMenu/NavAccountMenu.tsx"],"sourcesContent":["'use client';\n\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { ChevronRight, LogOut } from 'lucide-react';\nimport * as React from 'react';\nimport { Switch } from '@/components/atoms/forms/Switch/Switch';\nimport { Kbd } from '@/components/molecules/data/Kbd';\nimport {\n PopoverRoot as PopoverBase,\n PopoverPopup as PopoverContentBase,\n PopoverTrigger as PopoverTriggerBase,\n} from '@/components/organisms/overlays/Popover';\nimport { useControllableState } from '@/hooks/use-controllable-state';\nimport { createSafeContext } from '@/lib/create-safe-context';\nimport { cn } from '@/lib/utils';\n\n// ============================================\n// Context for NavAccountMenu\n// ============================================\n\ninterface NavAccountMenuContextValue {\n type: 'card' | 'simple';\n open: boolean;\n onOpenChange: (open: boolean) => void;\n}\n\nconst [NavAccountMenuContext, useNavAccountMenuContext] =\n createSafeContext<NavAccountMenuContextValue>('NavAccountMenu');\n\n// ============================================\n// NavAccountMenu (Root)\n// ============================================\n\nexport interface NavAccountMenuProps {\n /** Trigger variant style */\n type?: 'card' | 'simple';\n /** Controlled open state */\n open?: boolean;\n /** Callback when open state changes */\n onOpenChange?: (open: boolean) => void;\n /** Initial open state for uncontrolled mode */\n defaultOpen?: boolean;\n /** Children (trigger + content) */\n children: React.ReactNode;\n}\n\nfunction NavAccountMenu({\n type = 'card',\n open: controlledOpen,\n defaultOpen = false,\n onOpenChange,\n children,\n}: NavAccountMenuProps) {\n const [open, handleOpenChange] = useControllableState({\n value: controlledOpen,\n defaultValue: defaultOpen,\n onChange: onOpenChange,\n });\n\n const contextValue = React.useMemo(\n () => ({\n type,\n open,\n onOpenChange: handleOpenChange,\n }),\n [type, open, handleOpenChange],\n );\n\n return (\n <NavAccountMenuContext.Provider value={contextValue}>\n <PopoverBase open={open} onOpenChange={handleOpenChange}>\n <div data-slot=\"nav-account-menu\">{children}</div>\n </PopoverBase>\n </NavAccountMenuContext.Provider>\n );\n}\n\n// ============================================\n// NavAccountMenuTrigger\n// ============================================\n\nconst triggerVariants = cva(\n 'flex items-center gap-4 w-full text-left cursor-pointer transition-colors duration-200 ease-smooth outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring motion-reduce:transition-none',\n {\n variants: {\n type: {\n card: 'bg-surface-1 border border-border rounded-xl shadow-xs p-3 hover:bg-surface-2',\n simple: 'border border-border px-2 py-3 hover:bg-surface-2 rounded-lg',\n },\n },\n defaultVariants: {\n type: 'card',\n },\n },\n);\n\nexport interface NavAccountMenuTriggerProps\n extends VariantProps<typeof triggerVariants> {\n /** Avatar element (use Avatar component) */\n avatar?: React.ReactNode;\n /** User display name */\n name: string;\n /** User email address */\n email?: string;\n /** Optional badge after name (e.g., \"External\" tag) */\n badge?: React.ReactNode;\n /** Show logout button instead of chevron (for 'simple' type) */\n showLogoutButton?: boolean;\n /** Logout callback for simple variant */\n onLogout?: () => void;\n /** Show only avatar without name/email - useful for collapsed sidebar */\n compact?: boolean;\n /** Additional className */\n className?: string;\n}\n\nfunction NavAccountMenuTrigger({\n avatar,\n name,\n email,\n badge,\n showLogoutButton,\n onLogout,\n compact = false,\n className,\n}: NavAccountMenuTriggerProps) {\n const { type, open } = useNavAccountMenuContext();\n\n const handleLogoutClick = (e: React.MouseEvent) => {\n e.stopPropagation();\n onLogout?.();\n };\n\n const avatarContent = avatar ? (\n <div className=\"shrink-0\">{avatar}</div>\n ) : null;\n const accountDetails = !compact ? (\n <div className=\"flex min-w-0 flex-1 flex-col\">\n <div className=\"flex min-w-0 items-center gap-2\">\n <span className=\"min-w-0 truncate text-sm font-semibold text-foreground\">\n {name}\n </span>\n {badge && <span className=\"shrink-0\">{badge}</span>}\n </div>\n {email && (\n <span className=\"truncate text-sm text-muted-foreground\">{email}</span>\n )}\n </div>\n ) : null;\n\n if (type === 'simple' && showLogoutButton && !compact) {\n return (\n <div\n data-slot=\"nav-account-menu-trigger\"\n className={cn(triggerVariants({ type }), 'group/trigger', className)}\n >\n <PopoverTriggerBase\n render={\n <button\n type=\"button\"\n aria-haspopup=\"true\"\n className=\"flex min-w-0 flex-1 items-center gap-4 text-left outline-none\"\n />\n }\n >\n {avatarContent}\n {accountDetails}\n </PopoverTriggerBase>\n <button\n type=\"button\"\n onClick={handleLogoutClick}\n className=\"shrink-0 rounded-md p-1.5 text-muted-foreground transition-colors duration-200 ease-smooth hover:bg-muted hover:text-secondary-foreground focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring motion-reduce:transition-none\"\n aria-label=\"Sign out\"\n >\n <LogOut className=\"size-5\" />\n </button>\n </div>\n );\n }\n\n return (\n <PopoverTriggerBase\n render={\n <button\n type=\"button\"\n data-slot=\"nav-account-menu-trigger\"\n aria-haspopup=\"true\"\n aria-label={compact ? `${name} account menu` : undefined}\n className={cn(\n triggerVariants({ type }),\n 'group/trigger',\n compact ? 'w-auto justify-center' : 'max-w-[280px]',\n className,\n )}\n />\n }\n >\n {avatarContent}\n {!compact && (\n <>\n {accountDetails}\n <ChevronRight\n className={cn(\n 'size-4 shrink-0 text-muted-foreground transition-transform duration-200 ease-smooth motion-reduce:transition-none',\n open ? 'rotate-180' : 'rtl:rotate-180',\n )}\n />\n </>\n )}\n </PopoverTriggerBase>\n );\n}\n\n// ============================================\n// NavAccountMenuContent\n// ============================================\n\nexport interface NavAccountMenuContentProps {\n /** Popover side positioning */\n side?: 'top' | 'right' | 'bottom' | 'left';\n /** Popover alignment */\n align?: 'start' | 'center' | 'end';\n /** Side offset */\n sideOffset?: number;\n /** Children */\n children: React.ReactNode;\n /** Additional className */\n className?: string;\n}\n\nfunction NavAccountMenuContent({\n side = 'right',\n align = 'end',\n sideOffset = 8,\n children,\n className,\n}: NavAccountMenuContentProps) {\n return (\n <PopoverContentBase\n side={side}\n align={align}\n sideOffset={sideOffset}\n aria-label=\"Account menu\"\n data-slot=\"nav-account-menu-content\"\n className={cn(\n 'w-[300px] max-w-[calc(100vw-2rem)] p-0 gap-0 bg-popover border border-border rounded-[14px] overflow-hidden',\n 'shadow-[0px_12px_16px_-4px_color-mix(in_srgb,var(--foreground)_8%,transparent),0px_4px_6px_-2px_color-mix(in_srgb,var(--foreground)_3%,transparent),0px_2px_2px_-1px_color-mix(in_srgb,var(--foreground)_4%,transparent)]',\n 'data-open:animate-in data-closed:animate-out',\n 'data-closed:fade-out-0 data-open:fade-in-0',\n 'data-closed:zoom-out-95 data-open:zoom-in-95',\n 'data-[side=bottom]:slide-in-from-top-2',\n 'data-[side=left]:slide-in-from-right-2',\n 'data-[side=right]:slide-in-from-left-2',\n 'data-[side=top]:slide-in-from-bottom-2',\n 'duration-200 motion-reduce:animate-none',\n className,\n )}\n >\n <div className=\"flex flex-col py-2\" role=\"menu\" aria-label=\"Account menu\">\n {children}\n </div>\n </PopoverContentBase>\n );\n}\n\n// ============================================\n// NavAccountMenuHeader\n// ============================================\n\nexport interface NavAccountMenuHeaderProps {\n /** Header title (e.g. \"Profile\") */\n title: string;\n /** Subtitle text or custom React node (e.g. \"Last login 22 May, 2026 11:30pm\") */\n subtitle?: React.ReactNode;\n /** Additional className */\n className?: string;\n}\n\nfunction NavAccountMenuHeader({\n title,\n subtitle,\n className,\n}: NavAccountMenuHeaderProps) {\n return (\n <div\n data-slot=\"nav-account-menu-header\"\n className={cn('px-6 pb-3 delight-fade-in', className)}\n >\n <p className=\"text-base font-semibold text-foreground\">{title}</p>\n {subtitle &&\n (typeof subtitle === 'string' ? (\n <p className=\"mt-2 text-sm text-muted-foreground\">{subtitle}</p>\n ) : (\n <div className=\"mt-2\">{subtitle}</div>\n ))}\n </div>\n );\n}\n\n// ============================================\n// NavAccountMenuSection\n// ============================================\n\nexport interface NavAccountMenuSectionProps {\n /** Optional section header label */\n label?: string;\n /** Show top border separator between sections */\n bordered?: boolean;\n /** Section content */\n children: React.ReactNode;\n /** Additional className */\n className?: string;\n}\n\nfunction NavAccountMenuSection({\n label,\n bordered = false,\n children,\n className,\n}: NavAccountMenuSectionProps) {\n return (\n <section\n data-slot=\"nav-account-menu-section\"\n aria-label={label}\n className={cn(\n 'flex flex-col gap-1 py-1.5',\n bordered && 'border-t border-border',\n className,\n )}\n >\n {label && (\n <div className=\"px-3 pt-1.5 pb-1\">\n <span className=\"text-xs font-semibold text-muted-foreground\">\n {label}\n </span>\n </div>\n )}\n {children}\n </section>\n );\n}\n\n// ============================================\n// NavAccountMenuItem\n// ============================================\n\n/**\n * Props passed to the render function for custom menu item rendering.\n */\nexport interface NavAccountMenuItemRenderProps {\n /** Combined className for styling */\n className: string;\n /** Click handler that closes menu and triggers onSelect */\n onClick: () => void;\n /** Menu item content (icon, label, shortcut) */\n children: React.ReactNode;\n}\n\n/**\n * Render prop type for polymorphic rendering.\n * Accepts a function that receives props and returns an element.\n */\ntype NavAccountMenuItemRenderFn = (\n props: NavAccountMenuItemRenderProps,\n) => React.ReactElement;\n\nexport interface NavAccountMenuItemProps {\n /** Left icon (20px) */\n icon?: React.ReactNode;\n /** Keyboard shortcut display */\n shortcut?: string;\n /** Destructive styling (red) */\n destructive?: boolean;\n /** Disabled state */\n disabled?: boolean;\n /** Selection callback */\n onSelect?: () => void;\n /**\n * Render prop for polymorphic rendering.\n * Use this to render the menu item as a different element (e.g., link).\n * @example\n * <NavAccountMenuItem\n * icon={<User01 />}\n * render={(props) => <a {...props} href=\"/profile\" />}\n * >\n * View profile\n * </NavAccountMenuItem>\n */\n render?: NavAccountMenuItemRenderFn;\n /** Label text */\n children: React.ReactNode;\n /** Additional className */\n className?: string;\n}\n\nfunction NavAccountMenuItem({\n icon,\n shortcut,\n destructive = false,\n disabled = false,\n onSelect,\n render,\n children,\n className,\n}: NavAccountMenuItemProps) {\n const { onOpenChange } = useNavAccountMenuContext();\n\n const handleClick = () => {\n if (disabled) return;\n onSelect?.();\n onOpenChange(false);\n };\n\n const content = (\n <div className=\"flex flex-1 gap-2 items-center overflow-hidden p-2 rounded-md transition-[background-color] duration-200 ease-smooth delight-selection-press motion-reduce:transition-none\">\n <div className=\"flex flex-1 gap-2 items-center min-w-0\">\n {icon && (\n <span\n className={cn(\n 'shrink-0 [&>svg]:size-4 transition-transform duration-200 ease-smooth group-hover/menuitem:translate-x-0.5 motion-reduce:transition-none',\n destructive ? 'text-destructive' : 'text-foreground',\n )}\n >\n {icon}\n </span>\n )}\n <span\n className={cn(\n 'flex-1 text-sm truncate',\n destructive ? 'text-destructive' : 'text-secondary-foreground',\n )}\n >\n {children}\n </span>\n </div>\n {shortcut && (\n <Kbd variant=\"outline\" size=\"xs\" className=\"shrink-0\">\n {shortcut}\n </Kbd>\n )}\n </div>\n );\n\n const baseClassName = cn(\n 'group/menuitem flex items-center px-1.5 py-0 w-full text-left cursor-pointer outline-none',\n 'hover:[&>div]:bg-muted focus-visible:[&>div]:bg-muted',\n 'focus-visible:outline-2 focus-visible:outline-offset-[-2px] focus-visible:outline-ring',\n disabled && 'pointer-events-none opacity-50',\n className,\n );\n\n if (render) {\n return render({\n className: baseClassName,\n onClick: handleClick,\n children: content,\n });\n }\n\n return (\n <button\n type=\"button\"\n role=\"menuitem\"\n data-slot=\"nav-account-menu-item\"\n className={baseClassName}\n onClick={handleClick}\n disabled={disabled}\n aria-disabled={disabled || undefined}\n >\n {content}\n </button>\n );\n}\n\n// ============================================\n// NavAccountMenuAccount\n// ============================================\n\nexport interface NavAccountMenuAccountProps {\n /** Avatar element */\n avatar?: React.ReactNode;\n /** Account display name */\n name: string;\n /** Account email */\n email: string;\n /** Whether this account is currently selected */\n selected?: boolean;\n /** Selection callback */\n onSelect?: () => void;\n /** Additional className */\n className?: string;\n}\n\nfunction NavAccountMenuAccount({\n avatar,\n name,\n email,\n selected = false,\n onSelect,\n className,\n}: NavAccountMenuAccountProps) {\n return (\n <div\n data-slot=\"nav-account-menu-account\"\n className={cn('flex items-center px-1.5 py-0 w-full', className)}\n >\n <button\n type=\"button\"\n role=\"menuitemradio\"\n aria-checked={selected}\n aria-label={`Switch to ${name} (${email})`}\n className={cn(\n 'relative flex flex-1 gap-2 items-center overflow-hidden px-2 py-1.5 rounded-md cursor-pointer outline-none',\n 'hover:bg-muted focus-visible:bg-muted',\n 'transition-colors duration-200 ease-smooth motion-reduce:transition-none',\n 'focus-visible:outline-2 focus-visible:outline-offset-[-2px] focus-visible:outline-ring',\n 'text-left',\n selected && 'bg-surface-2',\n )}\n onClick={onSelect}\n >\n {avatar && <div className=\"shrink-0\">{avatar}</div>}\n <div className=\"flex flex-col min-w-0 flex-1\">\n <span className=\"text-sm font-semibold text-foreground truncate\">\n {name}\n </span>\n <span className=\"text-sm text-muted-foreground truncate\">\n {email}\n </span>\n </div>\n {/* Radio indicator */}\n <div\n aria-hidden=\"true\"\n className={cn(\n 'size-4 rounded-full border-2 shrink-0 flex items-center justify-center transition-colors duration-200 ease-smooth motion-reduce:transition-none',\n selected\n ? 'bg-primary border-primary'\n : 'border-border bg-transparent',\n )}\n >\n {selected && (\n <div className=\"size-1.5 rounded-full bg-background delight-check-bounce\" />\n )}\n </div>\n </button>\n </div>\n );\n}\n\n// ============================================\n// NavAccountMenuSeparator\n// ============================================\n\nexport interface NavAccountMenuSeparatorProps {\n /** Additional className */\n className?: string;\n}\n\nfunction NavAccountMenuSeparator({ className }: NavAccountMenuSeparatorProps) {\n return (\n <hr\n data-slot=\"nav-account-menu-separator\"\n className={cn('h-px border-0 bg-border mx-5', className)}\n />\n );\n}\n\n// ============================================\n// NavAccountMenuFooter\n// ============================================\n\nexport interface NavAccountMenuFooterProps {\n /** Footer content (typically buttons) */\n children: React.ReactNode;\n /** Additional className */\n className?: string;\n}\n\nfunction NavAccountMenuFooter({\n children,\n className,\n}: NavAccountMenuFooterProps) {\n return (\n <div\n data-slot=\"nav-account-menu-footer\"\n className={cn('flex items-center justify-center px-5 pt-4', className)}\n >\n {children}\n </div>\n );\n}\n\n// ============================================\n// NavAccountMenuThemeSwitch (uses Switch theme variant)\n// ============================================\n\nexport interface NavAccountMenuThemeSwitchProps {\n /** Switch theme variant to render */\n variant?:\n | 'theme-gradient'\n | 'theme-switch'\n | 'theme-pill'\n | 'theme-segmented';\n /** Switch size */\n size?: 'sm' | 'md' | 'lg';\n /** Controlled checked state (dark = checked) */\n checked?: boolean;\n /** Callback when checked state changes */\n onCheckedChange?: (checked: boolean) => void;\n /** Optional label displayed next to the switch (e.g. \"Light Mode\") */\n label?: string;\n /** Additional className */\n className?: string;\n}\n\nfunction NavAccountMenuThemeSwitch({\n variant = 'theme-gradient',\n size = 'sm',\n checked,\n onCheckedChange,\n label,\n className,\n}: NavAccountMenuThemeSwitchProps) {\n const switchId = React.useId();\n const labelId = label ? `${switchId}-label` : undefined;\n\n return (\n <div\n data-slot=\"nav-account-menu-theme-switch\"\n className={cn('flex items-center px-1.5 py-0', className)}\n >\n <div className=\"flex items-center gap-2.5 p-2\">\n <Switch\n id={switchId}\n variant={variant}\n size={size}\n checked={checked}\n onCheckedChange={onCheckedChange}\n aria-labelledby={labelId}\n aria-label={label ? undefined : 'Theme selector'}\n />\n {label && (\n <label\n htmlFor={switchId}\n id={labelId}\n className=\"cursor-pointer text-sm text-secondary-foreground\"\n >\n {label}\n </label>\n )}\n </div>\n </div>\n );\n}\n\n// ============================================\n// Display Names\n// ============================================\n\nNavAccountMenu.displayName = 'NavAccountMenu';\nNavAccountMenuTrigger.displayName = 'NavAccountMenuTrigger';\nNavAccountMenuContent.displayName = 'NavAccountMenuContent';\nNavAccountMenuHeader.displayName = 'NavAccountMenuHeader';\nNavAccountMenuSection.displayName = 'NavAccountMenuSection';\nNavAccountMenuItem.displayName = 'NavAccountMenuItem';\nNavAccountMenuAccount.displayName = 'NavAccountMenuAccount';\nNavAccountMenuSeparator.displayName = 'NavAccountMenuSeparator';\nNavAccountMenuFooter.displayName = 'NavAccountMenuFooter';\nNavAccountMenuThemeSwitch.displayName = 'NavAccountMenuThemeSwitch';\n\n// ============================================\n// Exports\n// ============================================\n\nexport {\n NavAccountMenu,\n NavAccountMenuAccount,\n NavAccountMenuContent,\n NavAccountMenuFooter,\n NavAccountMenuHeader,\n NavAccountMenuItem,\n NavAccountMenuSection,\n NavAccountMenuSeparator,\n NavAccountMenuThemeSwitch,\n NavAccountMenuTrigger,\n triggerVariants as navAccountMenuTriggerVariants,\n};\n"],"mappings":"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"}
package/dist/index229.js CHANGED
@@ -24,7 +24,7 @@ function AuthPasswordInput({ endIcon, visibilityLabel = "password", ...props })
24
24
  "aria-pressed": isVisible,
25
25
  title: label,
26
26
  onClick: () => setIsVisible((value) => !value),
27
- className: "pointer-events-auto inline-flex size-5 items-center justify-center rounded-sm text-text-quaternary transition-colors duration-150 ease-smooth hover:text-secondary-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
27
+ className: "pointer-events-auto inline-flex size-5 items-center justify-center rounded-sm text-muted-foreground transition-colors duration-150 ease-smooth hover:text-secondary-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
28
28
  children: /* @__PURE__ */ jsx(isVisible ? EyeOff : Eye, {
29
29
  "aria-hidden": true,
30
30
  className: "size-4"
@@ -1 +1 @@
1
- {"version":3,"file":"index229.js","names":[],"sources":["../src/components/pages/_auth/auth-page-utils.tsx"],"sourcesContent":["'use client';\n\nimport { Eye, EyeOff } from 'lucide-react';\nimport * as React from 'react';\nimport { Button } from '@/components/atoms/buttons/Button';\nimport { Input, type InputProps } from '@/components/atoms/forms/Input';\nimport { Separator } from '@/components/atoms/layout/Separator';\nimport type {\n AuthPageAction,\n AuthPageAsideConfig,\n} from '@/components/templates/AuthPageLayout';\nimport { renderActionElement } from '@/components/templates/AuthPageLayout';\nimport { cn } from '@/lib/utils';\n\nexport interface AuthFormProps\n extends Omit<React.ComponentProps<'form'>, 'children'> {\n children: React.ReactNode;\n}\n\ntype ActionButtonRenderProps = React.ComponentProps<'button'>;\ntype ActionButtonType = React.ComponentProps<'button'>['type'];\ntype ActionButtonRender = (\n props: ActionButtonRenderProps,\n) => React.ReactElement;\ntype ActionRenderTargetProps = Omit<\n ActionButtonRenderProps,\n 'disabled' | 'ref' | 'role' | 'tabIndex' | 'type'\n>;\ntype ActionAnchorProps = Omit<React.ComponentProps<'a'>, 'href'>;\n\ninterface AuthPrimaryButtonProps {\n children: React.ReactNode;\n loading?: boolean;\n}\n\ninterface AuthActionButtonProps {\n action: AuthPageAction;\n loading?: boolean;\n}\n\ninterface AuthActionProps {\n action: AuthPageAction;\n}\n\ninterface AuthInlineActionProps {\n prefix: React.ReactNode;\n action: AuthPageAction;\n}\n\ninterface AuthSocialDividerProps {\n label: React.ReactNode;\n}\n\ninterface AuthSsoActionsProps {\n actions?: AuthPageAction[];\n}\n\ninterface AuthPasswordInputProps extends InputProps {\n visibilityLabel?: string;\n}\n\nexport function AuthForm({\n children,\n className,\n ...props\n}: AuthFormProps): React.ReactElement {\n return (\n <form className={cn('flex flex-col gap-6', className)} {...props}>\n {children}\n </form>\n );\n}\n\nexport function AuthPasswordInput({\n endIcon,\n visibilityLabel = 'password',\n ...props\n}: AuthPasswordInputProps): React.ReactElement {\n const [isVisible, setIsVisible] = React.useState(false);\n const label = `${isVisible ? 'Hide' : 'Show'} ${visibilityLabel}`;\n const VisibilityIcon = isVisible ? EyeOff : Eye;\n const toggle = (\n <button\n type=\"button\"\n aria-label={label}\n aria-pressed={isVisible}\n title={label}\n onClick={() => setIsVisible((value) => !value)}\n className=\"pointer-events-auto inline-flex size-5 items-center justify-center rounded-sm text-text-quaternary transition-colors duration-150 ease-smooth hover:text-secondary-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background\"\n >\n <VisibilityIcon aria-hidden className=\"size-4\" />\n </button>\n );\n\n return (\n <Input\n {...props}\n type={isVisible ? 'text' : 'password'}\n endIcon={\n endIcon ? (\n <span className=\"pointer-events-auto inline-flex items-center gap-2\">\n {endIcon}\n {toggle}\n </span>\n ) : (\n toggle\n )\n }\n />\n );\n}\n\nexport function AuthPrimaryButton({\n children,\n loading,\n}: AuthPrimaryButtonProps): React.ReactElement {\n return (\n <Button\n appearance=\"solid\"\n loading={loading}\n shape=\"rounded\"\n size=\"md\"\n type=\"submit\"\n className=\"w-full\"\n >\n {children}\n </Button>\n );\n}\n\nfunction getNonNativeActionProps({\n disabled: _disabled,\n ref: _ref,\n role: _role,\n tabIndex: _tabIndex,\n type: _type,\n ...props\n}: ActionButtonRenderProps): ActionRenderTargetProps {\n return props;\n}\n\nfunction renderActionLink(href: string): ActionButtonRender {\n return function renderLinkAction(\n props: ActionButtonRenderProps,\n ): React.ReactElement {\n const anchorProps = getNonNativeActionProps(props) as ActionAnchorProps;\n return <a {...anchorProps} href={href} />;\n };\n}\n\nfunction renderCustomActionElement(action: AuthPageAction): ActionButtonRender {\n return function renderCustomAction(\n buttonProps: ActionButtonRenderProps,\n ): React.ReactElement {\n const props = getNonNativeActionProps(buttonProps);\n if (!action.render) {\n return <button type=\"button\" {...props} />;\n }\n\n return React.cloneElement(action.render, {\n ...props,\n className: cn(props.className, action.render.props.className),\n onClick: action.onClick ?? action.render.props.onClick ?? props.onClick,\n children: action.render.props.children ?? props.children ?? action.label,\n });\n };\n}\n\nfunction renderActionButton(\n action: AuthPageAction,\n): React.ReactElement | ActionButtonRender {\n if (action.render) {\n return renderCustomActionElement(action);\n }\n\n if (action.href) {\n return renderActionLink(action.href);\n }\n\n return <button type=\"button\">{action.label}</button>;\n}\n\nfunction getPrimaryActionButtonType(\n action: AuthPageAction,\n isPolymorphic: boolean,\n): ActionButtonType {\n if (isPolymorphic) {\n return undefined;\n }\n\n if (action.onClick) {\n return 'button';\n }\n\n return 'submit';\n}\n\nexport function AuthPrimaryActionButton({\n action,\n loading,\n}: AuthActionButtonProps): React.ReactElement {\n const isPolymorphic = !!(action.href || action.render);\n const supportsLoading = !isPolymorphic;\n\n return (\n <Button\n appearance=\"solid\"\n loading={supportsLoading ? loading : undefined}\n nativeButton={isPolymorphic ? false : undefined}\n render={isPolymorphic ? renderActionButton(action) : undefined}\n shape=\"rounded\"\n size=\"md\"\n type={getPrimaryActionButtonType(action, isPolymorphic)}\n onClick={action.onClick}\n className=\"w-full\"\n >\n {action.label}\n </Button>\n );\n}\n\nexport function AuthGhostAction({\n action,\n}: AuthActionProps): React.ReactElement {\n const isPolymorphic = !!(action.href || action.render);\n\n return (\n <Button\n appearance=\"ghost\"\n nativeButton={isPolymorphic ? false : undefined}\n render={renderActionButton(action)}\n shape=\"rounded\"\n size=\"md\"\n type={isPolymorphic ? undefined : 'button'}\n onClick={action.onClick}\n className=\"w-full\"\n >\n {action.label}\n </Button>\n );\n}\n\nexport function AuthInlineAction({\n prefix,\n action,\n}: AuthInlineActionProps): React.ReactElement {\n const className =\n 'font-medium text-foreground transition-colors duration-150 ease-smooth hover:text-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background';\n\n return (\n <p className=\"text-center text-md leading-normal text-secondary-foreground\">\n <span>{prefix} </span>\n {renderActionElement(action, className)}\n </p>\n );\n}\n\nexport function AuthSocialDivider({\n label,\n}: AuthSocialDividerProps): React.ReactElement {\n return (\n <div className=\"flex items-center gap-4\">\n <Separator className=\"flex-1\" />\n <span className=\"shrink-0 text-md text-foreground\">{label}</span>\n <Separator className=\"flex-1\" />\n </div>\n );\n}\n\nexport function AuthSsoActions({\n actions,\n}: AuthSsoActionsProps): React.ReactElement | null {\n if (!actions?.length) return null;\n\n return (\n <div className=\"flex flex-col gap-3\">\n {actions.map((action, index) => {\n const isPolymorphic = !!(action.href || action.render);\n\n return (\n <Button\n key={`${String(action.label)}-${index}`}\n appearance=\"outline\"\n nativeButton={isPolymorphic ? false : undefined}\n render={renderActionButton(action)}\n shape=\"rounded\"\n size=\"default\"\n type={isPolymorphic ? undefined : 'button'}\n onClick={action.onClick}\n className=\"w-full\"\n >\n {action.label}\n </Button>\n );\n })}\n </div>\n );\n}\n\nexport const defaultLoginAside: AuthPageAsideConfig = {\n title: (\n <>\n Welcome back!\n <br />\n Please sign in to your Create Studio account\n </>\n ),\n description:\n 'Thank you for registering! Please check your inbox and click the verification link to activate your account.',\n cardTitle: 'Please enter your login details',\n cardDescription:\n 'Stay connected with Shadcn Studio Subscribe now for the latest updates and news.',\n};\n\nexport const defaultRegisterAside: AuthPageAsideConfig = {\n title: 'Create your account to get started.',\n description:\n 'Your account will allow you to securely save your progress, customize your preferences, and stay connected across all your devices.',\n cardTitle: \"We're excited to have you join our community\",\n cardDescription:\n 'Your account will allow you to securely save your progress, customize your preferences.',\n};\n\nexport const defaultForgotPasswordAside: AuthPageAsideConfig = {\n title: \"Don't worry, it happens! Resetting your password is quick and easy.\",\n description:\n \"Just enter your registered email address below, and we'll send you a secure link to reset your password. Follow the instructions in the email, and you'll be back in your account in no time!\",\n cardTitle: 'Follow the instructions',\n cardDescription:\n \"If you don't see the email in your inbox, be sure to check your spam or junk folder.\",\n};\n\nexport const defaultResetPasswordAside: AuthPageAsideConfig = {\n title: \"You're just one step away from regaining access to your account.\",\n description:\n \"Please create a new password below. Make sure it's strong and secure, combining letters, numbers, and special characters.\",\n cardTitle: 'Reset Your Password',\n cardDescription:\n \"You're just one step away from regaining access to your account.\",\n};\n\nexport const defaultTwoFactorAside: AuthPageAsideConfig = {\n title: 'Enable Two-Factor Authentication (2FA)',\n description:\n \"Enhance the security of your account by enabling Two-Factor Authentication (2FA). With 2FA, you'll add an extra layer of protection.\",\n cardTitle: 'Keeps your information safe',\n cardDescription:\n 'To get started, choose your preferred verification method and follow the instructions.',\n};\n\nexport const defaultVerifyEmailAside: AuthPageAsideConfig = {\n title: 'Ensure you entered the correct email address',\n description:\n 'Thank you for signing up! To complete your registration and secure your account, we need to verify your email address.',\n cardTitle: 'Verify Your Email Address',\n cardDescription:\n \"Verifying your email helps us keep your account secure and ensures you won't miss important updates.\",\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"index229.js","names":[],"sources":["../src/components/pages/_auth/auth-page-utils.tsx"],"sourcesContent":["'use client';\n\nimport { Eye, EyeOff } from 'lucide-react';\nimport * as React from 'react';\nimport { Button } from '@/components/atoms/buttons/Button';\nimport { Input, type InputProps } from '@/components/atoms/forms/Input';\nimport { Separator } from '@/components/atoms/layout/Separator';\nimport type {\n AuthPageAction,\n AuthPageAsideConfig,\n} from '@/components/templates/AuthPageLayout';\nimport { renderActionElement } from '@/components/templates/AuthPageLayout';\nimport { cn } from '@/lib/utils';\n\nexport interface AuthFormProps\n extends Omit<React.ComponentProps<'form'>, 'children'> {\n children: React.ReactNode;\n}\n\ntype ActionButtonRenderProps = React.ComponentProps<'button'>;\ntype ActionButtonType = React.ComponentProps<'button'>['type'];\ntype ActionButtonRender = (\n props: ActionButtonRenderProps,\n) => React.ReactElement;\ntype ActionRenderTargetProps = Omit<\n ActionButtonRenderProps,\n 'disabled' | 'ref' | 'role' | 'tabIndex' | 'type'\n>;\ntype ActionAnchorProps = Omit<React.ComponentProps<'a'>, 'href'>;\n\ninterface AuthPrimaryButtonProps {\n children: React.ReactNode;\n loading?: boolean;\n}\n\ninterface AuthActionButtonProps {\n action: AuthPageAction;\n loading?: boolean;\n}\n\ninterface AuthActionProps {\n action: AuthPageAction;\n}\n\ninterface AuthInlineActionProps {\n prefix: React.ReactNode;\n action: AuthPageAction;\n}\n\ninterface AuthSocialDividerProps {\n label: React.ReactNode;\n}\n\ninterface AuthSsoActionsProps {\n actions?: AuthPageAction[];\n}\n\ninterface AuthPasswordInputProps extends InputProps {\n visibilityLabel?: string;\n}\n\nexport function AuthForm({\n children,\n className,\n ...props\n}: AuthFormProps): React.ReactElement {\n return (\n <form className={cn('flex flex-col gap-6', className)} {...props}>\n {children}\n </form>\n );\n}\n\nexport function AuthPasswordInput({\n endIcon,\n visibilityLabel = 'password',\n ...props\n}: AuthPasswordInputProps): React.ReactElement {\n const [isVisible, setIsVisible] = React.useState(false);\n const label = `${isVisible ? 'Hide' : 'Show'} ${visibilityLabel}`;\n const VisibilityIcon = isVisible ? EyeOff : Eye;\n const toggle = (\n <button\n type=\"button\"\n aria-label={label}\n aria-pressed={isVisible}\n title={label}\n onClick={() => setIsVisible((value) => !value)}\n className=\"pointer-events-auto inline-flex size-5 items-center justify-center rounded-sm text-muted-foreground transition-colors duration-150 ease-smooth hover:text-secondary-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background\"\n >\n <VisibilityIcon aria-hidden className=\"size-4\" />\n </button>\n );\n\n return (\n <Input\n {...props}\n type={isVisible ? 'text' : 'password'}\n endIcon={\n endIcon ? (\n <span className=\"pointer-events-auto inline-flex items-center gap-2\">\n {endIcon}\n {toggle}\n </span>\n ) : (\n toggle\n )\n }\n />\n );\n}\n\nexport function AuthPrimaryButton({\n children,\n loading,\n}: AuthPrimaryButtonProps): React.ReactElement {\n return (\n <Button\n appearance=\"solid\"\n loading={loading}\n shape=\"rounded\"\n size=\"md\"\n type=\"submit\"\n className=\"w-full\"\n >\n {children}\n </Button>\n );\n}\n\nfunction getNonNativeActionProps({\n disabled: _disabled,\n ref: _ref,\n role: _role,\n tabIndex: _tabIndex,\n type: _type,\n ...props\n}: ActionButtonRenderProps): ActionRenderTargetProps {\n return props;\n}\n\nfunction renderActionLink(href: string): ActionButtonRender {\n return function renderLinkAction(\n props: ActionButtonRenderProps,\n ): React.ReactElement {\n const anchorProps = getNonNativeActionProps(props) as ActionAnchorProps;\n return <a {...anchorProps} href={href} />;\n };\n}\n\nfunction renderCustomActionElement(action: AuthPageAction): ActionButtonRender {\n return function renderCustomAction(\n buttonProps: ActionButtonRenderProps,\n ): React.ReactElement {\n const props = getNonNativeActionProps(buttonProps);\n if (!action.render) {\n return <button type=\"button\" {...props} />;\n }\n\n return React.cloneElement(action.render, {\n ...props,\n className: cn(props.className, action.render.props.className),\n onClick: action.onClick ?? action.render.props.onClick ?? props.onClick,\n children: action.render.props.children ?? props.children ?? action.label,\n });\n };\n}\n\nfunction renderActionButton(\n action: AuthPageAction,\n): React.ReactElement | ActionButtonRender {\n if (action.render) {\n return renderCustomActionElement(action);\n }\n\n if (action.href) {\n return renderActionLink(action.href);\n }\n\n return <button type=\"button\">{action.label}</button>;\n}\n\nfunction getPrimaryActionButtonType(\n action: AuthPageAction,\n isPolymorphic: boolean,\n): ActionButtonType {\n if (isPolymorphic) {\n return undefined;\n }\n\n if (action.onClick) {\n return 'button';\n }\n\n return 'submit';\n}\n\nexport function AuthPrimaryActionButton({\n action,\n loading,\n}: AuthActionButtonProps): React.ReactElement {\n const isPolymorphic = !!(action.href || action.render);\n const supportsLoading = !isPolymorphic;\n\n return (\n <Button\n appearance=\"solid\"\n loading={supportsLoading ? loading : undefined}\n nativeButton={isPolymorphic ? false : undefined}\n render={isPolymorphic ? renderActionButton(action) : undefined}\n shape=\"rounded\"\n size=\"md\"\n type={getPrimaryActionButtonType(action, isPolymorphic)}\n onClick={action.onClick}\n className=\"w-full\"\n >\n {action.label}\n </Button>\n );\n}\n\nexport function AuthGhostAction({\n action,\n}: AuthActionProps): React.ReactElement {\n const isPolymorphic = !!(action.href || action.render);\n\n return (\n <Button\n appearance=\"ghost\"\n nativeButton={isPolymorphic ? false : undefined}\n render={renderActionButton(action)}\n shape=\"rounded\"\n size=\"md\"\n type={isPolymorphic ? undefined : 'button'}\n onClick={action.onClick}\n className=\"w-full\"\n >\n {action.label}\n </Button>\n );\n}\n\nexport function AuthInlineAction({\n prefix,\n action,\n}: AuthInlineActionProps): React.ReactElement {\n const className =\n 'font-medium text-foreground transition-colors duration-150 ease-smooth hover:text-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background';\n\n return (\n <p className=\"text-center text-md leading-normal text-secondary-foreground\">\n <span>{prefix} </span>\n {renderActionElement(action, className)}\n </p>\n );\n}\n\nexport function AuthSocialDivider({\n label,\n}: AuthSocialDividerProps): React.ReactElement {\n return (\n <div className=\"flex items-center gap-4\">\n <Separator className=\"flex-1\" />\n <span className=\"shrink-0 text-md text-foreground\">{label}</span>\n <Separator className=\"flex-1\" />\n </div>\n );\n}\n\nexport function AuthSsoActions({\n actions,\n}: AuthSsoActionsProps): React.ReactElement | null {\n if (!actions?.length) return null;\n\n return (\n <div className=\"flex flex-col gap-3\">\n {actions.map((action, index) => {\n const isPolymorphic = !!(action.href || action.render);\n\n return (\n <Button\n key={`${String(action.label)}-${index}`}\n appearance=\"outline\"\n nativeButton={isPolymorphic ? false : undefined}\n render={renderActionButton(action)}\n shape=\"rounded\"\n size=\"default\"\n type={isPolymorphic ? undefined : 'button'}\n onClick={action.onClick}\n className=\"w-full\"\n >\n {action.label}\n </Button>\n );\n })}\n </div>\n );\n}\n\nexport const defaultLoginAside: AuthPageAsideConfig = {\n title: (\n <>\n Welcome back!\n <br />\n Please sign in to your Create Studio account\n </>\n ),\n description:\n 'Thank you for registering! Please check your inbox and click the verification link to activate your account.',\n cardTitle: 'Please enter your login details',\n cardDescription:\n 'Stay connected with Shadcn Studio Subscribe now for the latest updates and news.',\n};\n\nexport const defaultRegisterAside: AuthPageAsideConfig = {\n title: 'Create your account to get started.',\n description:\n 'Your account will allow you to securely save your progress, customize your preferences, and stay connected across all your devices.',\n cardTitle: \"We're excited to have you join our community\",\n cardDescription:\n 'Your account will allow you to securely save your progress, customize your preferences.',\n};\n\nexport const defaultForgotPasswordAside: AuthPageAsideConfig = {\n title: \"Don't worry, it happens! Resetting your password is quick and easy.\",\n description:\n \"Just enter your registered email address below, and we'll send you a secure link to reset your password. Follow the instructions in the email, and you'll be back in your account in no time!\",\n cardTitle: 'Follow the instructions',\n cardDescription:\n \"If you don't see the email in your inbox, be sure to check your spam or junk folder.\",\n};\n\nexport const defaultResetPasswordAside: AuthPageAsideConfig = {\n title: \"You're just one step away from regaining access to your account.\",\n description:\n \"Please create a new password below. Make sure it's strong and secure, combining letters, numbers, and special characters.\",\n cardTitle: 'Reset Your Password',\n cardDescription:\n \"You're just one step away from regaining access to your account.\",\n};\n\nexport const defaultTwoFactorAside: AuthPageAsideConfig = {\n title: 'Enable Two-Factor Authentication (2FA)',\n description:\n \"Enhance the security of your account by enabling Two-Factor Authentication (2FA). With 2FA, you'll add an extra layer of protection.\",\n cardTitle: 'Keeps your information safe',\n cardDescription:\n 'To get started, choose your preferred verification method and follow the instructions.',\n};\n\nexport const defaultVerifyEmailAside: AuthPageAsideConfig = {\n title: 'Ensure you entered the correct email address',\n description:\n 'Thank you for signing up! To complete your registration and secure your account, we need to verify your email address.',\n cardTitle: 'Verify Your Email Address',\n cardDescription:\n \"Verifying your email helps us keep your account secure and ensures you won't miss important updates.\",\n};\n"],"mappings":";;;;;;;;;;AA6DA,SAAgB,SAAS,EACvB,UACA,WACA,GAAG,SACiC;CACpC,OACE,oBAAC,QAAD;EAAM,WAAW,GAAG,uBAAuB,SAAS;EAAG,GAAI;EACxD;CACG,CAAA;AAEV;AAEA,SAAgB,kBAAkB,EAChC,SACA,kBAAkB,YAClB,GAAG,SAC0C;CAC7C,MAAM,CAAC,WAAW,gBAAgB,QAAM,SAAS,KAAK;CACtD,MAAM,QAAQ,GAAG,YAAY,SAAS,OAAO,GAAG;CAEhD,MAAM,SACJ,oBAAC,UAAD;EACE,MAAK;EACL,cAAY;EACZ,gBAAc;EACd,OAAO;EACP,eAAe,cAAc,UAAU,CAAC,KAAK;EAC7C,WAAU;YAEV,oBAVmB,YAAY,SAAS,KAUxC;GAAgB,eAAA;GAAY,WAAU;EAAU,CAAA;CAC1C,CAAA;CAGV,OACE,oBAAC,OAAD;EACE,GAAI;EACJ,MAAM,YAAY,SAAS;EAC3B,SACE,UACE,qBAAC,QAAD;GAAM,WAAU;aAAhB,CACG,SACA,MACG;OAEN;CAGL,CAAA;AAEL;AAEA,SAAgB,kBAAkB,EAChC,UACA,WAC6C;CAC7C,OACE,oBAAC,QAAD;EACE,YAAW;EACF;EACT,OAAM;EACN,MAAK;EACL,MAAK;EACL,WAAU;EAET;CACK,CAAA;AAEZ;AAEA,SAAS,wBAAwB,EAC/B,UAAU,WACV,KAAK,MACL,MAAM,OACN,UAAU,WACV,MAAM,OACN,GAAG,SACgD;CACnD,OAAO;AACT;AAEA,SAAS,iBAAiB,MAAkC;CAC1D,OAAO,SAAS,iBACd,OACoB;EAEpB,OAAO,oBAAC,KAAD;GAAG,GADU,wBAAwB,KAC9B;GAAmB;EAAO,CAAA;CAC1C;AACF;AAEA,SAAS,0BAA0B,QAA4C;CAC7E,OAAO,SAAS,mBACd,aACoB;EACpB,MAAM,QAAQ,wBAAwB,WAAW;EACjD,IAAI,CAAC,OAAO,QACV,OAAO,oBAAC,UAAD;GAAQ,MAAK;GAAS,GAAI;EAAQ,CAAA;EAG3C,OAAO,QAAM,aAAa,OAAO,QAAQ;GACvC,GAAG;GACH,WAAW,GAAG,MAAM,WAAW,OAAO,OAAO,MAAM,SAAS;GAC5D,SAAS,OAAO,WAAW,OAAO,OAAO,MAAM,WAAW,MAAM;GAChE,UAAU,OAAO,OAAO,MAAM,YAAY,MAAM,YAAY,OAAO;EACrE,CAAC;CACH;AACF;AAEA,SAAS,mBACP,QACyC;CACzC,IAAI,OAAO,QACT,OAAO,0BAA0B,MAAM;CAGzC,IAAI,OAAO,MACT,OAAO,iBAAiB,OAAO,IAAI;CAGrC,OAAO,oBAAC,UAAD;EAAQ,MAAK;YAAU,OAAO;CAAc,CAAA;AACrD;AAEA,SAAS,2BACP,QACA,eACkB;CAClB,IAAI,eACF;CAGF,IAAI,OAAO,SACT,OAAO;CAGT,OAAO;AACT;AAEA,SAAgB,wBAAwB,EACtC,QACA,WAC4C;CAC5C,MAAM,gBAAgB,CAAC,EAAE,OAAO,QAAQ,OAAO;CAG/C,OACE,oBAAC,QAAD;EACE,YAAW;EACX,SAAS,CALY,gBAKM,UAAU,KAAA;EACrC,cAAc,gBAAgB,QAAQ,KAAA;EACtC,QAAQ,gBAAgB,mBAAmB,MAAM,IAAI,KAAA;EACrD,OAAM;EACN,MAAK;EACL,MAAM,2BAA2B,QAAQ,aAAa;EACtD,SAAS,OAAO;EAChB,WAAU;YAET,OAAO;CACF,CAAA;AAEZ;AAEA,SAAgB,gBAAgB,EAC9B,UACsC;CACtC,MAAM,gBAAgB,CAAC,EAAE,OAAO,QAAQ,OAAO;CAE/C,OACE,oBAAC,QAAD;EACE,YAAW;EACX,cAAc,gBAAgB,QAAQ,KAAA;EACtC,QAAQ,mBAAmB,MAAM;EACjC,OAAM;EACN,MAAK;EACL,MAAM,gBAAgB,KAAA,IAAY;EAClC,SAAS,OAAO;EAChB,WAAU;YAET,OAAO;CACF,CAAA;AAEZ;AAEA,SAAgB,iBAAiB,EAC/B,QACA,UAC4C;CAI5C,OACE,qBAAC,KAAD;EAAG,WAAU;YAAb,CACE,qBAAC,QAAD,EAAA,UAAA,CAAO,QAAO,GAAO,EAAA,CAAA,GACpB,oBAAoB,QAAQ,oOAAS,CACrC;;AAEP;AAEA,SAAgB,kBAAkB,EAChC,SAC6C;CAC7C,OACE,qBAAC,OAAD;EAAK,WAAU;YAAf;GACE,oBAAC,WAAD,EAAW,WAAU,SAAU,CAAA;GAC/B,oBAAC,QAAD;IAAM,WAAU;cAAoC;GAAY,CAAA;GAChE,oBAAC,WAAD,EAAW,WAAU,SAAU,CAAA;EAC5B;;AAET;AAEA,SAAgB,eAAe,EAC7B,WACiD;CACjD,IAAI,CAAC,SAAS,QAAQ,OAAO;CAE7B,OACE,oBAAC,OAAD;EAAK,WAAU;YACZ,QAAQ,KAAK,QAAQ,UAAU;GAC9B,MAAM,gBAAgB,CAAC,EAAE,OAAO,QAAQ,OAAO;GAE/C,OACE,oBAAC,QAAD;IAEE,YAAW;IACX,cAAc,gBAAgB,QAAQ,KAAA;IACtC,QAAQ,mBAAmB,MAAM;IACjC,OAAM;IACN,MAAK;IACL,MAAM,gBAAgB,KAAA,IAAY;IAClC,SAAS,OAAO;IAChB,WAAU;cAET,OAAO;GACF,GAXD,GAAG,OAAO,OAAO,KAAK,EAAE,GAAG,OAW1B;EAEZ,CAAC;CACE,CAAA;AAET;AAEA,IAAa,oBAAyC;CACpD,OACE,qBAAA,UAAA,EAAA,UAAA;EAAE;EAEA,oBAAC,MAAD,CAAK,CAAA;EAAC;CAEN,EAAA,CAAA;CAEJ,aACE;CACF,WAAW;CACX,iBACE;AACJ;AAEA,IAAa,uBAA4C;CACvD,OAAO;CACP,aACE;CACF,WAAW;CACX,iBACE;AACJ;AAEA,IAAa,6BAAkD;CAC7D,OAAO;CACP,aACE;CACF,WAAW;CACX,iBACE;AACJ;AAEA,IAAa,4BAAiD;CAC5D,OAAO;CACP,aACE;CACF,WAAW;CACX,iBACE;AACJ;AAEA,IAAa,wBAA6C;CACxD,OAAO;CACP,aACE;CACF,WAAW;CACX,iBACE;AACJ;AAEA,IAAa,0BAA+C;CAC1D,OAAO;CACP,aACE;CACF,WAAW;CACX,iBACE;AACJ"}
package/dist/index24.js CHANGED
@@ -212,10 +212,10 @@ var FeaturedIcon = React$1.forwardRef(({ children, size = "sm", className }, ref
212
212
  return /* @__PURE__ */ jsx("div", {
213
213
  ref,
214
214
  "data-slot": "featured-icon",
215
- className: cn("shrink-0 rounded-md border border-border bg-card/60", "flex items-center justify-center", "dark:bg-foreground/60 dark:border-border", containerSize, className),
215
+ className: cn("shrink-0 rounded-md border border-border bg-card/60", "flex items-center justify-center", "dark:border-border", containerSize, className),
216
216
  style: { boxShadow: "var(--shadow-inset-ring)" },
217
217
  children: /* @__PURE__ */ jsx("div", {
218
- className: cn("text-secondary-foreground dark:text-text-quaternary", innerSize),
218
+ className: cn("text-secondary-foreground", innerSize),
219
219
  children
220
220
  })
221
221
  });