@qijenchen/design-system 0.1.0-beta.74 → 0.1.0-beta.76

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 (203) hide show
  1. package/CLAUDE.md +1 -1
  2. package/dist/components/AppShell/app-shell.d.ts +2 -2
  3. package/dist/components/AppShell/app-shell.js.map +1 -1
  4. package/dist/components/Avatar/avatar.js.map +1 -1
  5. package/dist/components/BulkActionBar/bulk-action-bar.d.ts.map +1 -1
  6. package/dist/components/BulkActionBar/bulk-action-bar.js +1 -1
  7. package/dist/components/BulkActionBar/bulk-action-bar.js.map +1 -1
  8. package/dist/components/Button/button.d.ts.map +1 -1
  9. package/dist/components/Button/button.js.map +1 -1
  10. package/dist/components/Chart/chart.d.ts +1 -1
  11. package/dist/components/Chart/chart.js.map +1 -1
  12. package/dist/components/Checkbox/checkbox.d.ts +1 -1
  13. package/dist/components/Checkbox/checkbox.js +1 -1
  14. package/dist/components/Checkbox/checkbox.js.map +1 -1
  15. package/dist/components/Combobox/combobox.d.ts +1 -1
  16. package/dist/components/Combobox/combobox.d.ts.map +1 -1
  17. package/dist/components/Combobox/combobox.js +13 -10
  18. package/dist/components/Combobox/combobox.js.map +1 -1
  19. package/dist/components/Command/command.d.ts +1 -1
  20. package/dist/components/Command/command.js +3 -3
  21. package/dist/components/Command/command.js.map +1 -1
  22. package/dist/components/DataTable/cell-registry.d.ts.map +1 -1
  23. package/dist/components/DataTable/cell-registry.js +2 -2
  24. package/dist/components/DataTable/cell-registry.js.map +1 -1
  25. package/dist/components/DataTable/data-table.d.ts +27 -6
  26. package/dist/components/DataTable/data-table.d.ts.map +1 -1
  27. package/dist/components/DataTable/data-table.js +57 -34
  28. package/dist/components/DataTable/data-table.js.map +1 -1
  29. package/dist/components/DatePicker/date-picker.d.ts.map +1 -1
  30. package/dist/components/DatePicker/date-picker.js +2 -2
  31. package/dist/components/DatePicker/date-picker.js.map +1 -1
  32. package/dist/components/DescriptionList/description-list.d.ts +1 -1
  33. package/dist/components/DescriptionList/description-list.js +2 -2
  34. package/dist/components/DescriptionList/description-list.js.map +1 -1
  35. package/dist/components/Empty/empty.d.ts +2 -0
  36. package/dist/components/Empty/empty.d.ts.map +1 -1
  37. package/dist/components/Empty/empty.js.map +1 -1
  38. package/dist/components/Field/field-wrapper.js +4 -4
  39. package/dist/components/Field/field-wrapper.js.map +1 -1
  40. package/dist/components/OverflowIndicator/overflow-indicator.d.ts +1 -1
  41. package/dist/components/OverflowIndicator/overflow-indicator.js +2 -2
  42. package/dist/components/OverflowIndicator/overflow-indicator.js.map +1 -1
  43. package/dist/components/PeoplePicker/people-picker.js +2 -2
  44. package/dist/components/PeoplePicker/people-picker.js.map +1 -1
  45. package/dist/components/ProfileCard/profile-card.d.ts +1 -1
  46. package/dist/components/ProfileCard/profile-card.js +2 -1
  47. package/dist/components/ProfileCard/profile-card.js.map +1 -1
  48. package/dist/components/Rating/rating.js.map +1 -1
  49. package/dist/components/Select/select.js +4 -4
  50. package/dist/components/Select/select.js.map +1 -1
  51. package/dist/components/Textarea/textarea.d.ts +1 -1
  52. package/dist/components/Textarea/textarea.js +2 -2
  53. package/dist/components/Textarea/textarea.js.map +1 -1
  54. package/dist/components/TimePicker/time-picker.d.ts.map +1 -1
  55. package/dist/components/TimePicker/time-picker.js +14 -23
  56. package/dist/components/TimePicker/time-picker.js.map +1 -1
  57. package/dist/components/TreeView/tree-view.d.ts +1 -1
  58. package/dist/components/TreeView/tree-view.js +1 -1
  59. package/dist/components/TreeView/tree-view.js.map +1 -1
  60. package/ds-canonical/fork/governance.lock +1 -1
  61. package/ds-canonical/fork/preamble.md +2 -2
  62. package/ds-canonical/hooks/check_field_controls_contracts.sh +30 -3
  63. package/ds-canonical/hooks/check_story_invariants.sh +26 -0
  64. package/ds-canonical/hooks/tests/test_check_story_invariants.sh +30 -0
  65. package/ds-canonical/references/props-naming.md +15 -1
  66. package/ds-canonical/rules/ui-development.md +2 -2
  67. package/llms-full.txt +7 -2
  68. package/llms.txt +3 -3
  69. package/package.json +1 -1
  70. package/src/components/Accordion/accordion.principles.stories.tsx +3 -3
  71. package/src/components/Alert/alert.anatomy.stories.tsx +4 -4
  72. package/src/components/Alert/alert.principles.stories.tsx +5 -5
  73. package/src/components/AppShell/app-shell.principles.stories.tsx +6 -6
  74. package/src/components/AppShell/app-shell.spec.md +4 -4
  75. package/src/components/AppShell/app-shell.tsx +2 -2
  76. package/src/components/AspectRatio/aspect-ratio.principles.stories.tsx +1 -1
  77. package/src/components/Avatar/avatar.principles.stories.tsx +3 -3
  78. package/src/components/Avatar/avatar.tsx +1 -1
  79. package/src/components/Badge/badge.principles.stories.tsx +3 -3
  80. package/src/components/Breadcrumb/breadcrumb.principles.stories.tsx +3 -3
  81. package/src/components/Breadcrumb/breadcrumb.spec.md +11 -1
  82. package/src/components/BulkActionBar/bulk-action-bar.anatomy.stories.tsx +1 -1
  83. package/src/components/BulkActionBar/bulk-action-bar.principles.stories.tsx +3 -3
  84. package/src/components/BulkActionBar/bulk-action-bar.spec.md +4 -2
  85. package/src/components/BulkActionBar/bulk-action-bar.stories.tsx +2 -2
  86. package/src/components/BulkActionBar/bulk-action-bar.tsx +3 -2
  87. package/src/components/Button/button.principles.stories.tsx +3 -3
  88. package/src/components/Button/button.tsx +0 -10
  89. package/src/components/Calendar/calendar.anatomy.stories.tsx +1 -1
  90. package/src/components/Calendar/calendar.principles.stories.tsx +3 -3
  91. package/src/components/Carousel/carousel.principles.stories.tsx +2 -2
  92. package/src/components/Chart/chart.principles.stories.tsx +4 -4
  93. package/src/components/Chart/chart.tsx +1 -1
  94. package/src/components/Checkbox/checkbox.principles.stories.tsx +2 -2
  95. package/src/components/Checkbox/checkbox.tsx +1 -1
  96. package/src/components/Chip/chip.principles.stories.tsx +3 -3
  97. package/src/components/Coachmark/coachmark.anatomy.stories.tsx +1 -1
  98. package/src/components/Coachmark/coachmark.principles.stories.tsx +3 -3
  99. package/src/components/Coachmark/coachmark.spec.md +2 -2
  100. package/src/components/Combobox/combobox.anatomy.stories.tsx +14 -14
  101. package/src/components/Combobox/combobox.principles.stories.tsx +6 -6
  102. package/src/components/Combobox/combobox.spec.md +1 -1
  103. package/src/components/Combobox/combobox.tsx +25 -14
  104. package/src/components/Command/command.anatomy.stories.tsx +2 -0
  105. package/src/components/Command/command.principles.stories.tsx +7 -7
  106. package/src/components/Command/command.tsx +2 -2
  107. package/src/components/DataTable/cell-registry.tsx +6 -2
  108. package/src/components/DataTable/data-table-filter-panel.tsx +3 -3
  109. package/src/components/DataTable/data-table.anatomy.stories.tsx +1 -1
  110. package/src/components/DataTable/data-table.css +1 -1
  111. package/src/components/DataTable/data-table.principles.stories.tsx +3 -3
  112. package/src/components/DataTable/data-table.spec.md +25 -17
  113. package/src/components/DataTable/data-table.stories.tsx +29 -25
  114. package/src/components/DataTable/data-table.tsx +92 -44
  115. package/src/components/DateGrid/date-grid.anatomy.stories.tsx +1 -1
  116. package/src/components/DateGrid/date-grid.principles.stories.tsx +4 -4
  117. package/src/components/DateGrid/date-grid.spec.md +1 -1
  118. package/src/components/DatePicker/date-picker.anatomy.stories.tsx +15 -11
  119. package/src/components/DatePicker/date-picker.principles.stories.tsx +5 -5
  120. package/src/components/DatePicker/date-picker.spec.md +1 -1
  121. package/src/components/DatePicker/date-picker.tsx +9 -6
  122. package/src/components/DescriptionList/description-list.principles.stories.tsx +5 -5
  123. package/src/components/DescriptionList/description-list.tsx +1 -1
  124. package/src/components/Dialog/dialog.anatomy.stories.tsx +1 -1
  125. package/src/components/Dialog/dialog.principles.stories.tsx +4 -4
  126. package/src/components/DropdownMenu/dropdown-menu.anatomy.stories.tsx +1 -1
  127. package/src/components/DropdownMenu/dropdown-menu.principles.stories.tsx +5 -5
  128. package/src/components/DropdownMenu/dropdown-menu.spec.md +1 -1
  129. package/src/components/Empty/empty.principles.stories.tsx +2 -2
  130. package/src/components/Empty/empty.tsx +2 -0
  131. package/src/components/Field/field-controls.spec.md +9 -6
  132. package/src/components/Field/field-wrapper.tsx +4 -4
  133. package/src/components/Field/field.principles.stories.tsx +4 -4
  134. package/src/components/FileItem/file-item.principles.stories.tsx +6 -5
  135. package/src/components/FileUpload/file-upload.principles.stories.tsx +6 -6
  136. package/src/components/FileUpload/file-upload.spec.md +1 -1
  137. package/src/components/FileViewer/file-viewer.principles.stories.tsx +5 -5
  138. package/src/components/HoverCard/hover-card.principles.stories.tsx +6 -6
  139. package/src/components/Input/input.anatomy.stories.tsx +3 -3
  140. package/src/components/Input/input.principles.stories.tsx +4 -4
  141. package/src/components/LinkInput/link-input.anatomy.stories.tsx +3 -3
  142. package/src/components/LinkInput/link-input.principles.stories.tsx +5 -5
  143. package/src/components/Menu/menu-item.principles.stories.tsx +7 -7
  144. package/src/components/Notice/notice.anatomy.stories.tsx +1 -1
  145. package/src/components/Notice/notice.principles.stories.tsx +7 -7
  146. package/src/components/NumberInput/number-input.anatomy.stories.tsx +8 -7
  147. package/src/components/NumberInput/number-input.principles.stories.tsx +4 -4
  148. package/src/components/NumberInput/number-input.spec.md +1 -1
  149. package/src/components/OverflowIndicator/overflow-indicator.principles.stories.tsx +5 -5
  150. package/src/components/OverflowIndicator/overflow-indicator.tsx +1 -1
  151. package/src/components/PeoplePicker/people-picker.principles.stories.tsx +3 -3
  152. package/src/components/PeoplePicker/people-picker.spec.md +3 -3
  153. package/src/components/PeoplePicker/people-picker.tsx +6 -6
  154. package/src/components/Popover/popover.principles.stories.tsx +5 -5
  155. package/src/components/ProfileCard/profile-card.anatomy.stories.tsx +1 -1
  156. package/src/components/ProfileCard/profile-card.principles.stories.tsx +1 -1
  157. package/src/components/ProfileCard/profile-card.tsx +1 -1
  158. package/src/components/ProgressBar/progress-bar.principles.stories.tsx +2 -2
  159. package/src/components/ProgressBar/progress-bar.spec.md +1 -1
  160. package/src/components/RadioGroup/radio-group.principles.stories.tsx +2 -2
  161. package/src/components/Rating/rating.anatomy.stories.tsx +2 -2
  162. package/src/components/Rating/rating.principles.stories.tsx +3 -3
  163. package/src/components/Rating/rating.spec.md +1 -1
  164. package/src/components/Rating/rating.tsx +1 -1
  165. package/src/components/ScrollArea/scroll-area.principles.stories.tsx +4 -4
  166. package/src/components/Select/select.anatomy.stories.tsx +18 -18
  167. package/src/components/Select/select.principles.stories.tsx +5 -5
  168. package/src/components/Select/select.spec.md +1 -1
  169. package/src/components/Select/select.tsx +7 -7
  170. package/src/components/SelectMenu/select-menu.anatomy.stories.tsx +1 -1
  171. package/src/components/SelectMenu/select-menu.principles.stories.tsx +8 -8
  172. package/src/components/SelectionControl/selection-item.principles.stories.tsx +7 -7
  173. package/src/components/Separator/separator.principles.stories.tsx +4 -4
  174. package/src/components/Sheet/sheet.principles.stories.tsx +2 -2
  175. package/src/components/Sidebar/sidebar.principles.stories.tsx +4 -4
  176. package/src/components/Sidebar/sidebar.spec.md +2 -2
  177. package/src/components/Skeleton/skeleton.principles.stories.tsx +5 -5
  178. package/src/components/Slider/slider.anatomy.stories.tsx +1 -1
  179. package/src/components/Slider/slider.principles.stories.tsx +3 -3
  180. package/src/components/Steps/steps.principles.stories.tsx +4 -4
  181. package/src/components/Steps/steps.spec.md +2 -2
  182. package/src/components/Switch/switch.principles.stories.tsx +1 -1
  183. package/src/components/Tabs/tabs.principles.stories.tsx +3 -3
  184. package/src/components/Tabs/tabs.spec.md +1 -1
  185. package/src/components/Tag/tag.principles.stories.tsx +3 -3
  186. package/src/components/Textarea/textarea.principles.stories.tsx +2 -2
  187. package/src/components/Textarea/textarea.tsx +3 -3
  188. package/src/components/TimePicker/time-picker.principles.stories.tsx +5 -5
  189. package/src/components/TimePicker/time-picker.spec.md +1 -1
  190. package/src/components/TimePicker/time-picker.tsx +11 -12
  191. package/src/components/Toast/toast.principles.stories.tsx +2 -2
  192. package/src/components/Tooltip/tooltip.principles.stories.tsx +3 -3
  193. package/src/components/TreeView/tree-view.principles.stories.tsx +5 -5
  194. package/src/components/TreeView/tree-view.stories.tsx +1 -1
  195. package/src/components/TreeView/tree-view.tsx +1 -1
  196. package/src/patterns/element-anatomy/item-anatomy.spec.md +1 -1
  197. package/src/patterns/element-anatomy/item-anatomy.stories.tsx +1 -1
  198. package/src/patterns/overlay-surface/overlay-surface.spec.md +1 -0
  199. package/src/patterns/resize-handle/resize-handle.spec.md +1 -1
  200. package/src/tokens/color/color.spec.md +2 -0
  201. package/src/tokens/color/semantic.css +1 -1
  202. package/src/tokens/uiSize/uiSize.css +5 -0
  203. package/src/tokens/uiSize/uiSize.spec.md +17 -3
@@ -1 +1 @@
1
- {"version":3,"file":"chart.js","sources":["../../../src/components/Chart/chart.tsx"],"sourcesContent":["import * as React from 'react'\nimport * as RechartsPrimitive from 'recharts'\nimport { cn } from '@/lib/utils'\n\n/**\n * Chart — shadcn-style wrapper over Recharts + 本 DS token\n *\n * 結構對齊 shadcn chart(ChartContainer / ChartTooltipContent / ChartLegendContent),\n * 但所有視覺(tooltip / legend / grid / axis)改用本 DS token。\n *\n * ── Color mapping ──\n * ChartConfig.{key}.color 接受 2 種形式:\n * 1. CSS var 字串('var(--chart-1)' 等)\n * 2. 任何合法 CSS color\n * 預設建議使用 --chart-1..5(本 DS 提供的 5 色類別 token)\n *\n * ── 視覺 token ──\n * Tooltip: bg-surface-raised / border-border / shadow-[elevation-200] / rounded-md\n * Legend text: text-fg-secondary / text-caption\n * Grid: stroke-divider\n * Axis tick: text-fg-muted / text-caption\n */\n\nexport type ChartConfig = {\n [k in string]: {\n label?: React.ReactNode\n icon?: React.ComponentType\n } & (\n | { color?: string; theme?: never }\n | { color?: never; theme: Record<'light' | 'dark', string> }\n )\n}\n\ntype ChartContextProps = { config: ChartConfig }\n\nconst ChartContext = React.createContext<ChartContextProps | null>(null)\n\nfunction useChart() {\n const ctx = React.useContext(ChartContext)\n if (!ctx) throw new Error('useChart 必須在 <ChartContainer> 內使用')\n return ctx\n}\n\n// ── ChartContainer ─────────────────────────────────────────────────────────\n\ninterface ChartContainerProps extends React.ComponentProps<'div'> {\n config: ChartConfig\n children: React.ComponentProps<typeof RechartsPrimitive.ResponsiveContainer>['children']\n}\n\nconst ChartContainer = React.forwardRef<HTMLDivElement, ChartContainerProps>(\n ({ id, className, children, config, ...props }, ref) => {\n const uniqueId = React.useId()\n const chartId = `chart-${id || uniqueId.replace(/:/g, '')}`\n // Memoize provider value(2026-04-22 D3 perf audit):避免 render 重建 wrapper object\n const ctxValue = React.useMemo(() => ({ config }), [config])\n\n return (\n <ChartContext.Provider value={ctxValue}>\n <div\n ref={ref}\n data-chart={chartId}\n className={cn(\n // 整體視覺套用本 DS typography + token\n // 預設 aspect-video(16:9)— Recharts ResponsiveContainer 需 parent 有高度。\n // Consumer 若需其他比例,包 <AspectRatio ratio={n}> 覆寫(AspectRatio 的 padding-bottom 高度會蓋過此 class)。\n 'flex aspect-video justify-center text-caption',\n // recharts 內部預設樣式覆寫:grid / axis / tooltip shadow 等\n \"[&_.recharts-cartesian-grid_line]:stroke-divider\",\n \"[&_.recharts-cartesian-axis-tick_text]:fill-fg-muted\",\n \"[&_.recharts-polar-grid_[stroke='#ccc']]:stroke-divider\",\n \"[&_.recharts-reference-line_[stroke='#ccc']]:stroke-divider\",\n \"[&_.recharts-dot[stroke='#fff']]:stroke-transparent\",\n \"[&_.recharts-layer]:outline-none\",\n \"[&_.recharts-sector[stroke='#fff']]:stroke-transparent\",\n \"[&_.recharts-sector]:outline-none\",\n \"[&_.recharts-surface]:outline-none\",\n className,\n )}\n {...props}\n >\n <ChartStyle id={chartId} config={config} />\n <RechartsPrimitive.ResponsiveContainer>\n {children}\n </RechartsPrimitive.ResponsiveContainer>\n </div>\n </ChartContext.Provider>\n )\n },\n)\nChartContainer.displayName = 'ChartContainer'\n\n// ── ChartStyle ──────────────────────────────────────────────────────────────\n// 將 config 內每個 key 的 color 注入 scoped CSS variable(`--color-{key}`),\n// 供 Recharts `fill={`var(--color-${key})`}` 直接消費。\n\nconst THEMES = { light: '', dark: '[data-theme=dark] ' } as const\n\nfunction ChartStyle({ id, config }: { id: string; config: ChartConfig }) {\n const entries = Object.entries(config).filter(([, v]) => 'color' in v || 'theme' in v)\n if (entries.length === 0) return null\n\n return (\n <style\n dangerouslySetInnerHTML={{\n __html: Object.entries(THEMES)\n .map(([theme, prefix]) => {\n const vars = entries\n .map(([key, item]) => {\n const color =\n 'theme' in item ? item.theme?.[theme as keyof typeof item.theme] : item.color\n return color ? ` --color-${key}: ${color};` : null\n })\n .filter(Boolean)\n .join('\\n')\n return `${prefix}[data-chart=${id}] {\\n${vars}\\n}`\n })\n .join('\\n'),\n }}\n />\n )\n}\n\n// ── ChartTooltip / ChartTooltipContent ─────────────────────────────────────\n\nconst ChartTooltip = RechartsPrimitive.Tooltip\n\ntype RechartsTooltipPayloadItem = {\n value?: string | number\n name?: string | number\n dataKey?: string | number\n color?: string\n payload?: unknown\n [key: string]: unknown\n}\n\ninterface ChartTooltipContentProps extends Omit<React.ComponentProps<'div'>, 'color'> {\n active?: boolean\n payload?: RechartsTooltipPayloadItem[]\n label?: unknown\n labelFormatter?: (value: unknown, payload: RechartsTooltipPayloadItem[]) => React.ReactNode\n labelClassName?: string\n formatter?: (\n value: unknown,\n name: unknown,\n item: RechartsTooltipPayloadItem,\n index: number,\n payload: unknown,\n ) => React.ReactNode\n color?: string\n hideLabel?: boolean\n hideIndicator?: boolean\n indicator?: 'line' | 'dot' | 'dashed'\n nameKey?: string\n labelKey?: string\n}\n\n// code-quality-allow: long-function — foundational composite main body — 拆 sub-fn 會複雜化 local state / ref / context binding\nconst ChartTooltipContent = React.forwardRef<HTMLDivElement, ChartTooltipContentProps>(\n (\n {\n active,\n payload,\n className,\n indicator = 'dot',\n hideLabel = false,\n hideIndicator = false,\n label,\n labelFormatter,\n labelClassName,\n formatter,\n color,\n nameKey,\n labelKey,\n },\n ref,\n ) => {\n const { config } = useChart()\n\n const tooltipLabel = React.useMemo(() => {\n if (hideLabel || !payload?.length) return null\n const [item] = payload\n const key = `${labelKey || item.dataKey || item.name || 'value'}`\n const itemConfig = getPayloadConfig(config, item, key)\n const value =\n !labelKey && typeof label === 'string'\n ? config[label as keyof typeof config]?.label || label\n : itemConfig?.label\n if (labelFormatter) return <div className={cn('font-medium', labelClassName)}>{labelFormatter(value, payload)}</div>\n if (!value) return null\n return <div className={cn('font-medium', labelClassName)}>{value}</div>\n }, [label, labelFormatter, payload, hideLabel, labelClassName, config, labelKey])\n\n if (!active || !payload?.length) return null\n\n const nestLabel = payload.length === 1 && indicator !== 'dot'\n\n return (\n <div\n ref={ref}\n // 2026-05-31 #5:自訂 tooltip 補 role=status + aria-live,保留 Recharts 原生 SR 朗讀(spec L146 宣稱鍵盤可達+讀屏)\n role=\"status\"\n aria-live=\"polite\"\n className={cn(\n 'grid min-w-32 items-start gap-1.5 rounded-md border border-border bg-surface-raised px-2.5 py-1.5 text-caption shadow-[var(--elevation-200)]',\n className,\n )}\n >\n {!nestLabel ? tooltipLabel : null}\n <div className=\"grid gap-1.5\">\n {payload.map((item, index) => {\n const key = `${nameKey || item.name || item.dataKey || 'value'}`\n const itemConfig = getPayloadConfig(config, item, key)\n const indicatorColor = color || (item.payload as { fill?: string })?.fill || item.color\n\n return (\n <div\n key={item.dataKey || index}\n className={cn(\n 'flex w-full flex-wrap items-stretch gap-2 [&>svg]:h-2.5 [&>svg]:w-2.5 [&>svg]:text-fg-muted',\n indicator === 'dot' && 'items-center',\n )}\n >\n {formatter && item?.value !== undefined && item.name ? (\n formatter(item.value, item.name, item, index, item.payload)\n ) : (\n <>\n {itemConfig?.icon ? (\n <itemConfig.icon />\n ) : (\n !hideIndicator && (\n <div\n className={cn('shrink-0 rounded-xs border-(--color-border) bg-(--color-bg)', {\n 'h-2.5 w-2.5': indicator === 'dot',\n 'w-1': indicator === 'line',\n 'w-0 border-[1.5px] border-dashed bg-transparent': indicator === 'dashed',\n 'my-0.5': nestLabel && indicator === 'dashed',\n })}\n style={\n {\n '--color-bg': indicatorColor,\n '--color-border': indicatorColor,\n } as React.CSSProperties\n }\n />\n )\n )}\n <div\n className={cn(\n 'flex flex-1 justify-between leading-none',\n nestLabel ? 'items-end' : 'items-center',\n )}\n >\n <div className=\"grid gap-1.5\">\n {nestLabel ? tooltipLabel : null}\n <span className=\"text-fg-secondary\">{itemConfig?.label || item.name}</span>\n </div>\n {item.value && (\n <span className=\"text-foreground font-mono font-medium tabular-nums\">\n {item.value.toLocaleString()}\n </span>\n )}\n </div>\n </>\n )}\n </div>\n )\n })}\n </div>\n </div>\n )\n },\n)\nChartTooltipContent.displayName = 'ChartTooltipContent'\n\n// ── ChartLegend / ChartLegendContent ───────────────────────────────────────\n\nconst ChartLegend = RechartsPrimitive.Legend\n\ntype RechartsLegendPayloadItem = {\n value?: unknown\n dataKey?: string | number\n color?: string\n payload?: unknown\n [key: string]: unknown\n}\n\ninterface ChartLegendContentProps extends React.ComponentProps<'div'> {\n payload?: RechartsLegendPayloadItem[]\n verticalAlign?: 'top' | 'middle' | 'bottom'\n hideIcon?: boolean\n nameKey?: string\n}\n\nconst ChartLegendContent = React.forwardRef<HTMLDivElement, ChartLegendContentProps>(\n ({ className, hideIcon = false, payload, verticalAlign = 'bottom', nameKey }, ref) => {\n const { config } = useChart()\n if (!payload?.length) return null\n\n return (\n <div\n ref={ref}\n className={cn(\n 'flex items-center justify-center gap-4',\n verticalAlign === 'top' ? 'pb-3' : 'pt-3',\n className,\n )}\n >\n {payload.map((item) => {\n const key = `${nameKey || item.dataKey || 'value'}`\n const itemConfig = getPayloadConfig(config, item, key)\n return (\n <div\n key={String(item.value)}\n className=\"flex items-center gap-1.5 text-fg-secondary [&>svg]:h-3 [&>svg]:w-3 [&>svg]:text-fg-muted\"\n >\n {itemConfig?.icon && !hideIcon ? (\n <itemConfig.icon />\n ) : (\n <div className=\"h-2 w-2 shrink-0 rounded-xs\" style={{ backgroundColor: item.color }} />\n )}\n {itemConfig?.label}\n </div>\n )\n })}\n </div>\n )\n },\n)\nChartLegendContent.displayName = 'ChartLegendContent'\n\n// ── helpers ────────────────────────────────────────────────────────────────\n\nfunction getPayloadConfig(\n config: ChartConfig,\n payload: unknown,\n key: string,\n) {\n if (typeof payload !== 'object' || payload === null) return undefined\n const payloadPayload =\n 'payload' in payload && typeof payload.payload === 'object' && payload.payload !== null\n ? payload.payload\n : undefined\n let configLabelKey: string = key\n if (key in (payload as Record<string, unknown>) && typeof (payload as Record<string, unknown>)[key] === 'string') {\n configLabelKey = (payload as Record<string, string>)[key]\n } else if (payloadPayload && key in payloadPayload && typeof (payloadPayload as Record<string, unknown>)[key] === 'string') {\n configLabelKey = (payloadPayload as Record<string, string>)[key]\n }\n return configLabelKey in config ? config[configLabelKey] : config[key]\n}\n\n// Story auto-compile metadata — Phase 1 mechanical migration(2026-04-24)\n// Phase 2 fill needed: purpose descriptions + when rationale + world-class refs\nexport const chartMeta = {\n component: 'Chart',\n family: null, // non-family composite / overlay / layout\n variants: {\n\n },\n sizes: {\n\n },\n states: ['default'],\n tokens: {\n bg: ['bg-surface-raised', 'bg-transparent'],\n fg: ['text-fg-muted', 'text-fg-secondary', 'text-foreground'],\n ring: [],\n },\n} as const\n\nexport {\n ChartContainer,\n ChartTooltip,\n ChartTooltipContent,\n ChartLegend,\n ChartLegendContent,\n ChartStyle,\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"chart.js","sources":["../../../src/components/Chart/chart.tsx"],"sourcesContent":["import * as React from 'react'\nimport * as RechartsPrimitive from 'recharts'\nimport { cn } from '@/lib/utils'\n\n/**\n * Chart — shadcn-style wrapper over Recharts + 本 DS token\n *\n * 結構對齊 shadcn chart(ChartContainer / ChartTooltipContent / ChartLegendContent),\n * 但所有視覺(tooltip / legend / grid / axis)改用本 DS token。\n *\n * ── Color mapping ──\n * ChartConfig.{key}.color 接受 2 種形式:\n * 1. CSS var 字串('var(--chart-1)' 等)\n * 2. 任何合法 CSS color\n * 預設建議使用 --chart-1..5(本 DS 提供的 5 色類別 token)\n *\n * ── 視覺 token ──\n * Tooltip: bg-surface-raised / border-border / shadow-[var(--elevation-200)] / rounded-md\n * Legend text: text-fg-secondary / text-caption\n * Grid: stroke-divider\n * Axis tick: text-fg-muted / text-caption\n */\n\nexport type ChartConfig = {\n [k in string]: {\n label?: React.ReactNode\n icon?: React.ComponentType\n } & (\n | { color?: string; theme?: never }\n | { color?: never; theme: Record<'light' | 'dark', string> }\n )\n}\n\ntype ChartContextProps = { config: ChartConfig }\n\nconst ChartContext = React.createContext<ChartContextProps | null>(null)\n\nfunction useChart() {\n const ctx = React.useContext(ChartContext)\n if (!ctx) throw new Error('useChart 必須在 <ChartContainer> 內使用')\n return ctx\n}\n\n// ── ChartContainer ─────────────────────────────────────────────────────────\n\ninterface ChartContainerProps extends React.ComponentProps<'div'> {\n config: ChartConfig\n children: React.ComponentProps<typeof RechartsPrimitive.ResponsiveContainer>['children']\n}\n\nconst ChartContainer = React.forwardRef<HTMLDivElement, ChartContainerProps>(\n ({ id, className, children, config, ...props }, ref) => {\n const uniqueId = React.useId()\n const chartId = `chart-${id || uniqueId.replace(/:/g, '')}`\n // Memoize provider value(2026-04-22 D3 perf audit):避免 render 重建 wrapper object\n const ctxValue = React.useMemo(() => ({ config }), [config])\n\n return (\n <ChartContext.Provider value={ctxValue}>\n <div\n ref={ref}\n data-chart={chartId}\n className={cn(\n // 整體視覺套用本 DS typography + token\n // 預設 aspect-video(16:9)— Recharts ResponsiveContainer 需 parent 有高度。\n // Consumer 若需其他比例,包 <AspectRatio ratio={n}> 覆寫(AspectRatio 的 padding-bottom 高度會蓋過此 class)。\n 'flex aspect-video justify-center text-caption',\n // recharts 內部預設樣式覆寫:grid / axis / tooltip shadow 等\n \"[&_.recharts-cartesian-grid_line]:stroke-divider\",\n \"[&_.recharts-cartesian-axis-tick_text]:fill-fg-muted\",\n \"[&_.recharts-polar-grid_[stroke='#ccc']]:stroke-divider\",\n \"[&_.recharts-reference-line_[stroke='#ccc']]:stroke-divider\",\n \"[&_.recharts-dot[stroke='#fff']]:stroke-transparent\",\n \"[&_.recharts-layer]:outline-none\",\n \"[&_.recharts-sector[stroke='#fff']]:stroke-transparent\",\n \"[&_.recharts-sector]:outline-none\",\n \"[&_.recharts-surface]:outline-none\",\n className,\n )}\n {...props}\n >\n <ChartStyle id={chartId} config={config} />\n <RechartsPrimitive.ResponsiveContainer>\n {children}\n </RechartsPrimitive.ResponsiveContainer>\n </div>\n </ChartContext.Provider>\n )\n },\n)\nChartContainer.displayName = 'ChartContainer'\n\n// ── ChartStyle ──────────────────────────────────────────────────────────────\n// 將 config 內每個 key 的 color 注入 scoped CSS variable(`--color-{key}`),\n// 供 Recharts `fill={`var(--color-${key})`}` 直接消費。\n\nconst THEMES = { light: '', dark: '[data-theme=dark] ' } as const\n\nfunction ChartStyle({ id, config }: { id: string; config: ChartConfig }) {\n const entries = Object.entries(config).filter(([, v]) => 'color' in v || 'theme' in v)\n if (entries.length === 0) return null\n\n return (\n <style\n dangerouslySetInnerHTML={{\n __html: Object.entries(THEMES)\n .map(([theme, prefix]) => {\n const vars = entries\n .map(([key, item]) => {\n const color =\n 'theme' in item ? item.theme?.[theme as keyof typeof item.theme] : item.color\n return color ? ` --color-${key}: ${color};` : null\n })\n .filter(Boolean)\n .join('\\n')\n return `${prefix}[data-chart=${id}] {\\n${vars}\\n}`\n })\n .join('\\n'),\n }}\n />\n )\n}\n\n// ── ChartTooltip / ChartTooltipContent ─────────────────────────────────────\n\nconst ChartTooltip = RechartsPrimitive.Tooltip\n\ntype RechartsTooltipPayloadItem = {\n value?: string | number\n name?: string | number\n dataKey?: string | number\n color?: string\n payload?: unknown\n [key: string]: unknown\n}\n\ninterface ChartTooltipContentProps extends Omit<React.ComponentProps<'div'>, 'color'> {\n active?: boolean\n payload?: RechartsTooltipPayloadItem[]\n label?: unknown\n labelFormatter?: (value: unknown, payload: RechartsTooltipPayloadItem[]) => React.ReactNode\n labelClassName?: string\n formatter?: (\n value: unknown,\n name: unknown,\n item: RechartsTooltipPayloadItem,\n index: number,\n payload: unknown,\n ) => React.ReactNode\n color?: string\n hideLabel?: boolean\n hideIndicator?: boolean\n indicator?: 'line' | 'dot' | 'dashed'\n nameKey?: string\n labelKey?: string\n}\n\n// code-quality-allow: long-function — foundational composite main body — 拆 sub-fn 會複雜化 local state / ref / context binding\nconst ChartTooltipContent = React.forwardRef<HTMLDivElement, ChartTooltipContentProps>(\n (\n {\n active,\n payload,\n className,\n indicator = 'dot',\n hideLabel = false,\n hideIndicator = false,\n label,\n labelFormatter,\n labelClassName,\n formatter,\n color,\n nameKey,\n labelKey,\n },\n ref,\n ) => {\n const { config } = useChart()\n\n const tooltipLabel = React.useMemo(() => {\n if (hideLabel || !payload?.length) return null\n const [item] = payload\n const key = `${labelKey || item.dataKey || item.name || 'value'}`\n const itemConfig = getPayloadConfig(config, item, key)\n const value =\n !labelKey && typeof label === 'string'\n ? config[label as keyof typeof config]?.label || label\n : itemConfig?.label\n if (labelFormatter) return <div className={cn('font-medium', labelClassName)}>{labelFormatter(value, payload)}</div>\n if (!value) return null\n return <div className={cn('font-medium', labelClassName)}>{value}</div>\n }, [label, labelFormatter, payload, hideLabel, labelClassName, config, labelKey])\n\n if (!active || !payload?.length) return null\n\n const nestLabel = payload.length === 1 && indicator !== 'dot'\n\n return (\n <div\n ref={ref}\n // 2026-05-31 #5:自訂 tooltip 補 role=status + aria-live,保留 Recharts 原生 SR 朗讀(spec L146 宣稱鍵盤可達+讀屏)\n role=\"status\"\n aria-live=\"polite\"\n className={cn(\n 'grid min-w-32 items-start gap-1.5 rounded-md border border-border bg-surface-raised px-2.5 py-1.5 text-caption shadow-[var(--elevation-200)]',\n className,\n )}\n >\n {!nestLabel ? tooltipLabel : null}\n <div className=\"grid gap-1.5\">\n {payload.map((item, index) => {\n const key = `${nameKey || item.name || item.dataKey || 'value'}`\n const itemConfig = getPayloadConfig(config, item, key)\n const indicatorColor = color || (item.payload as { fill?: string })?.fill || item.color\n\n return (\n <div\n key={item.dataKey || index}\n className={cn(\n 'flex w-full flex-wrap items-stretch gap-2 [&>svg]:h-2.5 [&>svg]:w-2.5 [&>svg]:text-fg-muted',\n indicator === 'dot' && 'items-center',\n )}\n >\n {formatter && item?.value !== undefined && item.name ? (\n formatter(item.value, item.name, item, index, item.payload)\n ) : (\n <>\n {itemConfig?.icon ? (\n <itemConfig.icon />\n ) : (\n !hideIndicator && (\n <div\n className={cn('shrink-0 rounded-xs border-(--color-border) bg-(--color-bg)', {\n 'h-2.5 w-2.5': indicator === 'dot',\n 'w-1': indicator === 'line',\n 'w-0 border-[1.5px] border-dashed bg-transparent': indicator === 'dashed',\n 'my-0.5': nestLabel && indicator === 'dashed',\n })}\n style={\n {\n '--color-bg': indicatorColor,\n '--color-border': indicatorColor,\n } as React.CSSProperties\n }\n />\n )\n )}\n <div\n className={cn(\n 'flex flex-1 justify-between leading-none',\n nestLabel ? 'items-end' : 'items-center',\n )}\n >\n <div className=\"grid gap-1.5\">\n {nestLabel ? tooltipLabel : null}\n <span className=\"text-fg-secondary\">{itemConfig?.label || item.name}</span>\n </div>\n {item.value && (\n <span className=\"text-foreground font-mono font-medium tabular-nums\">\n {item.value.toLocaleString()}\n </span>\n )}\n </div>\n </>\n )}\n </div>\n )\n })}\n </div>\n </div>\n )\n },\n)\nChartTooltipContent.displayName = 'ChartTooltipContent'\n\n// ── ChartLegend / ChartLegendContent ───────────────────────────────────────\n\nconst ChartLegend = RechartsPrimitive.Legend\n\ntype RechartsLegendPayloadItem = {\n value?: unknown\n dataKey?: string | number\n color?: string\n payload?: unknown\n [key: string]: unknown\n}\n\ninterface ChartLegendContentProps extends React.ComponentProps<'div'> {\n payload?: RechartsLegendPayloadItem[]\n verticalAlign?: 'top' | 'middle' | 'bottom'\n hideIcon?: boolean\n nameKey?: string\n}\n\nconst ChartLegendContent = React.forwardRef<HTMLDivElement, ChartLegendContentProps>(\n ({ className, hideIcon = false, payload, verticalAlign = 'bottom', nameKey }, ref) => {\n const { config } = useChart()\n if (!payload?.length) return null\n\n return (\n <div\n ref={ref}\n className={cn(\n 'flex items-center justify-center gap-4',\n verticalAlign === 'top' ? 'pb-3' : 'pt-3',\n className,\n )}\n >\n {payload.map((item) => {\n const key = `${nameKey || item.dataKey || 'value'}`\n const itemConfig = getPayloadConfig(config, item, key)\n return (\n <div\n key={String(item.value)}\n className=\"flex items-center gap-1.5 text-fg-secondary [&>svg]:h-3 [&>svg]:w-3 [&>svg]:text-fg-muted\"\n >\n {itemConfig?.icon && !hideIcon ? (\n <itemConfig.icon />\n ) : (\n <div className=\"h-2 w-2 shrink-0 rounded-xs\" style={{ backgroundColor: item.color }} />\n )}\n {itemConfig?.label}\n </div>\n )\n })}\n </div>\n )\n },\n)\nChartLegendContent.displayName = 'ChartLegendContent'\n\n// ── helpers ────────────────────────────────────────────────────────────────\n\nfunction getPayloadConfig(\n config: ChartConfig,\n payload: unknown,\n key: string,\n) {\n if (typeof payload !== 'object' || payload === null) return undefined\n const payloadPayload =\n 'payload' in payload && typeof payload.payload === 'object' && payload.payload !== null\n ? payload.payload\n : undefined\n let configLabelKey: string = key\n if (key in (payload as Record<string, unknown>) && typeof (payload as Record<string, unknown>)[key] === 'string') {\n configLabelKey = (payload as Record<string, string>)[key]\n } else if (payloadPayload && key in payloadPayload && typeof (payloadPayload as Record<string, unknown>)[key] === 'string') {\n configLabelKey = (payloadPayload as Record<string, string>)[key]\n }\n return configLabelKey in config ? config[configLabelKey] : config[key]\n}\n\n// Story auto-compile metadata — Phase 1 mechanical migration(2026-04-24)\n// Phase 2 fill needed: purpose descriptions + when rationale + world-class refs\nexport const chartMeta = {\n component: 'Chart',\n family: null, // non-family composite / overlay / layout\n variants: {\n\n },\n sizes: {\n\n },\n states: ['default'],\n tokens: {\n bg: ['bg-surface-raised', 'bg-transparent'],\n fg: ['text-fg-muted', 'text-fg-secondary', 'text-foreground'],\n ring: [],\n },\n} as const\n\nexport {\n ChartContainer,\n ChartTooltip,\n ChartTooltipContent,\n ChartLegend,\n ChartLegendContent,\n ChartStyle,\n}\n"],"names":[],"mappings":"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"}
@@ -64,7 +64,7 @@ export declare const checkboxMeta: {
64
64
  readonly lg: {
65
65
  readonly fieldHeight: 36;
66
66
  readonly iconSize: 16;
67
- readonly typography: "body";
67
+ readonly typography: "body-lg";
68
68
  };
69
69
  };
70
70
  readonly states: readonly ["default", "hover", "focus-visible", "disabled"];
@@ -141,7 +141,7 @@ const checkboxMeta = {
141
141
  // 2026-06-10 修 stale meta:iconSize 對齊 checkIconSize 真值(L49 sm/md=12, lg=16;deep-audit A.1b 抓 metadata drift)
142
142
  sm: { fieldHeight: 28, iconSize: 12, typography: "body" },
143
143
  md: { fieldHeight: 32, iconSize: 12, typography: "body" },
144
- lg: { fieldHeight: 36, iconSize: 16, typography: "body" }
144
+ lg: { fieldHeight: 36, iconSize: 16, typography: "body-lg" }
145
145
  },
146
146
  states: ["default", "hover", "focus-visible", "disabled"],
147
147
  tokens: {
@@ -1 +1 @@
1
- {"version":3,"file":"checkbox.js","sources":["../../../src/components/Checkbox/checkbox.tsx"],"sourcesContent":["// @benchmark-unverified-blanket: file-level retraction per M22 (d) — claims herein not individually URL-cited; treat as unverified visual/usage rumor unless retrofit per-claim. Hook escape preserved.\nimport * as React from \"react\"\nimport * as CheckboxPrimitive from \"@radix-ui/react-checkbox\"\nimport { Check, Minus } from \"lucide-react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"@/lib/utils\"\nimport type { FieldMode, FieldVariant } from \"@/design-system/components/Field/field-types\"\nimport { useFieldContext, useResolvedFieldDisabled, useResolvedFieldMode, useResolvedFieldSize } from \"@/design-system/components/Field/field-context\"\nimport { fieldWrapperStyles } from \"@/design-system/components/Field/field-wrapper\"\nimport { SelectionItem } from \"@/design-system/components/SelectionControl/selection-item\"\nimport type { LucideIcon } from \"lucide-react\"\nimport type { AvatarData } from \"@/design-system/components/Avatar/avatar\"\nimport { CheckboxGroupContext } from \"./checkbox-group\"\n\n// ── Variants ────────────────────────────────────────────────────────────────\n// 三種尺寸(sm/md=16px, lg=20px),對齊 icon 系統與 SelectionItem。\n\nconst checkboxVariants = cva(\n [\n 'grid place-content-center shrink-0 rounded-md',\n 'border border-border bg-surface',\n 'transition-colors duration-150',\n 'hover:border-border-hover',\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1',\n 'data-[state=checked]:bg-primary data-[state=checked]:text-on-emphasis data-[state=checked]:border-primary',\n 'data-[state=checked]:hover:bg-primary-hover data-[state=checked]:hover:border-primary-hover',\n 'data-[state=indeterminate]:bg-primary data-[state=indeterminate]:text-on-emphasis data-[state=indeterminate]:border-primary',\n 'data-[state=indeterminate]:hover:bg-primary-hover data-[state=indeterminate]:hover:border-primary-hover',\n 'disabled:cursor-not-allowed disabled:bg-disabled disabled:border-transparent disabled:hover:border-transparent',\n 'disabled:data-[state=checked]:bg-disabled disabled:data-[state=checked]:text-fg-disabled disabled:data-[state=checked]:border-transparent',\n 'disabled:data-[state=indeterminate]:bg-disabled disabled:data-[state=indeterminate]:text-fg-disabled disabled:data-[state=indeterminate]:border-transparent',\n // readOnly:鎖定互動但維持 checked/unchecked 視覺\n 'data-[readonly=true]:pointer-events-none data-[readonly=true]:cursor-default',\n 'data-[readonly=true]:hover:border-border',\n ],\n {\n variants: {\n size: {\n sm: 'h-4 w-4',\n md: 'h-4 w-4',\n lg: 'h-5 w-5',\n },\n },\n defaultVariants: {\n size: 'md',\n },\n }\n)\n\n// ── Check Icon Size ─────────────────────────────────────────────────────────\nconst checkIconSize: Record<string, number> = { sm: 12, md: 12, lg: 16 }\n\n// ── Check Icon Stroke Weight ────────────────────────────────────────────────\n// 16px 以下 icon 視覺不夠顯眼 → 用較粗 stroke 補償。Lucide 預設 strokeWidth=2 在\n// 12px 下 render 約 1px 線寬,視覺偏細;加粗到 3.5(render ≈ 1.75px)才有足夠視覺權重。\n// 16px 用 2.5(render ≈ 1.67px)讓 checked 態的 check icon 夠顯眼。\n//\n// 為什麼不是 3 / 2:本 session 實測 3 / 2 在 storybook 上兩個 size 的 render 線寬差僅\n// 0.17px(1.5 vs 1.33),使用者肉眼看不出差異(image #64 回報)。改為 3.5 / 2.5:\n// - md 12px × 3.5 → 1.75px 線寬\n// - lg 16px × 2.5 → 1.67px 線寬\n// 兩者仍接近但 md 的線寬 **絕對值** 跟 16px 預設(1.33)有更明顯差異,視覺上「小 check 更粗」。\n//\n// 世界級對照:iOS HIG / Material 3 / Polaris 的 checkmark 在 <16px 下皆加粗 compensate。\n// 為什麼不用 Lucide absoluteStrokeWidth:那保持「絕對 px 粗細」,我們反而要「小尺寸比例更粗」。\n//\n// Check 與 Minus(indeterminate)共用此規則;Switch 的 SPECS.checkStroke 採同樣值。\n// 2026-05-18 簡化 per user 視覺證「sm/md 3.5 vs lg 2.5 看不出差別」(image #64 + 2nd round\n// 圖一 video proof)+「做完」approval:\n// - 原 {3.5, 3.5, 2.5} → effective render thickness 1.75 / 1.75 / 1.67 = 跨 size 差 0.08px(視覺看不出)\n// - 改 {3, 3, 2.5} 保留 sm/md 小尺寸 legibility insurance(per iOS HIG / Material 3 cite)\n// + lg 仍稍粗於 Lucide default 2(保留 compensation 主旨,但不過度差異化)\n// ⚠️ 2026-06-12:發現 base.css `.lucide{stroke-width:1.75}` 全域規則自 2026-04-08 起\n// 無條件蓋掉本 prop(CSS class > SVG attribute)→ 本表從未真渲染過,上述 05-18 視覺\n// 測試兩者實為 0.875px(證據污染)。base.css 已改 `[stroke-width='2']` 限定,本表自此\n// 真實生效(pixel 驗證 1.50px)。SSOT → .claude/references/ui-dev-rules.md「小尺寸 icon stroke 補償」\nconst checkStrokeWidth: Record<string, number> = { sm: 3, md: 3, lg: 2.5 }\n\n// ── Types ───────────────────────────────────────────────────────────────────\n\nexport interface CheckboxProps\n extends React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root>,\n VariantProps<typeof checkboxVariants> {\n /**\n * Inline label。提供時 Checkbox 自動透過 SelectionItem 包裝,\n * 套用 text-body / text-foreground / disabled 色 的 codified 樣式。\n * 在 <Field> context 內時此 prop 會被忽略(由 FieldLabel 接管)。\n */\n label?: React.ReactNode\n /**\n * Inline description(secondary 文字)。須與 label 搭配使用。\n * 套用 text-body / text-fg-secondary 樣式。\n * 在 <Field> context 內時此 prop 會被忽略(由 FieldDescription 接管)。\n */\n description?: React.ReactNode\n /** 可選左側 icon(label 前)— 2026-06-12 M30 修:轉發 SelectionItem 既有 canonical 槽(selection-item.tsx jsDoc 為 SSOT;與 avatar 互斥)*/\n icon?: LucideIcon\n /** 可選左側 avatar(label 前)— 同上,SelectionItem 槽轉發 */\n avatar?: AvatarData\n /**\n * readonly 模式:鎖定互動但維持 checked/unchecked 視覺正確。\n * 與 disabled 的差異:readonly 不降色(可讀),disabled 降色(弱化)。\n * 用於表單 readonly 呈現、DataTable cell 非編輯態。\n */\n readOnly?: boolean\n /**\n * Field mode(2026-05-05 Phase B3 align):\n * edit — 一般可互動 checkbox(預設)\n * display — **純展示**:渲染 ✓ / —(無互動 primitive、無 input chrome);\n * 對齊 Carbon read-only / DataTable boolean cell 場景。取代既有 BooleanDisplay。\n * readonly — 同 readOnly prop:checkbox 視覺保留 + 鎖互動 + a11y readonly signal\n * disabled — 同 disabled prop:降色 + 鎖互動\n */\n mode?: FieldMode\n /**\n * Visual chrome — checkbox 本體無 input wrapper variant,本 prop 對 checkbox 主體無視覺影響;\n * 為對齊 Field 4-mode + chrome 透傳契約而保留(M19 一致性)。\n */\n variant?: FieldVariant\n}\n\n// ── Component ───────────────────────────────────────────────────────────────\n\nconst Checkbox = React.forwardRef<\n React.ElementRef<typeof CheckboxPrimitive.Root>,\n CheckboxProps\n>(\n (\n {\n className,\n size,\n label,\n icon,\n avatar,\n description,\n readOnly = false,\n disabled,\n mode,\n // chrome 對 Checkbox 主體無視覺影響(無 input wrapper)— 接收純為 prop 一致性;destructure 防 leak 到 DOM。\n variant: _chrome,\n id: idProp,\n ...props\n },\n ref\n ) => {\n const sizeKey = size ?? 'md'\n const iconPx = checkIconSize[sizeKey]\n const iconStrokeWidth = checkStrokeWidth[sizeKey]\n\n // Field context:Checkbox 單獨塞進 Field(binary toggle)時,忽略自己的 label 讓 FieldLabel 接管\n // 2026-05-31 #35:hooks(useFieldContext / useContext / useId)必在任何 conditional return 前呼叫(Rules of Hooks)。\n // 原 mode='display' early return 寫在 hooks 之上 → runtime 切 mode 會 hook count 不一致 crash;已下移至 hooks 後。\n //\n // **例外**:Checkbox 是 CheckboxGroup 的 child 時(multi-select 情境),**每個 checkbox\n // 的 label 是它自己的選項名**,FieldLabel 只是群組名稱 — 此時 label **必須保留**,\n // 不能被 Field context 吞掉。AR50 的根因就是這個 branch 之前誤把 group 內的 checkbox\n // label 全清空,導致 sheet 內 3 個 checkbox 沒 label。\n const fieldCtx = useFieldContext()\n const checkboxGroupCtx = React.useContext(CheckboxGroupContext)\n const insideField = fieldCtx?.hasFieldWrapper === true\n const insideGroup = checkboxGroupCtx?.inGroup === true\n const shouldSuppressLabel = insideField && !insideGroup\n const effectiveLabel = shouldSuppressLabel ? undefined : label\n const effectiveDescription = shouldSuppressLabel ? undefined : description\n\n // Id 連結\n //\n // ── 2026-04-21 bug fix ──\n // 原本:`idProp ?? fieldCtx?.id ?? generatedId`。\n // 在 Field 內 fieldCtx.id 存在,CheckboxGroup 所有 children 共用同一個 id →\n // 每個 checkbox 的 `<label htmlFor={sameId}>` 全指向第一個 checkbox →\n // **點任何 label 都只開關第一個 checkbox(real bug)**。\n //\n // 修法:group 內的 checkbox 強制用 generatedId(唯一),不沿用 Field id;\n // solo in Field(binary toggle)才沿用 fieldCtx.id 讓 FieldLabel htmlFor 生效。\n const generatedId = React.useId()\n const inputId = idProp ?? (insideGroup ? generatedId : (fieldCtx?.id ?? generatedId))\n\n // 2026-06-08 SSOT cascade:disabled + mode 經 resolver hook(原 raw prop → <Field disabled>/<Field mode=\"display\"> 漏 cascade)\n const resolvedDisabled = useResolvedFieldDisabled(disabled)\n const resolvedMode = useResolvedFieldMode({ mode, disabled, readOnly })\n const effectiveReadOnly = readOnly || resolvedMode === 'readonly'\n // mode='disabled'(如 DataTable disabled cell 直傳)必須落到真 disabled chrome —\n // 2026-06-12 修:原本只看 resolvedDisabled(prop/fieldCtx),mode='disabled' 無人消費\n // → disabled boolean cell 渲出可 focus 的正常外觀 checkbox(違 field-controls.spec L286)\n const effectiveDisabled = resolvedDisabled || resolvedMode === 'disabled'\n // readonly 灰框 size:走 SSOT resolver(prop > ctx > 'md',field-context.ts:150-161)\n const resolvedBoxSize = useResolvedFieldSize(size ?? undefined, 'md') as 'sm' | 'md' | 'lg'\n\n // ── mode='display'(下移至所有 hooks 之後,per #35 Rules of Hooks)──────────\n // 純展示模式:無互動 primitive、渲染 ✓ / —(checked=true → ✓ / 其他 → —)。取代 BooleanDisplay。\n if (resolvedMode === 'display') {\n const isChecked = props.checked === true\n return isChecked\n ? <span className=\"text-foreground\">✓</span>\n : <span className=\"text-fg-muted\">—</span>\n }\n\n // ── mode='readonly' in Field(2026-06-12 user 拍板「灰框 + ✓/—」)─────────────\n // Field 內 readonly boolean = readonly 灰框 chrome + display 同款值語言 ✓/—。\n // 灰框消費 fieldWrapperStyles 同一 cva = 與 Input readonly 字面同源(SSOT,改一處全動)。\n // 理由:同一張 readonly 表單裡文字控件有 bg-readonly 灰框鎖定訊號,boolean 保留全彩\n // 控件會誤導「仍可操作」(世界級 0/4 用原樣鎖互動:Salesforce=✓ 靜態 glyph /\n // SAP=靜態文字 / Atlassian=readView / Ant Pro=文字)。\n // Scope:僅 Field 內且無 inline label(FieldLabel 接管 label 的表單欄位場景);\n // standalone readOnly(settings list / SelectionItem row)維持原樣鎖互動不變。\n if (effectiveReadOnly && insideField && effectiveLabel == null) {\n const isChecked = (props.checked ?? props.defaultChecked) === true\n const boxSize = resolvedBoxSize\n return (\n <div\n role=\"checkbox\"\n aria-checked={isChecked}\n aria-readonly=\"true\"\n aria-labelledby={fieldCtx?.labelId}\n aria-invalid={fieldCtx?.invalid || undefined}\n data-readonly=\"true\"\n tabIndex={0}\n className={cn(\n fieldWrapperStyles({ size: boxSize, mode: 'readonly', variant: 'default' }),\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',\n className,\n )}\n >\n {isChecked ? <span className=\"text-foreground\">✓</span> : <span className=\"text-fg-muted\">—</span>}\n </div>\n )\n }\n\n const rootEl = (\n <CheckboxPrimitive.Root\n id={inputId}\n ref={ref}\n disabled={effectiveDisabled}\n aria-readonly={effectiveReadOnly || undefined}\n data-readonly={effectiveReadOnly || undefined}\n tabIndex={effectiveReadOnly ? -1 : undefined}\n aria-describedby={fieldCtx?.descriptionId}\n className={cn(checkboxVariants({ size }), className)}\n {...props}\n >\n <CheckboxPrimitive.Indicator className=\"grid place-content-center text-current\">\n {props.checked === 'indeterminate'\n ? <Minus style={{ width: iconPx, height: iconPx }} strokeWidth={iconStrokeWidth} />\n : <Check style={{ width: iconPx, height: iconPx }} strokeWidth={iconStrokeWidth} />\n }\n </CheckboxPrimitive.Indicator>\n </CheckboxPrimitive.Root>\n )\n\n // 無 label → 只渲染 checkbox 本體\n if (effectiveLabel == null) return rootEl\n\n // 有 label → 透過 SelectionItem 包裝(control 在左、label+description 在右)\n return (\n <SelectionItem\n control={rootEl}\n label={effectiveLabel}\n description={effectiveDescription}\n icon={icon}\n avatar={avatar}\n htmlFor={inputId}\n disabled={effectiveDisabled}\n size={sizeKey}\n />\n )\n }\n)\nCheckbox.displayName = CheckboxPrimitive.Root.displayName\n\n// Story auto-compile metadata — Phase 1 mechanical migration(2026-04-24)\n// Phase 2 fill needed: purpose descriptions + when rationale + world-class refs\nexport const checkboxMeta = {\n component: 'Checkbox',\n family: null, // self-contained primitive(對齊 spec frontmatter self-contained + body L31;非 Family 4)\n variants: {\n\n },\n sizes: {\n // 2026-06-10 修 stale meta:iconSize 對齊 checkIconSize 真值(L49 sm/md=12, lg=16;deep-audit A.1b 抓 metadata drift)\n sm: { fieldHeight: 28, iconSize: 12, typography: 'body' },\n md: { fieldHeight: 32, iconSize: 12, typography: 'body' },\n lg: { fieldHeight: 36, iconSize: 16, typography: 'body' },\n },\n states: ['default', 'hover', 'focus-visible', 'disabled'],\n tokens: {\n bg: ['bg-disabled', 'bg-primary', 'bg-primary-hover', 'bg-surface'],\n fg: ['text-fg-disabled', 'text-fg-secondary', 'text-foreground'],\n ring: ['ring-ring'],\n },\n defaultSize: 'md',\n} as const\n\nexport { Checkbox, checkboxVariants }\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"checkbox.js","sources":["../../../src/components/Checkbox/checkbox.tsx"],"sourcesContent":["// @benchmark-unverified-blanket: file-level retraction per M22 (d) — claims herein not individually URL-cited; treat as unverified visual/usage rumor unless retrofit per-claim. Hook escape preserved.\nimport * as React from \"react\"\nimport * as CheckboxPrimitive from \"@radix-ui/react-checkbox\"\nimport { Check, Minus } from \"lucide-react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"@/lib/utils\"\nimport type { FieldMode, FieldVariant } from \"@/design-system/components/Field/field-types\"\nimport { useFieldContext, useResolvedFieldDisabled, useResolvedFieldMode, useResolvedFieldSize } from \"@/design-system/components/Field/field-context\"\nimport { fieldWrapperStyles } from \"@/design-system/components/Field/field-wrapper\"\nimport { SelectionItem } from \"@/design-system/components/SelectionControl/selection-item\"\nimport type { LucideIcon } from \"lucide-react\"\nimport type { AvatarData } from \"@/design-system/components/Avatar/avatar\"\nimport { CheckboxGroupContext } from \"./checkbox-group\"\n\n// ── Variants ────────────────────────────────────────────────────────────────\n// 三種尺寸(sm/md=16px, lg=20px),對齊 icon 系統與 SelectionItem。\n\nconst checkboxVariants = cva(\n [\n 'grid place-content-center shrink-0 rounded-md',\n 'border border-border bg-surface',\n 'transition-colors duration-150',\n 'hover:border-border-hover',\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1',\n 'data-[state=checked]:bg-primary data-[state=checked]:text-on-emphasis data-[state=checked]:border-primary',\n 'data-[state=checked]:hover:bg-primary-hover data-[state=checked]:hover:border-primary-hover',\n 'data-[state=indeterminate]:bg-primary data-[state=indeterminate]:text-on-emphasis data-[state=indeterminate]:border-primary',\n 'data-[state=indeterminate]:hover:bg-primary-hover data-[state=indeterminate]:hover:border-primary-hover',\n 'disabled:cursor-not-allowed disabled:bg-disabled disabled:border-transparent disabled:hover:border-transparent',\n 'disabled:data-[state=checked]:bg-disabled disabled:data-[state=checked]:text-fg-disabled disabled:data-[state=checked]:border-transparent',\n 'disabled:data-[state=indeterminate]:bg-disabled disabled:data-[state=indeterminate]:text-fg-disabled disabled:data-[state=indeterminate]:border-transparent',\n // readOnly:鎖定互動但維持 checked/unchecked 視覺\n 'data-[readonly=true]:pointer-events-none data-[readonly=true]:cursor-default',\n 'data-[readonly=true]:hover:border-border',\n ],\n {\n variants: {\n size: {\n sm: 'h-4 w-4',\n md: 'h-4 w-4',\n lg: 'h-5 w-5',\n },\n },\n defaultVariants: {\n size: 'md',\n },\n }\n)\n\n// ── Check Icon Size ─────────────────────────────────────────────────────────\nconst checkIconSize: Record<string, number> = { sm: 12, md: 12, lg: 16 }\n\n// ── Check Icon Stroke Weight ────────────────────────────────────────────────\n// 16px 以下 icon 視覺不夠顯眼 → 用較粗 stroke 補償。Lucide 預設 strokeWidth=2 在\n// 12px 下 render 約 1px 線寬,視覺偏細;加粗到 3.5(render ≈ 1.75px)才有足夠視覺權重。\n// 16px 用 2.5(render ≈ 1.67px)讓 checked 態的 check icon 夠顯眼。\n//\n// 為什麼不是 3 / 2:本 session 實測 3 / 2 在 storybook 上兩個 size 的 render 線寬差僅\n// 0.17px(1.5 vs 1.33),使用者肉眼看不出差異(image #64 回報)。改為 3.5 / 2.5:\n// - md 12px × 3.5 → 1.75px 線寬\n// - lg 16px × 2.5 → 1.67px 線寬\n// 兩者仍接近但 md 的線寬 **絕對值** 跟 16px 預設(1.33)有更明顯差異,視覺上「小 check 更粗」。\n//\n// 世界級對照:iOS HIG / Material 3 / Polaris 的 checkmark 在 <16px 下皆加粗 compensate。\n// 為什麼不用 Lucide absoluteStrokeWidth:那保持「絕對 px 粗細」,我們反而要「小尺寸比例更粗」。\n//\n// Check 與 Minus(indeterminate)共用此規則;Switch 的 SPECS.checkStroke 採同樣值。\n// 2026-05-18 簡化 per user 視覺證「sm/md 3.5 vs lg 2.5 看不出差別」(image #64 + 2nd round\n// 圖一 video proof)+「做完」approval:\n// - 原 {3.5, 3.5, 2.5} → effective render thickness 1.75 / 1.75 / 1.67 = 跨 size 差 0.08px(視覺看不出)\n// - 改 {3, 3, 2.5} 保留 sm/md 小尺寸 legibility insurance(per iOS HIG / Material 3 cite)\n// + lg 仍稍粗於 Lucide default 2(保留 compensation 主旨,但不過度差異化)\n// ⚠️ 2026-06-12:發現 base.css `.lucide{stroke-width:1.75}` 全域規則自 2026-04-08 起\n// 無條件蓋掉本 prop(CSS class > SVG attribute)→ 本表從未真渲染過,上述 05-18 視覺\n// 測試兩者實為 0.875px(證據污染)。base.css 已改 `[stroke-width='2']` 限定,本表自此\n// 真實生效(pixel 驗證 1.50px)。SSOT → .claude/references/ui-dev-rules.md「小尺寸 icon stroke 補償」\nconst checkStrokeWidth: Record<string, number> = { sm: 3, md: 3, lg: 2.5 }\n\n// ── Types ───────────────────────────────────────────────────────────────────\n\nexport interface CheckboxProps\n extends React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root>,\n VariantProps<typeof checkboxVariants> {\n /**\n * Inline label。提供時 Checkbox 自動透過 SelectionItem 包裝,\n * 套用 text-body / text-foreground / disabled 色 的 codified 樣式。\n * 在 <Field> context 內時此 prop 會被忽略(由 FieldLabel 接管)。\n */\n label?: React.ReactNode\n /**\n * Inline description(secondary 文字)。須與 label 搭配使用。\n * 套用 text-body / text-fg-secondary 樣式。\n * 在 <Field> context 內時此 prop 會被忽略(由 FieldDescription 接管)。\n */\n description?: React.ReactNode\n /** 可選左側 icon(label 前)— 2026-06-12 M30 修:轉發 SelectionItem 既有 canonical 槽(selection-item.tsx jsDoc 為 SSOT;與 avatar 互斥)*/\n icon?: LucideIcon\n /** 可選左側 avatar(label 前)— 同上,SelectionItem 槽轉發 */\n avatar?: AvatarData\n /**\n * readonly 模式:鎖定互動但維持 checked/unchecked 視覺正確。\n * 與 disabled 的差異:readonly 不降色(可讀),disabled 降色(弱化)。\n * 用於表單 readonly 呈現、DataTable cell 非編輯態。\n */\n readOnly?: boolean\n /**\n * Field mode(2026-05-05 Phase B3 align):\n * edit — 一般可互動 checkbox(預設)\n * display — **純展示**:渲染 ✓ / —(無互動 primitive、無 input chrome);\n * 對齊 Carbon read-only / DataTable boolean cell 場景。取代既有 BooleanDisplay。\n * readonly — 同 readOnly prop:checkbox 視覺保留 + 鎖互動 + a11y readonly signal\n * disabled — 同 disabled prop:降色 + 鎖互動\n */\n mode?: FieldMode\n /**\n * Visual chrome — checkbox 本體無 input wrapper variant,本 prop 對 checkbox 主體無視覺影響;\n * 為對齊 Field 4-mode + chrome 透傳契約而保留(M19 一致性)。\n */\n variant?: FieldVariant\n}\n\n// ── Component ───────────────────────────────────────────────────────────────\n\nconst Checkbox = React.forwardRef<\n React.ElementRef<typeof CheckboxPrimitive.Root>,\n CheckboxProps\n>(\n (\n {\n className,\n size,\n label,\n icon,\n avatar,\n description,\n readOnly = false,\n disabled,\n mode,\n // chrome 對 Checkbox 主體無視覺影響(無 input wrapper)— 接收純為 prop 一致性;destructure 防 leak 到 DOM。\n variant: _chrome,\n id: idProp,\n ...props\n },\n ref\n ) => {\n const sizeKey = size ?? 'md'\n const iconPx = checkIconSize[sizeKey]\n const iconStrokeWidth = checkStrokeWidth[sizeKey]\n\n // Field context:Checkbox 單獨塞進 Field(binary toggle)時,忽略自己的 label 讓 FieldLabel 接管\n // 2026-05-31 #35:hooks(useFieldContext / useContext / useId)必在任何 conditional return 前呼叫(Rules of Hooks)。\n // 原 mode='display' early return 寫在 hooks 之上 → runtime 切 mode 會 hook count 不一致 crash;已下移至 hooks 後。\n //\n // **例外**:Checkbox 是 CheckboxGroup 的 child 時(multi-select 情境),**每個 checkbox\n // 的 label 是它自己的選項名**,FieldLabel 只是群組名稱 — 此時 label **必須保留**,\n // 不能被 Field context 吞掉。AR50 的根因就是這個 branch 之前誤把 group 內的 checkbox\n // label 全清空,導致 sheet 內 3 個 checkbox 沒 label。\n const fieldCtx = useFieldContext()\n const checkboxGroupCtx = React.useContext(CheckboxGroupContext)\n const insideField = fieldCtx?.hasFieldWrapper === true\n const insideGroup = checkboxGroupCtx?.inGroup === true\n const shouldSuppressLabel = insideField && !insideGroup\n const effectiveLabel = shouldSuppressLabel ? undefined : label\n const effectiveDescription = shouldSuppressLabel ? undefined : description\n\n // Id 連結\n //\n // ── 2026-04-21 bug fix ──\n // 原本:`idProp ?? fieldCtx?.id ?? generatedId`。\n // 在 Field 內 fieldCtx.id 存在,CheckboxGroup 所有 children 共用同一個 id →\n // 每個 checkbox 的 `<label htmlFor={sameId}>` 全指向第一個 checkbox →\n // **點任何 label 都只開關第一個 checkbox(real bug)**。\n //\n // 修法:group 內的 checkbox 強制用 generatedId(唯一),不沿用 Field id;\n // solo in Field(binary toggle)才沿用 fieldCtx.id 讓 FieldLabel htmlFor 生效。\n const generatedId = React.useId()\n const inputId = idProp ?? (insideGroup ? generatedId : (fieldCtx?.id ?? generatedId))\n\n // 2026-06-08 SSOT cascade:disabled + mode 經 resolver hook(原 raw prop → <Field disabled>/<Field mode=\"display\"> 漏 cascade)\n const resolvedDisabled = useResolvedFieldDisabled(disabled)\n const resolvedMode = useResolvedFieldMode({ mode, disabled, readOnly })\n const effectiveReadOnly = readOnly || resolvedMode === 'readonly'\n // mode='disabled'(如 DataTable disabled cell 直傳)必須落到真 disabled chrome —\n // 2026-06-12 修:原本只看 resolvedDisabled(prop/fieldCtx),mode='disabled' 無人消費\n // → disabled boolean cell 渲出可 focus 的正常外觀 checkbox(違 field-controls.spec L286)\n const effectiveDisabled = resolvedDisabled || resolvedMode === 'disabled'\n // readonly 灰框 size:走 SSOT resolver(prop > ctx > 'md',field-context.ts:150-161)\n const resolvedBoxSize = useResolvedFieldSize(size ?? undefined, 'md') as 'sm' | 'md' | 'lg'\n\n // ── mode='display'(下移至所有 hooks 之後,per #35 Rules of Hooks)──────────\n // 純展示模式:無互動 primitive、渲染 ✓ / —(checked=true → ✓ / 其他 → —)。取代 BooleanDisplay。\n if (resolvedMode === 'display') {\n const isChecked = props.checked === true\n return isChecked\n ? <span className=\"text-foreground\">✓</span>\n : <span className=\"text-fg-muted\">—</span>\n }\n\n // ── mode='readonly' in Field(2026-06-12 user 拍板「灰框 + ✓/—」)─────────────\n // Field 內 readonly boolean = readonly 灰框 chrome + display 同款值語言 ✓/—。\n // 灰框消費 fieldWrapperStyles 同一 cva = 與 Input readonly 字面同源(SSOT,改一處全動)。\n // 理由:同一張 readonly 表單裡文字控件有 bg-readonly 灰框鎖定訊號,boolean 保留全彩\n // 控件會誤導「仍可操作」(世界級 0/4 用原樣鎖互動:Salesforce=✓ 靜態 glyph /\n // SAP=靜態文字 / Atlassian=readView / Ant Pro=文字)。\n // Scope:僅 Field 內且無 inline label(FieldLabel 接管 label 的表單欄位場景);\n // standalone readOnly(settings list / SelectionItem row)維持原樣鎖互動不變。\n if (effectiveReadOnly && insideField && effectiveLabel == null) {\n const isChecked = (props.checked ?? props.defaultChecked) === true\n const boxSize = resolvedBoxSize\n return (\n <div\n role=\"checkbox\"\n aria-checked={isChecked}\n aria-readonly=\"true\"\n aria-labelledby={fieldCtx?.labelId}\n aria-invalid={fieldCtx?.invalid || undefined}\n data-readonly=\"true\"\n tabIndex={0}\n className={cn(\n fieldWrapperStyles({ size: boxSize, mode: 'readonly', variant: 'default' }),\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',\n className,\n )}\n >\n {isChecked ? <span className=\"text-foreground\">✓</span> : <span className=\"text-fg-muted\">—</span>}\n </div>\n )\n }\n\n const rootEl = (\n <CheckboxPrimitive.Root\n id={inputId}\n ref={ref}\n disabled={effectiveDisabled}\n aria-readonly={effectiveReadOnly || undefined}\n data-readonly={effectiveReadOnly || undefined}\n tabIndex={effectiveReadOnly ? -1 : undefined}\n aria-describedby={fieldCtx?.descriptionId}\n className={cn(checkboxVariants({ size }), className)}\n {...props}\n >\n <CheckboxPrimitive.Indicator className=\"grid place-content-center text-current\">\n {props.checked === 'indeterminate'\n ? <Minus style={{ width: iconPx, height: iconPx }} strokeWidth={iconStrokeWidth} />\n : <Check style={{ width: iconPx, height: iconPx }} strokeWidth={iconStrokeWidth} />\n }\n </CheckboxPrimitive.Indicator>\n </CheckboxPrimitive.Root>\n )\n\n // 無 label → 只渲染 checkbox 本體\n if (effectiveLabel == null) return rootEl\n\n // 有 label → 透過 SelectionItem 包裝(control 在左、label+description 在右)\n return (\n <SelectionItem\n control={rootEl}\n label={effectiveLabel}\n description={effectiveDescription}\n icon={icon}\n avatar={avatar}\n htmlFor={inputId}\n disabled={effectiveDisabled}\n size={sizeKey}\n />\n )\n }\n)\nCheckbox.displayName = CheckboxPrimitive.Root.displayName\n\n// Story auto-compile metadata — Phase 1 mechanical migration(2026-04-24)\n// Phase 2 fill needed: purpose descriptions + when rationale + world-class refs\nexport const checkboxMeta = {\n component: 'Checkbox',\n family: null, // self-contained primitive(對齊 spec frontmatter self-contained + body L31;非 Family 4)\n variants: {\n\n },\n sizes: {\n // 2026-06-10 修 stale meta:iconSize 對齊 checkIconSize 真值(L49 sm/md=12, lg=16;deep-audit A.1b 抓 metadata drift)\n sm: { fieldHeight: 28, iconSize: 12, typography: 'body' },\n md: { fieldHeight: 32, iconSize: 12, typography: 'body' },\n lg: { fieldHeight: 36, iconSize: 16, typography: 'body-lg' },\n },\n states: ['default', 'hover', 'focus-visible', 'disabled'],\n tokens: {\n bg: ['bg-disabled', 'bg-primary', 'bg-primary-hover', 'bg-surface'],\n fg: ['text-fg-disabled', 'text-fg-secondary', 'text-foreground'],\n ring: ['ring-ring'],\n },\n defaultSize: 'md',\n} as const\n\nexport { Checkbox, checkboxVariants }\n"],"names":[],"mappings":"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"}
@@ -115,7 +115,7 @@ export interface ComboboxProps {
115
115
  * **2026-05-13 v2 deprecate path**:原 PeoplePicker pass `{8}` 假設「Combobox tagPadding=4px,4+8=12」
116
116
  * 但 `tagPadding[size]` 是 density-dependent calc `(field-height - icon-size) / 2`,只在 md size +
117
117
  * default density 才 = 4px;其他 size/density 漂 6/8px → 4+8=12 公式破。改 PeoplePicker 直接 inject
118
- * `!px-3` className 到 Combobox Field wrapper(per people-picker.spec.md:94 v2),`tagAreaPaddingLeftPx`
118
+ * `!px-[var(--field-px)]` className 到 Combobox Field wrapper(per people-picker.spec.md:94 v2),`tagAreaPaddingLeftPx`
119
119
  * 走 undefined。Future 仍保留此 prop 給其他 consumer 精準調整 padding,但 PeoplePicker 已不再用。
120
120
  */
121
121
  tagAreaPaddingLeftPx?: number;
@@ -1 +1 @@
1
- {"version":3,"file":"combobox.d.ts","sourceRoot":"","sources":["../../../src/components/Combobox/combobox.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAG9B,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,8CAA8C,CAAA;AAM3F,OAAO,EAAc,KAAK,gBAAgB,EAAE,MAAM,mDAAmD,CAAA;AAcrG;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,WAAW,cAAe,SAAQ,gBAAgB;CAEvD;AAgLD,KAAK,qBAAqB,GAAG,QAAQ,GAAG,KAAK,CAAA;AA6I7C,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB,uFAAuF;IACvF,OAAO,CAAC,EAAE,YAAY,CAAA;IACtB,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;IACzB,OAAO,EAAE,cAAc,EAAE,CAAA;IACzB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;IAChB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,CAAA;IACpC,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,WAAW;IACX,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB;;kGAE8F;IAC9F,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,gDAAgD;IAChD,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC7B,8CAA8C;IAC9C,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,qCAAqC;IACrC,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,sDAAsD;IACtD,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,4FAA4F;IAC5F,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB;gDAC4C;IAC5C,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,mFAAmF;IACnF,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACtC;;;;;;;;OAQG;IACH,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,QAAQ,EAAE,MAAM,IAAI,KAAK,KAAK,CAAC,SAAS,CAAA;IAC/F;;;;;OAKG;IACH,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,KAAK,KAAK,CAAC,SAAS,CAAA;IAC7E;;;;;;OAMG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B;;;sEAGkE;IAClE,wBAAwB,CAAC,EAAE,MAAM,CAAA;IACjC;;;;;;;;OAQG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB;;;;;;;;;;;;;;OAcG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAA;IAC7B;;;;OAIG;IACH,aAAa,CAAC,EAAE,qBAAqB,CAAA;IACrC;;;;;;;OAOG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAA;IAC7B;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAA;CAC7B;AA8VD,QAAA,MAAM,QAAQ,sFAab,CAAA;AAKD,eAAO,MAAM,YAAY;;;;;;;;;;;CAef,CAAA;AAEV,OAAO,EAAE,QAAQ,EAAE,CAAA"}
1
+ {"version":3,"file":"combobox.d.ts","sourceRoot":"","sources":["../../../src/components/Combobox/combobox.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAG9B,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,8CAA8C,CAAA;AAM3F,OAAO,EAAc,KAAK,gBAAgB,EAAE,MAAM,mDAAmD,CAAA;AAcrG;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,WAAW,cAAe,SAAQ,gBAAgB;CAEvD;AAgLD,KAAK,qBAAqB,GAAG,QAAQ,GAAG,KAAK,CAAA;AA6I7C,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB,uFAAuF;IACvF,OAAO,CAAC,EAAE,YAAY,CAAA;IACtB,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;IACzB,OAAO,EAAE,cAAc,EAAE,CAAA;IACzB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;IAChB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,CAAA;IACpC,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,WAAW;IACX,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB;;kGAE8F;IAC9F,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,gDAAgD;IAChD,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC7B,8CAA8C;IAC9C,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,qCAAqC;IACrC,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,sDAAsD;IACtD,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,4FAA4F;IAC5F,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB;gDAC4C;IAC5C,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,mFAAmF;IACnF,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACtC;;;;;;;;OAQG;IACH,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,QAAQ,EAAE,MAAM,IAAI,KAAK,KAAK,CAAC,SAAS,CAAA;IAC/F;;;;;OAKG;IACH,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,KAAK,KAAK,CAAC,SAAS,CAAA;IAC7E;;;;;;OAMG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B;;;sEAGkE;IAClE,wBAAwB,CAAC,EAAE,MAAM,CAAA;IACjC;;;;;;;;OAQG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB;;;;;;;;;;;;;;OAcG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAA;IAC7B;;;;OAIG;IACH,aAAa,CAAC,EAAE,qBAAqB,CAAA;IACrC;;;;;;;OAOG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAA;IAC7B;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAA;CAC7B;AAyWD,QAAA,MAAM,QAAQ,sFAab,CAAA;AAKD,eAAO,MAAM,YAAY;;;;;;;;;;;CAef,CAAA;AAEV,OAAO,EAAE,QAAQ,EAAE,CAAA"}
@@ -188,6 +188,7 @@ function ReadonlyMultiSelect({
188
188
  const variant = variantProp ?? "default";
189
189
  const sz = size ?? "md";
190
190
  const iconSize = sz === "lg" ? 20 : 16;
191
+ const tagHeight = sz === "sm" ? 20 : 24;
191
192
  const containerRef = React.useRef(null);
192
193
  const hasTags = ((value == null ? void 0 : value.length) ?? 0) > 0;
193
194
  if (resolvedMode === "display") {
@@ -217,10 +218,12 @@ function ReadonlyMultiSelect({
217
218
  // 2026-05-18 #6A Round 1 Step 1/4(per user 拍板「決策6選a」+ codex M31 Step 5 verdict cite combobox.tsx:451):
218
219
  // readonly/disabled path 對齊 L293 display wrapper 已 ship 的 overflow-hidden fix。
219
220
  // M10 propagation:原 overflow-visible 讓 readonly tag 越界蓋 indicator,跟 display 不對稱。
220
- wrap ? "flex-wrap py-1" : "overflow-hidden",
221
+ // 2026-06-27 對齊 edit path(L598-617):wrap 時 items-start + chevron self-start/tagHeight 鎖第一行;
222
+ // paddingRight: var(--field-px) re-assert 右緣 12px(tagPadding 對稱 calc 會吃掉右緣,跟 edit 一致)。
223
+ wrap ? "flex-wrap items-start py-1" : "overflow-hidden",
221
224
  className
222
225
  ),
223
- style: { gap: GAP, ...wrap ? { height: "auto" } : void 0 },
226
+ style: { gap: GAP, paddingRight: "var(--field-px)", ...wrap ? { height: "auto" } : void 0 },
224
227
  "data-field-mode": resolvedMode,
225
228
  "aria-disabled": resolvedMode === "disabled" ? true : void 0,
226
229
  children: [
@@ -235,7 +238,7 @@ function ReadonlyMultiSelect({
235
238
  disabled: resolvedMode === "disabled"
236
239
  }
237
240
  ) : /* @__PURE__ */ jsx("span", { className: "text-fg-muted", children: EMPTY_DISPLAY }),
238
- (variant === "naked" ? !!showDisplayEndIcon : true) && /* @__PURE__ */ jsx(ItemSuffix, { className: "pointer-events-none", children: /* @__PURE__ */ jsx(ChevronDown, { size: iconSize, className: cn("shrink-0", resolvedMode === "disabled" ? "text-fg-disabled" : "text-fg-muted"), "aria-hidden": true }) })
241
+ (variant === "naked" ? !!showDisplayEndIcon : resolvedMode === "disabled") && /* @__PURE__ */ jsx(ItemSuffix, { className: cn("pointer-events-none", wrap && "self-start"), style: wrap ? { height: tagHeight } : void 0, children: /* @__PURE__ */ jsx(ChevronDown, { size: iconSize, className: cn("shrink-0", resolvedMode === "disabled" ? "text-fg-disabled" : "text-fg-muted"), "aria-hidden": true }) })
239
242
  ]
240
243
  }
241
244
  );
@@ -265,6 +268,8 @@ function NativeCombobox({
265
268
  const handleAdd = (v) => {
266
269
  if (!value.includes(v)) onChange == null ? void 0 : onChange([...value, v]);
267
270
  };
271
+ const selectRef = React.useRef(null);
272
+ const tagAreaRef = React.useRef(null);
268
273
  if (resolvedMode !== "edit") {
269
274
  return /* @__PURE__ */ jsx(ReadonlyMultiSelect, { mode: resolvedMode, variant, size, options, value, wrap, className, showDisplayEndIcon });
270
275
  }
@@ -273,8 +278,6 @@ function NativeCombobox({
273
278
  return { value: v, label: ((_a = options.find((o) => o.value === v)) == null ? void 0 : _a.label) ?? v };
274
279
  });
275
280
  const unselected = options.filter((o) => !value.includes(o.value));
276
- const selectRef = React.useRef(null);
277
- const tagAreaRef = React.useRef(null);
278
281
  const tagHeight = size === "sm" ? 20 : 24;
279
282
  const selectDropdown = unselected.length > 0 ? /* @__PURE__ */ jsxs(
280
283
  "select",
@@ -304,7 +307,7 @@ function NativeCombobox({
304
307
  error && ["border-error hover:border-error-hover", "focus-within:border-error focus-within:hover:border-error"],
305
308
  className
306
309
  ),
307
- style: { paddingRight: "0.75rem", ...wrap ? { height: "auto" } : void 0 },
310
+ style: { paddingRight: "var(--field-px)", ...wrap ? { height: "auto" } : void 0 },
308
311
  "data-field-mode": "edit",
309
312
  "data-error": error ? "" : void 0,
310
313
  onClick: (e) => {
@@ -428,9 +431,6 @@ function CustomCombobox({
428
431
  React.useEffect(() => {
429
432
  if (!open) setSearch("");
430
433
  }, [open]);
431
- if (resolvedMode !== "edit") {
432
- return /* @__PURE__ */ jsx(ReadonlyMultiSelect, { mode: resolvedMode, variant, size, options, value, wrap, className, showDisplayEndIcon });
433
- }
434
434
  const items = React.useMemo(
435
435
  () => value.map((v) => {
436
436
  var _a;
@@ -457,6 +457,9 @@ function CustomCombobox({
457
457
  })),
458
458
  [filteredOptions]
459
459
  );
460
+ if (resolvedMode !== "edit") {
461
+ return /* @__PURE__ */ jsx(ReadonlyMultiSelect, { mode: resolvedMode, variant, size, options, value, wrap, className, showDisplayEndIcon });
462
+ }
460
463
  const chevronEl = /* @__PURE__ */ jsx(ChevronDown, { size: iconSize, className: cn("shrink-0 text-fg-muted transition-transform", open && "rotate-180"), "aria-hidden": true });
461
464
  const trigger = /* @__PURE__ */ jsxs(
462
465
  "div",
@@ -483,7 +486,7 @@ function CustomCombobox({
483
486
  error && ["border-error hover:border-error-hover", "focus-within:border-error focus-within:hover:border-error"],
484
487
  className
485
488
  ),
486
- style: { paddingRight: "0.75rem", ...wrap ? { height: "auto" } : void 0 },
489
+ style: { paddingRight: "var(--field-px)", ...wrap ? { height: "auto" } : void 0 },
487
490
  "data-field-mode": "edit",
488
491
  "data-error": error ? "" : void 0,
489
492
  onKeyDown: (e) => {