@qijenchen/design-system 0.1.0-beta.68 → 0.1.0-beta.70

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 (33) hide show
  1. package/dist/components/Steps/steps.d.ts.map +1 -1
  2. package/dist/components/Steps/steps.js +11 -3
  3. package/dist/components/Steps/steps.js.map +1 -1
  4. package/ds-canonical/fork/governance.lock +112 -0
  5. package/ds-canonical/fork/hooks/__pycache__/block_prototype_imports.cpython-312.pyc +0 -0
  6. package/ds-canonical/fork/hooks/block_prototype_imports.py +111 -0
  7. package/ds-canonical/fork/hooks/check_chrome_header_avatar_canonical.sh +95 -0
  8. package/ds-canonical/fork/hooks/check_consumer_app_invariants.sh +349 -0
  9. package/ds-canonical/fork/hooks/check_ds_anchor_preflight.sh +132 -0
  10. package/ds-canonical/fork/hooks/check_escape_marker_abuse.sh +140 -0
  11. package/ds-canonical/fork/hooks/check_field_family_invariants.sh +250 -0
  12. package/ds-canonical/fork/hooks/check_fork_product_quality.sh +36 -0
  13. package/ds-canonical/fork/hooks/check_item_list_gap.sh +54 -0
  14. package/ds-canonical/fork/hooks/check_layout_space_magic_numbers.sh +96 -0
  15. package/ds-canonical/fork/hooks/check_opacity_token_usage.sh +149 -0
  16. package/ds-canonical/fork/hooks/check_pattern_invariants.sh +196 -0
  17. package/ds-canonical/fork/hooks/check_sidebar_menu_button_implicit_wrap.sh +86 -0
  18. package/ds-canonical/fork/hooks/check_tailwind_wildcard_in_docs.sh +79 -0
  19. package/ds-canonical/fork/hooks/inject_deploy_url_after_push.sh +238 -0
  20. package/ds-canonical/fork/launchers/fork-governance-dispatcher.sh +44 -0
  21. package/ds-canonical/fork/launchers/inject_fork_governance_preamble.sh +46 -0
  22. package/ds-canonical/fork/launchers/settings-hooks.json +58 -0
  23. package/ds-canonical/fork/manifest.json +79 -0
  24. package/ds-canonical/fork/preamble.md +495 -0
  25. package/ds-canonical/hooks/check_consumer_app_invariants.sh +19 -0
  26. package/ds-canonical/references/scenario-definition.md +4 -4
  27. package/ds-canonical/skills/design-system-audit/SKILL.md +1 -1
  28. package/llms-full.txt +1 -1
  29. package/llms.txt +1 -1
  30. package/package.json +3 -1
  31. package/src/components/Steps/steps.tsx +11 -3
  32. package/src/story-governance/category-matrix.json +132 -0
  33. package/src/tokens/utility-registry.json +124 -0
@@ -1 +1 @@
1
- {"version":3,"file":"steps.d.ts","sourceRoot":"","sources":["../../../src/components/Steps/steps.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAE9B,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAMjE,MAAM,MAAM,SAAS,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;AAE1C,MAAM,MAAM,gBAAgB,GAAG,UAAU,GAAG,YAAY,CAAA;AACxD,MAAM,MAAM,cAAc,GAAG,eAAe,GAAG,UAAU,CAAA;AACzD,MAAM,MAAM,gBAAgB,GAAG,UAAU,GAAG,WAAW,GAAG,SAAS,GAAG,WAAW,GAAG,OAAO,CAAA;AA4I3F,QAAA,MAAM,iBAAiB;;8EAQrB,CAAA;AAEF,MAAM,WAAW,UACf,SAAQ,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,gBAAgB,CAAC,EAAE,UAAU,GAAG,cAAc,CAAC,EAC/E,YAAY,CAAC,OAAO,iBAAiB,CAAC;IACxC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IACvC,eAAe,CAAC,EAAE,MAAM,EAAE,CAAA;IAC1B,WAAW,CAAC,EAAE,MAAM,EAAE,CAAA;IACtB,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB,WAAW,CAAC,EAAE,gBAAgB,CAAA;IAC9B,SAAS,CAAC,EAAE,cAAc,CAAA;IAC1B,eAAe,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,MAAM,EAAE,CAAA;CAC5C;AAGD,QAAA,MAAM,KAAK,qFAyHV,CAAA;AAKD,UAAU,qBAAqB;IAC7B,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AAED,MAAM,WAAW,aACf,SAAQ,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,aAAa,CAAC,EAAE,OAAO,CAAC,EACxD,qBAAqB;IACvB,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AAED,QAAA,MAAM,gBAAgB;;;8EAgBpB,CAAA;AAGF,QAAA,MAAM,QAAQ,qFA8Db,CAAA;AA4WD,MAAM,WAAW,cAAe,SAAQ,KAAK,CAAC,cAAc,CAAC,eAAe,CAAC;CAAG;AAGhF,QAAA,MAAM,SAAS,wFA0Bd,CAAA;AAKD,MAAM,WAAW,oBAAqB,SAAQ,KAAK,CAAC,cAAc,CAAC,eAAe,CAAC;CAAG;AAEtF,QAAA,MAAM,eAAe,8FA2BpB,CAAA;AAKD,MAAM,WAAW,gBAAiB,SAAQ,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC;CAAG;AAEjF,QAAA,MAAM,WAAW,yFAchB,CAAA;AAOD,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;CAeZ,CAAA;AAEV,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,eAAe,EAAE,WAAW,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,CAAA"}
1
+ {"version":3,"file":"steps.d.ts","sourceRoot":"","sources":["../../../src/components/Steps/steps.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAE9B,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAMjE,MAAM,MAAM,SAAS,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;AAE1C,MAAM,MAAM,gBAAgB,GAAG,UAAU,GAAG,YAAY,CAAA;AACxD,MAAM,MAAM,cAAc,GAAG,eAAe,GAAG,UAAU,CAAA;AACzD,MAAM,MAAM,gBAAgB,GAAG,UAAU,GAAG,WAAW,GAAG,SAAS,GAAG,WAAW,GAAG,OAAO,CAAA;AA4I3F,QAAA,MAAM,iBAAiB;;8EAQrB,CAAA;AAEF,MAAM,WAAW,UACf,SAAQ,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,gBAAgB,CAAC,EAAE,UAAU,GAAG,cAAc,CAAC,EAC/E,YAAY,CAAC,OAAO,iBAAiB,CAAC;IACxC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IACvC,eAAe,CAAC,EAAE,MAAM,EAAE,CAAA;IAC1B,WAAW,CAAC,EAAE,MAAM,EAAE,CAAA;IACtB,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB,WAAW,CAAC,EAAE,gBAAgB,CAAA;IAC9B,SAAS,CAAC,EAAE,cAAc,CAAA;IAC1B,eAAe,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,MAAM,EAAE,CAAA;CAC5C;AAGD,QAAA,MAAM,KAAK,qFAyHV,CAAA;AAKD,UAAU,qBAAqB;IAC7B,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AAED,MAAM,WAAW,aACf,SAAQ,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,aAAa,CAAC,EAAE,OAAO,CAAC,EACxD,qBAAqB;IACvB,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AAED,QAAA,MAAM,gBAAgB;;;8EAgBpB,CAAA;AAGF,QAAA,MAAM,QAAQ,qFA8Db,CAAA;AAkXD,MAAM,WAAW,cAAe,SAAQ,KAAK,CAAC,cAAc,CAAC,eAAe,CAAC;CAAG;AAGhF,QAAA,MAAM,SAAS,wFA4Bd,CAAA;AAKD,MAAM,WAAW,oBAAqB,SAAQ,KAAK,CAAC,cAAc,CAAC,eAAe,CAAC;CAAG;AAEtF,QAAA,MAAM,eAAe,8FA2BpB,CAAA;AAKD,MAAM,WAAW,gBAAiB,SAAQ,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC;CAAG;AAEjF,QAAA,MAAM,WAAW,yFAchB,CAAA;AAOD,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;CAeZ,CAAA;AAEV,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,eAAe,EAAE,WAAW,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,CAAA"}
@@ -296,7 +296,11 @@ function StepItemHeader({ children, className, style }) {
296
296
  onKeyDown: item.clickable ? onKeyDown : void 0,
297
297
  "aria-disabled": item.disabled || void 0,
298
298
  className: cn(
299
- "outline-none",
299
+ // leading-compact:scanning-family header 行高 = 1.3(item-anatomy.spec.md:776 掃描模式 label 行高)。
300
+ // 設在 header 而非 li 根 → prefix h-[1lh] + 水平 connector h-[1lh] + label(StepLabel 亦 leading-compact)
301
+ // 全用 1.3 對齊;li 根 text-body(1.5,steps.tsx:329-331)留給展開 content 的 reading 行高,不被
302
+ // scanning 波及(避免 改A壞B)。對齊 MenuItem 把 leading-compact 放 row 容器之原則(item-anatomy.tsx:144-146)。
303
+ "outline-none leading-compact",
300
304
  item.clickable ? "cursor-pointer rounded-md focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring" : "cursor-not-allowed",
301
305
  className
302
306
  ),
@@ -356,7 +360,9 @@ function VerticalConnectorLine() {
356
360
  {
357
361
  "aria-hidden": true,
358
362
  className: cn(
359
- "absolute w-px",
363
+ // leading-compact:connector 的 0.5lh 須跟 scanning label 同行高(1.3)→ 起點對齊 circle 中心
364
+ // (circle 對齊 label 第一行;label 已 leading-compact)。否則 connector 繼承 li 根 1.5 → 0.5lh 偏大 → 起點偏低。
365
+ "absolute w-px leading-compact",
360
366
  isBlue ? "bg-info" : "bg-border"
361
367
  ),
362
368
  style: {
@@ -516,7 +522,9 @@ const StepLabel = React.forwardRef(
516
522
  {
517
523
  ref,
518
524
  className: cn(
519
- "font-medium break-words",
525
+ // leading-compact:scanning-family label 行高 = 1.3(item-anatomy.spec.md:776);text-body utility
526
+ // 自帶 lh:1.5,須顯式 leading-compact 蓋回 1.3,跟 MenuItem label(實測 14px/18px=1.3)一致。
527
+ "font-medium break-words leading-compact",
520
528
  size === "lg" ? "text-body-lg" : "text-body",
521
529
  disabled ? "text-fg-disabled" : state === "error" ? "text-error-text" : focused ? "text-foreground" : "text-fg-secondary",
522
530
  className
@@ -1 +1 @@
1
- {"version":3,"file":"steps.js","sources":["../../../src/components/Steps/steps.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.\n// code-quality-allow: file-size — foundational composite(Steps + StepItem + orientation/state/connector 邏輯緊密耦合,拆檔會讓 props drilling 複雜化超過可讀 gain)\nimport * as React from 'react'\nimport { Check, ChevronDown, X } from 'lucide-react'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { cn } from '@/lib/utils'\nimport { ItemPrefix, ItemSuffix } from '@/design-system/patterns/element-anatomy/item-anatomy'\n\n// ── Types ─────────────────────────────────────────────────────────────────\n\nexport type StepsSize = 'sm' | 'md' | 'lg'\n// code-quality-allow: dead-export — public API surface — consumer-exposed for future use\nexport type StepsOrientation = 'vertical' | 'horizontal'\nexport type StepsExpansion = 'follow-active' | 'multiple'\nexport type StepContentState = 'upcoming' | 'reachable' | 'current' | 'completed' | 'error'\n\n// ── Constants ─────────────────────────────────────────────────────────────\n\nconst INDICATOR_SIZE: Record<StepsSize, number> = {\n sm: 8,\n md: 24,\n lg: 32,\n}\n\nconst INDICATOR_ICON_SIZE: Record<StepsSize, number> = {\n sm: 0,\n md: 16,\n lg: 20,\n}\n\nconst SM_HIT_AREA = 24\n\nconst INDICATOR_BOX_WIDTH: Record<StepsSize, number> = {\n sm: SM_HIT_AREA,\n md: INDICATOR_SIZE.md,\n lg: INDICATOR_SIZE.lg,\n}\n\n// ── Outer ring (box-shadow, zero layout impact) ───────────────────────────\n\nconst RING_GAP_PX = 2\nconst RING_WIDTH_PX = 2\n\nfunction getOuterRingShadow(ringColor: string): string {\n return `0 0 0 ${RING_GAP_PX}px var(--surface), 0 0 0 ${RING_GAP_PX + RING_WIDTH_PX}px ${ringColor}`\n}\n\nfunction resolveRingColor(state: StepContentState, linear: boolean): string {\n if (state === 'error') return 'var(--error-hover)'\n if (state === 'current' && !linear) return 'var(--border-hover)'\n return 'var(--info-hover)'\n}\n\n// ── Contexts ──────────────────────────────────────────────────────────────\n\ninterface StepsContextValue {\n value: string | undefined\n completedValues: Set<string>\n errorValues: Set<string>\n reachableValues: Set<string>\n linear: boolean\n size: StepsSize\n orientation: StepsOrientation\n expansion: StepsExpansion\n expandedSet: Set<string>\n setValue: (value: string) => void\n toggleExpanded: (value: string) => void\n total: number\n}\n\nconst StepsContext = React.createContext<StepsContextValue | null>(null)\n\nfunction useStepsContext(): StepsContextValue {\n const ctx = React.useContext(StepsContext)\n if (!ctx) throw new Error('Steps compound components must be rendered inside <Steps>')\n return ctx\n}\n\ninterface StepItemContextValue {\n value: string\n state: StepContentState\n focused: boolean\n disabled: boolean\n clickable: boolean\n expanded: boolean\n isLast: boolean\n activate: () => void\n}\n\nconst StepItemContext = React.createContext<StepItemContextValue | null>(null)\n\nfunction useStepItemContext(): StepItemContextValue {\n const ctx = React.useContext(StepItemContext)\n if (!ctx) throw new Error('StepLabel / StepDescription / StepContent must be inside <StepItem>')\n return ctx\n}\n\nconst StepIndexContext = React.createContext<number>(0)\n\n// ── Pure helpers ──────────────────────────────────────────────────────────\n\nfunction computeState(\n itemValue: string,\n value: string | undefined,\n completedValues: Set<string>,\n errorValues: Set<string>,\n reachableValues: Set<string>,\n linear: boolean,\n override: StepContentState | undefined,\n): StepContentState {\n if (override) return override\n if (errorValues.has(itemValue)) return 'error'\n if (completedValues.has(itemValue)) return 'completed'\n if (itemValue === value) return 'current'\n if (linear && reachableValues.has(itemValue)) return 'reachable'\n return 'upcoming'\n}\n\nfunction isClickable(\n state: StepContentState,\n linear: boolean,\n disabled: boolean,\n): boolean {\n if (disabled) return false\n if (!linear) return true\n return state !== 'upcoming'\n}\n\nfunction normalizeExpanded(\n defaultExpanded: 'all' | 'none' | string[] | undefined,\n allValues: string[],\n): Set<string> {\n if (defaultExpanded === 'all') return new Set(allValues)\n if (!defaultExpanded || defaultExpanded === 'none') return new Set()\n return new Set(defaultExpanded)\n}\n\nfunction computeReachableValues(\n childValues: string[],\n completedValues: string[],\n): Set<string> {\n const completed = new Set(completedValues)\n const reachable = new Set(completed)\n for (const v of childValues) {\n if (!completed.has(v)) {\n reachable.add(v)\n break\n }\n }\n return reachable\n}\n\n// ── Steps root ────────────────────────────────────────────────────────────\n\nconst stepsRootVariants = cva('list-none p-0 m-0', {\n variants: {\n orientation: {\n vertical: 'flex flex-col',\n horizontal: 'flex flex-row items-start gap-3',\n },\n },\n defaultVariants: { orientation: 'vertical' },\n})\n\nexport interface StepsProps\n extends Omit<React.HTMLAttributes<HTMLOListElement>, 'onChange' | 'defaultValue'>,\n VariantProps<typeof stepsRootVariants> {\n value?: string\n defaultValue?: string\n onValueChange?: (value: string) => void\n completedValues?: string[]\n errorValues?: string[]\n linear?: boolean\n size?: StepsSize\n orientation?: StepsOrientation\n expansion?: StepsExpansion\n defaultExpanded?: 'all' | 'none' | string[]\n}\n\n// code-quality-allow: long-function — foundational composite main body — 拆 sub-fn 會複雜化 local state / ref / context binding\nconst Steps = React.forwardRef<HTMLOListElement, StepsProps>(\n (\n {\n value: valueProp,\n defaultValue,\n onValueChange,\n completedValues = [],\n errorValues = [],\n linear = true,\n size = 'md',\n orientation = 'vertical',\n expansion = 'follow-active',\n defaultExpanded,\n className,\n children,\n ...props\n },\n ref,\n ) => {\n const [internalValue, setInternalValue] = React.useState<string | undefined>(defaultValue)\n const isControlled = valueProp !== undefined\n const value = isControlled ? valueProp : internalValue\n\n const setValue = React.useCallback(\n (next: string) => {\n if (!isControlled) setInternalValue(next)\n onValueChange?.(next)\n },\n [isControlled, onValueChange],\n )\n\n const childValues = React.useMemo(() => {\n const vals: string[] = []\n React.Children.forEach(children, child => {\n if (\n React.isValidElement(child) &&\n typeof child.props === 'object' &&\n child.props &&\n 'value' in child.props\n ) {\n vals.push(String((child.props as { value: string }).value))\n }\n })\n return vals\n }, [children])\n\n const reachableValues = React.useMemo(\n () => computeReachableValues(childValues, completedValues),\n [childValues, completedValues],\n )\n\n const [expandedSet, setExpandedSet] = React.useState<Set<string>>(() =>\n normalizeExpanded(defaultExpanded, childValues),\n )\n\n const toggleExpanded = React.useCallback((itemValue: string) => {\n setExpandedSet(prev => {\n const next = new Set(prev)\n if (next.has(itemValue)) next.delete(itemValue)\n else next.add(itemValue)\n return next\n })\n }, [])\n\n const stepCount = React.Children.count(children)\n\n const ctxValue = React.useMemo<StepsContextValue>(\n () => ({\n value,\n completedValues: new Set(completedValues),\n errorValues: new Set(errorValues),\n reachableValues,\n linear,\n size,\n orientation,\n expansion,\n expandedSet,\n setValue,\n toggleExpanded,\n total: stepCount,\n }),\n [value, completedValues, errorValues, reachableValues, linear, size, orientation, expansion, expandedSet, setValue, toggleExpanded, stepCount],\n )\n\n // Interleave horizontal connectors between items\n const count = stepCount\n const itemsWithIndex: React.ReactNode[] = []\n\n React.Children.forEach(children, (child, index) => {\n if (!React.isValidElement(child)) {\n itemsWithIndex.push(child)\n return\n }\n const isLast = index === count - 1\n const cloned = React.cloneElement(\n child as React.ReactElement<StepItemInjectedProps>,\n { __isLast: isLast },\n )\n itemsWithIndex.push(\n <StepIndexContext.Provider key={`item-${index}`} value={index + 1}>\n {cloned}\n </StepIndexContext.Provider>,\n )\n // Horizontal connectors are now INSIDE each StepItem (Ant Design pattern),\n // not between items. No interleaving needed.\n })\n\n return (\n <StepsContext.Provider value={ctxValue}>\n <ol\n ref={ref}\n data-orientation={orientation}\n data-size={size}\n className={cn(stepsRootVariants({ orientation }), className)}\n {...props}\n >\n {itemsWithIndex}\n </ol>\n </StepsContext.Provider>\n )\n },\n)\nSteps.displayName = 'Steps'\n\n// ── StepItem ──────────────────────────────────────────────────────────────\n\ninterface StepItemInjectedProps {\n __isLast?: boolean\n}\n\nexport interface StepItemProps\n extends Omit<React.HTMLAttributes<HTMLLIElement>, 'value'>,\n StepItemInjectedProps {\n value: string\n state?: 'error'\n disabled?: boolean\n}\n\nconst stepItemVariants = cva('group/step-item outline-none', {\n variants: {\n orientation: {\n // pb-6 on li provides spacing for next item; connector is absolute within li\n vertical: 'relative flex flex-col',\n // Ant Design pattern:flex-1 等寬(最後一步用 last: 覆蓋成自然寬度)。\n // Connector 在 item 內部(不是 items 之間的獨立元素)。\n horizontal: 'flex-1 min-w-0 last:flex-none last:shrink-0',\n },\n size: {\n sm: 'text-body',\n md: 'text-body',\n lg: 'text-body-lg',\n },\n },\n defaultVariants: { orientation: 'vertical', size: 'md' },\n})\n\n// code-quality-allow: long-function — foundational composite main body — 拆 sub-fn 會複雜化 local state / ref / context binding\nconst StepItem = React.forwardRef<HTMLLIElement, StepItemProps>(\n ({ value, state: stateOverride, disabled = false, children, className, __isLast = false, ...props }, ref) => {\n const steps = useStepsContext()\n const state = computeState(\n value,\n steps.value,\n steps.completedValues,\n steps.errorValues,\n steps.reachableValues,\n steps.linear,\n stateOverride,\n )\n const focused = value === steps.value\n const clickable = isClickable(state, steps.linear, disabled)\n const expanded =\n steps.expansion === 'follow-active' ? focused : steps.expandedSet.has(value)\n\n const activate = React.useCallback(() => {\n if (!clickable) return\n // 永遠更新 focus(value),multiple 模式額外 toggle 展開\n steps.setValue(value)\n if (steps.expansion === 'multiple') {\n steps.toggleExpanded(value)\n }\n }, [clickable, steps, value])\n\n const itemCtx = React.useMemo<StepItemContextValue>(() => ({\n value,\n state,\n focused,\n disabled,\n clickable,\n expanded,\n isLast: __isLast,\n activate,\n }), [value, state, focused, disabled, clickable, expanded, __isLast, activate])\n\n const isVertical = steps.orientation === 'vertical'\n\n return (\n <StepItemContext.Provider value={itemCtx}>\n <li\n ref={ref}\n data-state={state}\n data-focused={focused || undefined}\n data-disabled={disabled || undefined}\n data-clickable={clickable || undefined}\n aria-current={focused ? 'step' : undefined}\n aria-disabled={disabled || undefined}\n className={cn(\n stepItemVariants({ orientation: steps.orientation, size: steps.size }),\n isVertical && !__isLast && 'pb-6',\n !clickable && 'cursor-not-allowed',\n className,\n )}\n {...props}\n >\n <StepItemLayout>{children}</StepItemLayout>\n </li>\n </StepItemContext.Provider>\n )\n },\n)\nStepItem.displayName = 'StepItem'\n\n// ── StepItem internal layout ─────────────────────────────────────────────\n\nfunction StepItemLayout({ children }: { children: React.ReactNode }) {\n const steps = useStepsContext()\n const item = useStepItemContext()\n\n let labelNode: React.ReactNode = null\n let descNode: React.ReactNode = null\n let contentNode: React.ReactNode = null\n React.Children.forEach(children, child => {\n if (!React.isValidElement(child)) return\n if (child.type === StepLabel) labelNode = child\n else if (child.type === StepDescription) descNode = child\n else if (child.type === StepContent) contentNode = child\n })\n\n if (steps.orientation === 'horizontal') {\n return <HorizontalLayout label={labelNode} description={descNode} />\n }\n return (\n <VerticalLayout label={labelNode} description={descNode} content={contentNode} isLast={item.isLast} />\n )\n}\n\n// ── Clickable header ─────────────────────────────────────────────────────\n\n// SR-only 狀態文字 map(2026-06-01 #25 a11y:indicator 是 aria-hidden 純視覺,故「第 N 步/共 M 步/狀態」\n// 需經 sr-only span 給螢幕報讀器。對齊 Carbon ProgressIndicator `--assistive-text`(已完成/進行中/未開始)慣例)\nconst STEP_STATUS_TEXT: Record<StepContentState, string> = {\n completed: '已完成',\n current: '進行中',\n error: '錯誤',\n reachable: '未開始',\n upcoming: '未開始',\n}\n\nfunction StepItemHeader({ children, className, style }: { children: React.ReactNode; className?: string; style?: React.CSSProperties }) {\n const item = useStepItemContext()\n const steps = useStepsContext()\n const index = React.useContext(StepIndexContext)\n const onKeyDown = (e: React.KeyboardEvent<HTMLDivElement>) => {\n if (!item.clickable) return\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n item.activate()\n }\n }\n return (\n <div\n role={item.clickable ? 'button' : undefined}\n tabIndex={item.clickable ? 0 : undefined}\n onClick={item.clickable ? item.activate : undefined}\n onKeyDown={item.clickable ? onKeyDown : undefined}\n aria-disabled={item.disabled || undefined}\n className={cn(\n 'outline-none',\n item.clickable\n ? 'cursor-pointer rounded-md focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring'\n : 'cursor-not-allowed',\n className,\n )}\n style={style}\n >\n <span className=\"sr-only\">{`第 ${index} 步,共 ${steps.total} 步,${STEP_STATUS_TEXT[item.state]}`}</span>\n {children}\n </div>\n )\n}\n\n// ── Vertical layout ──────────────────────────────────────────────────────\n\nfunction VerticalLayout({\n label,\n description,\n content,\n isLast,\n}: {\n label: React.ReactNode\n description: React.ReactNode\n content: React.ReactNode\n isLast: boolean\n}) {\n const steps = useStepsContext()\n const item = useStepItemContext()\n const showContent = !!content && item.expanded\n const indicatorBox = INDICATOR_BOX_WIDTH[steps.size]\n\n return (\n <>\n <StepItemHeader className=\"flex items-start gap-3\">\n {/* Row prefix slot — 消費 item-anatomy <ItemPrefix>(h-[1lh] 對齊 label 第一行 SSOT);\n width = INDICATOR_BOX_WIDTH 固定欄寬,base justify-center 讓 sm dot 在欄內置中 */}\n <ItemPrefix style={{ width: indicatorBox }}>\n <StepIndicator />\n </ItemPrefix>\n <div className=\"flex-1 min-w-0 flex items-start gap-2\">\n <div className=\"flex-1 min-w-0 flex flex-col\">\n {label}\n {description}\n </div>\n {/* Row suffix slot — 消費 item-anatomy <ItemSuffix>(h-[1lh] 對齊 label 第一行);\n text col 是 flex-1 → base ml-auto 惰性,8px 間距由父層 gap-2 提供(= MenuItem 父層 gap idiom)*/}\n {steps.expansion === 'multiple' && !!content && (\n <ItemSuffix aria-hidden>\n <ChevronDown\n size={16}\n className={cn(\n 'text-fg-muted transition-transform duration-150',\n item.expanded && 'rotate-180',\n )}\n />\n </ItemSuffix>\n )}\n </div>\n </StepItemHeader>\n {showContent && (\n <div className=\"flex items-start gap-3 mt-3\">\n <div className=\"shrink-0\" style={{ width: indicatorBox }} />\n <div className=\"flex-1 min-w-0\">{content}</div>\n </div>\n )}\n {!isLast && <VerticalConnectorLine />}\n </>\n )\n}\n\n// ── Vertical connector ───────────────────────────────────────────────────\n\nfunction VerticalConnectorLine() {\n const steps = useStepsContext()\n const item = useStepItemContext()\n const isBlue = item.state === 'completed'\n const radius = INDICATOR_SIZE[steps.size] / 2\n const gap = 8\n\n return (\n <div\n aria-hidden\n className={cn(\n 'absolute w-px',\n isBlue ? 'bg-info' : 'bg-border',\n )}\n style={{\n left: INDICATOR_BOX_WIDTH[steps.size] / 2,\n top: `calc(0.5lh + ${radius}px + ${gap}px)`,\n bottom: `calc(${radius}px - 0.5lh + ${gap}px)`,\n }}\n />\n )\n}\n\n// ── Horizontal layout (Ant Design pattern) ──────────────────────────────\n//\n// Connector 在 **item 內部**(不是 items 之間的獨立元素):\n// Step (flex-1): [indicator][gap][label][gap][──connector──]\n// Last step: [indicator][gap][label] (無 connector)\n//\n// Root: flex-row gap-3 → gap 只在 step items 之間\n// Step items: flex-1 等寬(最後一步 flex-none 自然寬度)\n//\n// 等距保證:\n// label→connector gap = item 內 flex gap-3 = 12px\n// connector→next circle = root gap-3 = 12px\n// 兩邊都是 12px ✓\n//\n// Description 在 step item 內(connector 下方),wrap 到 item 寬度 = 最長到連結線尾段 ✓\n\nfunction HorizontalLayout({\n label,\n description,\n}: {\n label: React.ReactNode\n description: React.ReactNode\n}) {\n const item = useStepItemContext()\n const steps = useStepsContext()\n const isBlue = item.state === 'completed'\n const indicatorBox = INDICATOR_BOX_WIDTH[steps.size]\n\n return (\n <>\n {/* Row 1: indicator + label + connector(在同一個 flex row) */}\n <StepItemHeader className=\"flex items-start gap-3\">\n {/* Row prefix slot — 消費 item-anatomy <ItemPrefix>(h-[1lh] 對齊 label 第一行 SSOT)*/}\n <ItemPrefix>\n <StepIndicator />\n </ItemPrefix>\n <div className=\"shrink-0 min-w-0\">{label}</div>\n {/* Connector 在 item 內部,flex-1 填滿剩餘寬度 */}\n {!item.isLast && (\n <div className=\"h-[1lh] flex-1 flex items-center min-w-4\" aria-hidden>\n <div className={cn('h-px w-full', isBlue ? 'bg-info' : 'bg-border')} />\n </div>\n )}\n </StepItemHeader>\n {/* Row 2: description — 在 item 寬度內 wrap(含 connector 佔的空間) */}\n {description && (\n <div className=\"min-w-0\" style={{ paddingLeft: indicatorBox + 12 }}>\n {description}\n </div>\n )}\n </>\n )\n}\n\n// ── StepIndicator ────────────────────────────────────────────────────────\n\nfunction StepIndicator() {\n const steps = useStepsContext()\n const item = useStepItemContext()\n const { size, linear } = steps\n const { state, focused, disabled } = item\n\n if (size === 'sm') return <SmIndicator state={state} focused={focused} disabled={disabled} linear={linear} />\n return <MdLgIndicator size={size} state={state} focused={focused} disabled={disabled} linear={linear} />\n}\n\n// ── sm indicator: 8px dot in 24px hit area ───────────────────────────────\n\nfunction SmIndicator({\n state,\n focused,\n disabled,\n linear,\n}: {\n state: StepContentState\n focused: boolean\n disabled: boolean\n linear: boolean\n}) {\n // sm current (linear) and reachable: hollow ring\n const isHollow = (state === 'current' && linear) || state === 'reachable'\n\n let dotStyle: React.CSSProperties\n if (isHollow) {\n dotStyle = {\n width: INDICATOR_SIZE.sm,\n height: INDICATOR_SIZE.sm,\n background: 'transparent',\n border: '2px solid var(--info-hover)',\n boxShadow: focused ? getOuterRingShadow(resolveRingColor(state, linear)) : undefined,\n }\n } else {\n const dotBg =\n state === 'completed' ? 'var(--info)'\n : state === 'error' ? 'var(--error)'\n : state === 'current' && !linear ? 'var(--fg-disabled)'\n : 'var(--fg-disabled)' // upcoming + non-linear fallback\n\n dotStyle = {\n width: INDICATOR_SIZE.sm,\n height: INDICATOR_SIZE.sm,\n background: dotBg,\n boxShadow: focused ? getOuterRingShadow(resolveRingColor(state, linear)) : undefined,\n }\n }\n\n return (\n <span\n aria-hidden\n className=\"relative inline-flex items-center justify-center shrink-0\"\n style={{ width: SM_HIT_AREA, height: SM_HIT_AREA }}\n >\n <span\n className={cn('block rounded-full', disabled && 'opacity-disabled')}\n style={dotStyle}\n />\n </span>\n )\n}\n\n// ── md/lg indicator: filled circle with number/icon ──────────────────────\n\nfunction MdLgIndicator({\n size,\n state,\n focused,\n disabled,\n linear,\n}: {\n size: StepsSize\n state: StepContentState\n focused: boolean\n disabled: boolean\n linear: boolean\n}) {\n const diameter = INDICATOR_SIZE[size]\n const iconPx = INDICATOR_ICON_SIZE[size]\n\n let fillBg: string\n let contentColor: string\n\n switch (state) {\n case 'error':\n fillBg = 'var(--error)'\n contentColor = 'var(--on-emphasis)'\n break\n case 'completed':\n fillBg = 'var(--info)'\n contentColor = 'var(--on-emphasis)'\n break\n case 'current':\n if (linear) {\n fillBg = 'var(--info)'\n contentColor = 'var(--on-emphasis)'\n } else {\n fillBg = 'var(--secondary)'\n contentColor = 'var(--foreground)'\n }\n break\n case 'reachable':\n fillBg = 'var(--info)'\n contentColor = 'var(--on-emphasis)'\n break\n default: // upcoming\n if (linear) {\n fillBg = 'var(--muted)'\n contentColor = 'var(--fg-disabled)'\n } else {\n fillBg = 'var(--secondary)'\n contentColor = 'var(--foreground)'\n }\n break\n }\n\n return (\n <span\n aria-hidden\n className={cn(\n 'relative inline-flex items-center justify-center shrink-0 rounded-full',\n 'font-medium leading-none transition-colors',\n disabled && 'opacity-disabled',\n )}\n style={{\n width: diameter,\n height: diameter,\n background: fillBg,\n color: contentColor,\n // 2026-06-11 R2:對齊 spec canonical「indicator 數字與 label 同級」(steps.spec.md 狀態表 md=14/lg=16;spec 明文「之前寫小一號(md=12,lg=14)是錯的」)\n fontSize: size === 'lg' ? 'var(--font-body-lg-size)' : 'var(--font-body-size)',\n boxShadow: focused ? getOuterRingShadow(resolveRingColor(state, linear)) : undefined,\n }}\n >\n <IndicatorContent state={state} iconPx={iconPx} />\n </span>\n )\n}\n\nfunction IndicatorContent({ state, iconPx }: { state: StepContentState; iconPx: number }) {\n if (state === 'completed') return <Check size={iconPx} strokeWidth={2.5} />\n if (state === 'error') return <X size={iconPx} strokeWidth={2.5} />\n return <StepNumber />\n}\n\nfunction StepNumber() {\n const index = React.useContext(StepIndexContext)\n return <span>{index}</span>\n}\n\n// ── StepLabel ────────────────────────────────────────────────────────────\n\nexport interface StepLabelProps extends React.HTMLAttributes<HTMLSpanElement> {}\n\n// code-quality-allow: long-function — foundational composite main body — 拆 sub-fn 會複雜化 local state / ref / context binding\nconst StepLabel = React.forwardRef<HTMLSpanElement, StepLabelProps>(\n ({ className, children, ...props }, ref) => {\n const { size } = useStepsContext()\n const { state, focused, disabled } = useStepItemContext()\n\n return (\n <span\n ref={ref}\n className={cn(\n 'font-medium break-words',\n size === 'lg' ? 'text-body-lg' : 'text-body',\n disabled\n ? 'text-fg-disabled'\n : state === 'error'\n ? 'text-error-text'\n : focused\n ? 'text-foreground'\n : 'text-fg-secondary',\n className,\n )}\n {...props}\n >\n {children}\n </span>\n )\n },\n)\nStepLabel.displayName = 'StepLabel'\n\n// ── StepDescription ──────────────────────────────────────────────────────\n\nexport interface StepDescriptionProps extends React.HTMLAttributes<HTMLSpanElement> {}\n\nconst StepDescription = React.forwardRef<HTMLSpanElement, StepDescriptionProps>(\n ({ className, children, style, ...props }, ref) => {\n const { size } = useStepsContext()\n const { disabled } = useStepItemContext()\n\n return (\n <span\n ref={ref}\n className={cn(\n // Steps 跟 MenuItem 同 scanning-family:sm/md = scanning(body+caption),lg = scanning-lg(body-lg+body-compact)\n size === 'lg'\n ? 'mt-[var(--item-gap-label-desc-scanning-lg)]'\n : 'mt-[var(--item-gap-label-desc-scanning)]',\n 'leading-compact break-words',\n disabled ? 'text-fg-disabled' : 'text-fg-secondary',\n className,\n )}\n style={{\n fontSize: size === 'lg' ? 'var(--font-body-size)' : 'var(--font-caption-size)',\n ...style,\n }}\n {...props}\n >\n {children}\n </span>\n )\n },\n)\nStepDescription.displayName = 'StepDescription'\n\n// ── StepContent ──────────────────────────────────────────────────────────\n\nexport interface StepContentProps extends React.HTMLAttributes<HTMLDivElement> {}\n\nconst StepContent = React.forwardRef<HTMLDivElement, StepContentProps>(\n ({ className, children, ...props }, ref) => {\n const { orientation } = useStepsContext()\n if (orientation === 'horizontal') return null\n return (\n <div\n ref={ref}\n className={cn('text-body text-foreground min-w-0', className)}\n {...props}\n >\n {children}\n </div>\n )\n },\n)\nStepContent.displayName = 'StepContent'\n\n// ── Exports ──────────────────────────────────────────────────────────────\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 stepsMeta = {\n component: 'Steps',\n family: 2,\n variants: {},\n sizes: {\n sm: { px: 8, when: 'Sidebar / 緊湊 onboarding;indicator 8px dot' },\n md: { px: 24, when: '預設 — wizard / checkout / 註冊主流程;indicator 24px circle' },\n lg: { px: 32, when: 'Marketing 流程展示 / 重要 onboarding;indicator 32px circle' },\n },\n states: ['upcoming', 'reachable', 'current', 'completed', 'error'], // 2026-06-11 R2:content-state 模型(spec 狀態表),非 Phase-1 boilerplate 互動 states,\n tokens: {\n bg: ['bg-info'],\n fg: ['--fg-disabled', '--foreground', '--on-emphasis', 'text-error-text', 'text-fg-disabled', 'text-fg-muted', 'text-fg-secondary', 'text-foreground'],\n ring: [],\n },\n} as const\n\nexport { Steps, StepItem, StepLabel, StepDescription, StepContent, stepsRootVariants, stepItemVariants }\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"steps.js","sources":["../../../src/components/Steps/steps.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.\n// code-quality-allow: file-size — foundational composite(Steps + StepItem + orientation/state/connector 邏輯緊密耦合,拆檔會讓 props drilling 複雜化超過可讀 gain)\nimport * as React from 'react'\nimport { Check, ChevronDown, X } from 'lucide-react'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { cn } from '@/lib/utils'\nimport { ItemPrefix, ItemSuffix } from '@/design-system/patterns/element-anatomy/item-anatomy'\n\n// ── Types ─────────────────────────────────────────────────────────────────\n\nexport type StepsSize = 'sm' | 'md' | 'lg'\n// code-quality-allow: dead-export — public API surface — consumer-exposed for future use\nexport type StepsOrientation = 'vertical' | 'horizontal'\nexport type StepsExpansion = 'follow-active' | 'multiple'\nexport type StepContentState = 'upcoming' | 'reachable' | 'current' | 'completed' | 'error'\n\n// ── Constants ─────────────────────────────────────────────────────────────\n\nconst INDICATOR_SIZE: Record<StepsSize, number> = {\n sm: 8,\n md: 24,\n lg: 32,\n}\n\nconst INDICATOR_ICON_SIZE: Record<StepsSize, number> = {\n sm: 0,\n md: 16,\n lg: 20,\n}\n\nconst SM_HIT_AREA = 24\n\nconst INDICATOR_BOX_WIDTH: Record<StepsSize, number> = {\n sm: SM_HIT_AREA,\n md: INDICATOR_SIZE.md,\n lg: INDICATOR_SIZE.lg,\n}\n\n// ── Outer ring (box-shadow, zero layout impact) ───────────────────────────\n\nconst RING_GAP_PX = 2\nconst RING_WIDTH_PX = 2\n\nfunction getOuterRingShadow(ringColor: string): string {\n return `0 0 0 ${RING_GAP_PX}px var(--surface), 0 0 0 ${RING_GAP_PX + RING_WIDTH_PX}px ${ringColor}`\n}\n\nfunction resolveRingColor(state: StepContentState, linear: boolean): string {\n if (state === 'error') return 'var(--error-hover)'\n if (state === 'current' && !linear) return 'var(--border-hover)'\n return 'var(--info-hover)'\n}\n\n// ── Contexts ──────────────────────────────────────────────────────────────\n\ninterface StepsContextValue {\n value: string | undefined\n completedValues: Set<string>\n errorValues: Set<string>\n reachableValues: Set<string>\n linear: boolean\n size: StepsSize\n orientation: StepsOrientation\n expansion: StepsExpansion\n expandedSet: Set<string>\n setValue: (value: string) => void\n toggleExpanded: (value: string) => void\n total: number\n}\n\nconst StepsContext = React.createContext<StepsContextValue | null>(null)\n\nfunction useStepsContext(): StepsContextValue {\n const ctx = React.useContext(StepsContext)\n if (!ctx) throw new Error('Steps compound components must be rendered inside <Steps>')\n return ctx\n}\n\ninterface StepItemContextValue {\n value: string\n state: StepContentState\n focused: boolean\n disabled: boolean\n clickable: boolean\n expanded: boolean\n isLast: boolean\n activate: () => void\n}\n\nconst StepItemContext = React.createContext<StepItemContextValue | null>(null)\n\nfunction useStepItemContext(): StepItemContextValue {\n const ctx = React.useContext(StepItemContext)\n if (!ctx) throw new Error('StepLabel / StepDescription / StepContent must be inside <StepItem>')\n return ctx\n}\n\nconst StepIndexContext = React.createContext<number>(0)\n\n// ── Pure helpers ──────────────────────────────────────────────────────────\n\nfunction computeState(\n itemValue: string,\n value: string | undefined,\n completedValues: Set<string>,\n errorValues: Set<string>,\n reachableValues: Set<string>,\n linear: boolean,\n override: StepContentState | undefined,\n): StepContentState {\n if (override) return override\n if (errorValues.has(itemValue)) return 'error'\n if (completedValues.has(itemValue)) return 'completed'\n if (itemValue === value) return 'current'\n if (linear && reachableValues.has(itemValue)) return 'reachable'\n return 'upcoming'\n}\n\nfunction isClickable(\n state: StepContentState,\n linear: boolean,\n disabled: boolean,\n): boolean {\n if (disabled) return false\n if (!linear) return true\n return state !== 'upcoming'\n}\n\nfunction normalizeExpanded(\n defaultExpanded: 'all' | 'none' | string[] | undefined,\n allValues: string[],\n): Set<string> {\n if (defaultExpanded === 'all') return new Set(allValues)\n if (!defaultExpanded || defaultExpanded === 'none') return new Set()\n return new Set(defaultExpanded)\n}\n\nfunction computeReachableValues(\n childValues: string[],\n completedValues: string[],\n): Set<string> {\n const completed = new Set(completedValues)\n const reachable = new Set(completed)\n for (const v of childValues) {\n if (!completed.has(v)) {\n reachable.add(v)\n break\n }\n }\n return reachable\n}\n\n// ── Steps root ────────────────────────────────────────────────────────────\n\nconst stepsRootVariants = cva('list-none p-0 m-0', {\n variants: {\n orientation: {\n vertical: 'flex flex-col',\n horizontal: 'flex flex-row items-start gap-3',\n },\n },\n defaultVariants: { orientation: 'vertical' },\n})\n\nexport interface StepsProps\n extends Omit<React.HTMLAttributes<HTMLOListElement>, 'onChange' | 'defaultValue'>,\n VariantProps<typeof stepsRootVariants> {\n value?: string\n defaultValue?: string\n onValueChange?: (value: string) => void\n completedValues?: string[]\n errorValues?: string[]\n linear?: boolean\n size?: StepsSize\n orientation?: StepsOrientation\n expansion?: StepsExpansion\n defaultExpanded?: 'all' | 'none' | string[]\n}\n\n// code-quality-allow: long-function — foundational composite main body — 拆 sub-fn 會複雜化 local state / ref / context binding\nconst Steps = React.forwardRef<HTMLOListElement, StepsProps>(\n (\n {\n value: valueProp,\n defaultValue,\n onValueChange,\n completedValues = [],\n errorValues = [],\n linear = true,\n size = 'md',\n orientation = 'vertical',\n expansion = 'follow-active',\n defaultExpanded,\n className,\n children,\n ...props\n },\n ref,\n ) => {\n const [internalValue, setInternalValue] = React.useState<string | undefined>(defaultValue)\n const isControlled = valueProp !== undefined\n const value = isControlled ? valueProp : internalValue\n\n const setValue = React.useCallback(\n (next: string) => {\n if (!isControlled) setInternalValue(next)\n onValueChange?.(next)\n },\n [isControlled, onValueChange],\n )\n\n const childValues = React.useMemo(() => {\n const vals: string[] = []\n React.Children.forEach(children, child => {\n if (\n React.isValidElement(child) &&\n typeof child.props === 'object' &&\n child.props &&\n 'value' in child.props\n ) {\n vals.push(String((child.props as { value: string }).value))\n }\n })\n return vals\n }, [children])\n\n const reachableValues = React.useMemo(\n () => computeReachableValues(childValues, completedValues),\n [childValues, completedValues],\n )\n\n const [expandedSet, setExpandedSet] = React.useState<Set<string>>(() =>\n normalizeExpanded(defaultExpanded, childValues),\n )\n\n const toggleExpanded = React.useCallback((itemValue: string) => {\n setExpandedSet(prev => {\n const next = new Set(prev)\n if (next.has(itemValue)) next.delete(itemValue)\n else next.add(itemValue)\n return next\n })\n }, [])\n\n const stepCount = React.Children.count(children)\n\n const ctxValue = React.useMemo<StepsContextValue>(\n () => ({\n value,\n completedValues: new Set(completedValues),\n errorValues: new Set(errorValues),\n reachableValues,\n linear,\n size,\n orientation,\n expansion,\n expandedSet,\n setValue,\n toggleExpanded,\n total: stepCount,\n }),\n [value, completedValues, errorValues, reachableValues, linear, size, orientation, expansion, expandedSet, setValue, toggleExpanded, stepCount],\n )\n\n // Interleave horizontal connectors between items\n const count = stepCount\n const itemsWithIndex: React.ReactNode[] = []\n\n React.Children.forEach(children, (child, index) => {\n if (!React.isValidElement(child)) {\n itemsWithIndex.push(child)\n return\n }\n const isLast = index === count - 1\n const cloned = React.cloneElement(\n child as React.ReactElement<StepItemInjectedProps>,\n { __isLast: isLast },\n )\n itemsWithIndex.push(\n <StepIndexContext.Provider key={`item-${index}`} value={index + 1}>\n {cloned}\n </StepIndexContext.Provider>,\n )\n // Horizontal connectors are now INSIDE each StepItem (Ant Design pattern),\n // not between items. No interleaving needed.\n })\n\n return (\n <StepsContext.Provider value={ctxValue}>\n <ol\n ref={ref}\n data-orientation={orientation}\n data-size={size}\n className={cn(stepsRootVariants({ orientation }), className)}\n {...props}\n >\n {itemsWithIndex}\n </ol>\n </StepsContext.Provider>\n )\n },\n)\nSteps.displayName = 'Steps'\n\n// ── StepItem ──────────────────────────────────────────────────────────────\n\ninterface StepItemInjectedProps {\n __isLast?: boolean\n}\n\nexport interface StepItemProps\n extends Omit<React.HTMLAttributes<HTMLLIElement>, 'value'>,\n StepItemInjectedProps {\n value: string\n state?: 'error'\n disabled?: boolean\n}\n\nconst stepItemVariants = cva('group/step-item outline-none', {\n variants: {\n orientation: {\n // pb-6 on li provides spacing for next item; connector is absolute within li\n vertical: 'relative flex flex-col',\n // Ant Design pattern:flex-1 等寬(最後一步用 last: 覆蓋成自然寬度)。\n // Connector 在 item 內部(不是 items 之間的獨立元素)。\n horizontal: 'flex-1 min-w-0 last:flex-none last:shrink-0',\n },\n size: {\n sm: 'text-body',\n md: 'text-body',\n lg: 'text-body-lg',\n },\n },\n defaultVariants: { orientation: 'vertical', size: 'md' },\n})\n\n// code-quality-allow: long-function — foundational composite main body — 拆 sub-fn 會複雜化 local state / ref / context binding\nconst StepItem = React.forwardRef<HTMLLIElement, StepItemProps>(\n ({ value, state: stateOverride, disabled = false, children, className, __isLast = false, ...props }, ref) => {\n const steps = useStepsContext()\n const state = computeState(\n value,\n steps.value,\n steps.completedValues,\n steps.errorValues,\n steps.reachableValues,\n steps.linear,\n stateOverride,\n )\n const focused = value === steps.value\n const clickable = isClickable(state, steps.linear, disabled)\n const expanded =\n steps.expansion === 'follow-active' ? focused : steps.expandedSet.has(value)\n\n const activate = React.useCallback(() => {\n if (!clickable) return\n // 永遠更新 focus(value),multiple 模式額外 toggle 展開\n steps.setValue(value)\n if (steps.expansion === 'multiple') {\n steps.toggleExpanded(value)\n }\n }, [clickable, steps, value])\n\n const itemCtx = React.useMemo<StepItemContextValue>(() => ({\n value,\n state,\n focused,\n disabled,\n clickable,\n expanded,\n isLast: __isLast,\n activate,\n }), [value, state, focused, disabled, clickable, expanded, __isLast, activate])\n\n const isVertical = steps.orientation === 'vertical'\n\n return (\n <StepItemContext.Provider value={itemCtx}>\n <li\n ref={ref}\n data-state={state}\n data-focused={focused || undefined}\n data-disabled={disabled || undefined}\n data-clickable={clickable || undefined}\n aria-current={focused ? 'step' : undefined}\n aria-disabled={disabled || undefined}\n className={cn(\n stepItemVariants({ orientation: steps.orientation, size: steps.size }),\n isVertical && !__isLast && 'pb-6',\n !clickable && 'cursor-not-allowed',\n className,\n )}\n {...props}\n >\n <StepItemLayout>{children}</StepItemLayout>\n </li>\n </StepItemContext.Provider>\n )\n },\n)\nStepItem.displayName = 'StepItem'\n\n// ── StepItem internal layout ─────────────────────────────────────────────\n\nfunction StepItemLayout({ children }: { children: React.ReactNode }) {\n const steps = useStepsContext()\n const item = useStepItemContext()\n\n let labelNode: React.ReactNode = null\n let descNode: React.ReactNode = null\n let contentNode: React.ReactNode = null\n React.Children.forEach(children, child => {\n if (!React.isValidElement(child)) return\n if (child.type === StepLabel) labelNode = child\n else if (child.type === StepDescription) descNode = child\n else if (child.type === StepContent) contentNode = child\n })\n\n if (steps.orientation === 'horizontal') {\n return <HorizontalLayout label={labelNode} description={descNode} />\n }\n return (\n <VerticalLayout label={labelNode} description={descNode} content={contentNode} isLast={item.isLast} />\n )\n}\n\n// ── Clickable header ─────────────────────────────────────────────────────\n\n// SR-only 狀態文字 map(2026-06-01 #25 a11y:indicator 是 aria-hidden 純視覺,故「第 N 步/共 M 步/狀態」\n// 需經 sr-only span 給螢幕報讀器。對齊 Carbon ProgressIndicator `--assistive-text`(已完成/進行中/未開始)慣例)\nconst STEP_STATUS_TEXT: Record<StepContentState, string> = {\n completed: '已完成',\n current: '進行中',\n error: '錯誤',\n reachable: '未開始',\n upcoming: '未開始',\n}\n\nfunction StepItemHeader({ children, className, style }: { children: React.ReactNode; className?: string; style?: React.CSSProperties }) {\n const item = useStepItemContext()\n const steps = useStepsContext()\n const index = React.useContext(StepIndexContext)\n const onKeyDown = (e: React.KeyboardEvent<HTMLDivElement>) => {\n if (!item.clickable) return\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n item.activate()\n }\n }\n return (\n <div\n role={item.clickable ? 'button' : undefined}\n tabIndex={item.clickable ? 0 : undefined}\n onClick={item.clickable ? item.activate : undefined}\n onKeyDown={item.clickable ? onKeyDown : undefined}\n aria-disabled={item.disabled || undefined}\n className={cn(\n // leading-compact:scanning-family header 行高 = 1.3(item-anatomy.spec.md:776 掃描模式 label 行高)。\n // 設在 header 而非 li 根 → prefix h-[1lh] + 水平 connector h-[1lh] + label(StepLabel 亦 leading-compact)\n // 全用 1.3 對齊;li 根 text-body(1.5,steps.tsx:329-331)留給展開 content 的 reading 行高,不被\n // scanning 波及(避免 改A壞B)。對齊 MenuItem 把 leading-compact 放 row 容器之原則(item-anatomy.tsx:144-146)。\n 'outline-none leading-compact',\n item.clickable\n ? 'cursor-pointer rounded-md focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring'\n : 'cursor-not-allowed',\n className,\n )}\n style={style}\n >\n <span className=\"sr-only\">{`第 ${index} 步,共 ${steps.total} 步,${STEP_STATUS_TEXT[item.state]}`}</span>\n {children}\n </div>\n )\n}\n\n// ── Vertical layout ──────────────────────────────────────────────────────\n\nfunction VerticalLayout({\n label,\n description,\n content,\n isLast,\n}: {\n label: React.ReactNode\n description: React.ReactNode\n content: React.ReactNode\n isLast: boolean\n}) {\n const steps = useStepsContext()\n const item = useStepItemContext()\n const showContent = !!content && item.expanded\n const indicatorBox = INDICATOR_BOX_WIDTH[steps.size]\n\n return (\n <>\n <StepItemHeader className=\"flex items-start gap-3\">\n {/* Row prefix slot — 消費 item-anatomy <ItemPrefix>(h-[1lh] 對齊 label 第一行 SSOT);\n width = INDICATOR_BOX_WIDTH 固定欄寬,base justify-center 讓 sm dot 在欄內置中 */}\n <ItemPrefix style={{ width: indicatorBox }}>\n <StepIndicator />\n </ItemPrefix>\n <div className=\"flex-1 min-w-0 flex items-start gap-2\">\n <div className=\"flex-1 min-w-0 flex flex-col\">\n {label}\n {description}\n </div>\n {/* Row suffix slot — 消費 item-anatomy <ItemSuffix>(h-[1lh] 對齊 label 第一行);\n text col 是 flex-1 → base ml-auto 惰性,8px 間距由父層 gap-2 提供(= MenuItem 父層 gap idiom)*/}\n {steps.expansion === 'multiple' && !!content && (\n <ItemSuffix aria-hidden>\n <ChevronDown\n size={16}\n className={cn(\n 'text-fg-muted transition-transform duration-150',\n item.expanded && 'rotate-180',\n )}\n />\n </ItemSuffix>\n )}\n </div>\n </StepItemHeader>\n {showContent && (\n <div className=\"flex items-start gap-3 mt-3\">\n <div className=\"shrink-0\" style={{ width: indicatorBox }} />\n <div className=\"flex-1 min-w-0\">{content}</div>\n </div>\n )}\n {!isLast && <VerticalConnectorLine />}\n </>\n )\n}\n\n// ── Vertical connector ───────────────────────────────────────────────────\n\nfunction VerticalConnectorLine() {\n const steps = useStepsContext()\n const item = useStepItemContext()\n const isBlue = item.state === 'completed'\n const radius = INDICATOR_SIZE[steps.size] / 2\n const gap = 8\n\n return (\n <div\n aria-hidden\n className={cn(\n // leading-compact:connector 的 0.5lh 須跟 scanning label 同行高(1.3)→ 起點對齊 circle 中心\n // (circle 對齊 label 第一行;label 已 leading-compact)。否則 connector 繼承 li 根 1.5 → 0.5lh 偏大 → 起點偏低。\n 'absolute w-px leading-compact',\n isBlue ? 'bg-info' : 'bg-border',\n )}\n style={{\n left: INDICATOR_BOX_WIDTH[steps.size] / 2,\n top: `calc(0.5lh + ${radius}px + ${gap}px)`,\n bottom: `calc(${radius}px - 0.5lh + ${gap}px)`,\n }}\n />\n )\n}\n\n// ── Horizontal layout (Ant Design pattern) ──────────────────────────────\n//\n// Connector 在 **item 內部**(不是 items 之間的獨立元素):\n// Step (flex-1): [indicator][gap][label][gap][──connector──]\n// Last step: [indicator][gap][label] (無 connector)\n//\n// Root: flex-row gap-3 → gap 只在 step items 之間\n// Step items: flex-1 等寬(最後一步 flex-none 自然寬度)\n//\n// 等距保證:\n// label→connector gap = item 內 flex gap-3 = 12px\n// connector→next circle = root gap-3 = 12px\n// 兩邊都是 12px ✓\n//\n// Description 在 step item 內(connector 下方),wrap 到 item 寬度 = 最長到連結線尾段 ✓\n\nfunction HorizontalLayout({\n label,\n description,\n}: {\n label: React.ReactNode\n description: React.ReactNode\n}) {\n const item = useStepItemContext()\n const steps = useStepsContext()\n const isBlue = item.state === 'completed'\n const indicatorBox = INDICATOR_BOX_WIDTH[steps.size]\n\n return (\n <>\n {/* Row 1: indicator + label + connector(在同一個 flex row) */}\n <StepItemHeader className=\"flex items-start gap-3\">\n {/* Row prefix slot — 消費 item-anatomy <ItemPrefix>(h-[1lh] 對齊 label 第一行 SSOT)*/}\n <ItemPrefix>\n <StepIndicator />\n </ItemPrefix>\n <div className=\"shrink-0 min-w-0\">{label}</div>\n {/* Connector 在 item 內部,flex-1 填滿剩餘寬度 */}\n {!item.isLast && (\n <div className=\"h-[1lh] flex-1 flex items-center min-w-4\" aria-hidden>\n <div className={cn('h-px w-full', isBlue ? 'bg-info' : 'bg-border')} />\n </div>\n )}\n </StepItemHeader>\n {/* Row 2: description — 在 item 寬度內 wrap(含 connector 佔的空間) */}\n {description && (\n <div className=\"min-w-0\" style={{ paddingLeft: indicatorBox + 12 }}>\n {description}\n </div>\n )}\n </>\n )\n}\n\n// ── StepIndicator ────────────────────────────────────────────────────────\n\nfunction StepIndicator() {\n const steps = useStepsContext()\n const item = useStepItemContext()\n const { size, linear } = steps\n const { state, focused, disabled } = item\n\n if (size === 'sm') return <SmIndicator state={state} focused={focused} disabled={disabled} linear={linear} />\n return <MdLgIndicator size={size} state={state} focused={focused} disabled={disabled} linear={linear} />\n}\n\n// ── sm indicator: 8px dot in 24px hit area ───────────────────────────────\n\nfunction SmIndicator({\n state,\n focused,\n disabled,\n linear,\n}: {\n state: StepContentState\n focused: boolean\n disabled: boolean\n linear: boolean\n}) {\n // sm current (linear) and reachable: hollow ring\n const isHollow = (state === 'current' && linear) || state === 'reachable'\n\n let dotStyle: React.CSSProperties\n if (isHollow) {\n dotStyle = {\n width: INDICATOR_SIZE.sm,\n height: INDICATOR_SIZE.sm,\n background: 'transparent',\n border: '2px solid var(--info-hover)',\n boxShadow: focused ? getOuterRingShadow(resolveRingColor(state, linear)) : undefined,\n }\n } else {\n const dotBg =\n state === 'completed' ? 'var(--info)'\n : state === 'error' ? 'var(--error)'\n : state === 'current' && !linear ? 'var(--fg-disabled)'\n : 'var(--fg-disabled)' // upcoming + non-linear fallback\n\n dotStyle = {\n width: INDICATOR_SIZE.sm,\n height: INDICATOR_SIZE.sm,\n background: dotBg,\n boxShadow: focused ? getOuterRingShadow(resolveRingColor(state, linear)) : undefined,\n }\n }\n\n return (\n <span\n aria-hidden\n className=\"relative inline-flex items-center justify-center shrink-0\"\n style={{ width: SM_HIT_AREA, height: SM_HIT_AREA }}\n >\n <span\n className={cn('block rounded-full', disabled && 'opacity-disabled')}\n style={dotStyle}\n />\n </span>\n )\n}\n\n// ── md/lg indicator: filled circle with number/icon ──────────────────────\n\nfunction MdLgIndicator({\n size,\n state,\n focused,\n disabled,\n linear,\n}: {\n size: StepsSize\n state: StepContentState\n focused: boolean\n disabled: boolean\n linear: boolean\n}) {\n const diameter = INDICATOR_SIZE[size]\n const iconPx = INDICATOR_ICON_SIZE[size]\n\n let fillBg: string\n let contentColor: string\n\n switch (state) {\n case 'error':\n fillBg = 'var(--error)'\n contentColor = 'var(--on-emphasis)'\n break\n case 'completed':\n fillBg = 'var(--info)'\n contentColor = 'var(--on-emphasis)'\n break\n case 'current':\n if (linear) {\n fillBg = 'var(--info)'\n contentColor = 'var(--on-emphasis)'\n } else {\n fillBg = 'var(--secondary)'\n contentColor = 'var(--foreground)'\n }\n break\n case 'reachable':\n fillBg = 'var(--info)'\n contentColor = 'var(--on-emphasis)'\n break\n default: // upcoming\n if (linear) {\n fillBg = 'var(--muted)'\n contentColor = 'var(--fg-disabled)'\n } else {\n fillBg = 'var(--secondary)'\n contentColor = 'var(--foreground)'\n }\n break\n }\n\n return (\n <span\n aria-hidden\n className={cn(\n 'relative inline-flex items-center justify-center shrink-0 rounded-full',\n 'font-medium leading-none transition-colors',\n disabled && 'opacity-disabled',\n )}\n style={{\n width: diameter,\n height: diameter,\n background: fillBg,\n color: contentColor,\n // 2026-06-11 R2:對齊 spec canonical「indicator 數字與 label 同級」(steps.spec.md 狀態表 md=14/lg=16;spec 明文「之前寫小一號(md=12,lg=14)是錯的」)\n fontSize: size === 'lg' ? 'var(--font-body-lg-size)' : 'var(--font-body-size)',\n boxShadow: focused ? getOuterRingShadow(resolveRingColor(state, linear)) : undefined,\n }}\n >\n <IndicatorContent state={state} iconPx={iconPx} />\n </span>\n )\n}\n\nfunction IndicatorContent({ state, iconPx }: { state: StepContentState; iconPx: number }) {\n if (state === 'completed') return <Check size={iconPx} strokeWidth={2.5} />\n if (state === 'error') return <X size={iconPx} strokeWidth={2.5} />\n return <StepNumber />\n}\n\nfunction StepNumber() {\n const index = React.useContext(StepIndexContext)\n return <span>{index}</span>\n}\n\n// ── StepLabel ────────────────────────────────────────────────────────────\n\nexport interface StepLabelProps extends React.HTMLAttributes<HTMLSpanElement> {}\n\n// code-quality-allow: long-function — foundational composite main body — 拆 sub-fn 會複雜化 local state / ref / context binding\nconst StepLabel = React.forwardRef<HTMLSpanElement, StepLabelProps>(\n ({ className, children, ...props }, ref) => {\n const { size } = useStepsContext()\n const { state, focused, disabled } = useStepItemContext()\n\n return (\n <span\n ref={ref}\n className={cn(\n // leading-compact:scanning-family label 行高 = 1.3(item-anatomy.spec.md:776);text-body utility\n // 自帶 lh:1.5,須顯式 leading-compact 蓋回 1.3,跟 MenuItem label(實測 14px/18px=1.3)一致。\n 'font-medium break-words leading-compact',\n size === 'lg' ? 'text-body-lg' : 'text-body',\n disabled\n ? 'text-fg-disabled'\n : state === 'error'\n ? 'text-error-text'\n : focused\n ? 'text-foreground'\n : 'text-fg-secondary',\n className,\n )}\n {...props}\n >\n {children}\n </span>\n )\n },\n)\nStepLabel.displayName = 'StepLabel'\n\n// ── StepDescription ──────────────────────────────────────────────────────\n\nexport interface StepDescriptionProps extends React.HTMLAttributes<HTMLSpanElement> {}\n\nconst StepDescription = React.forwardRef<HTMLSpanElement, StepDescriptionProps>(\n ({ className, children, style, ...props }, ref) => {\n const { size } = useStepsContext()\n const { disabled } = useStepItemContext()\n\n return (\n <span\n ref={ref}\n className={cn(\n // Steps 跟 MenuItem 同 scanning-family:sm/md = scanning(body+caption),lg = scanning-lg(body-lg+body-compact)\n size === 'lg'\n ? 'mt-[var(--item-gap-label-desc-scanning-lg)]'\n : 'mt-[var(--item-gap-label-desc-scanning)]',\n 'leading-compact break-words',\n disabled ? 'text-fg-disabled' : 'text-fg-secondary',\n className,\n )}\n style={{\n fontSize: size === 'lg' ? 'var(--font-body-size)' : 'var(--font-caption-size)',\n ...style,\n }}\n {...props}\n >\n {children}\n </span>\n )\n },\n)\nStepDescription.displayName = 'StepDescription'\n\n// ── StepContent ──────────────────────────────────────────────────────────\n\nexport interface StepContentProps extends React.HTMLAttributes<HTMLDivElement> {}\n\nconst StepContent = React.forwardRef<HTMLDivElement, StepContentProps>(\n ({ className, children, ...props }, ref) => {\n const { orientation } = useStepsContext()\n if (orientation === 'horizontal') return null\n return (\n <div\n ref={ref}\n className={cn('text-body text-foreground min-w-0', className)}\n {...props}\n >\n {children}\n </div>\n )\n },\n)\nStepContent.displayName = 'StepContent'\n\n// ── Exports ──────────────────────────────────────────────────────────────\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 stepsMeta = {\n component: 'Steps',\n family: 2,\n variants: {},\n sizes: {\n sm: { px: 8, when: 'Sidebar / 緊湊 onboarding;indicator 8px dot' },\n md: { px: 24, when: '預設 — wizard / checkout / 註冊主流程;indicator 24px circle' },\n lg: { px: 32, when: 'Marketing 流程展示 / 重要 onboarding;indicator 32px circle' },\n },\n states: ['upcoming', 'reachable', 'current', 'completed', 'error'], // 2026-06-11 R2:content-state 模型(spec 狀態表),非 Phase-1 boilerplate 互動 states,\n tokens: {\n bg: ['bg-info'],\n fg: ['--fg-disabled', '--foreground', '--on-emphasis', 'text-error-text', 'text-fg-disabled', 'text-fg-muted', 'text-fg-secondary', 'text-foreground'],\n ring: [],\n },\n} as const\n\nexport { Steps, StepItem, StepLabel, StepDescription, StepContent, stepsRootVariants, stepItemVariants }\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,112 @@
1
+ {
2
+ "_purpose": "sha256 of every shipped fork governance body + manifest (tamper-detect baseline)",
3
+ "entries": [
4
+ {
5
+ "file": "hooks/block_prototype_imports.py",
6
+ "sha256": "0ab679ddb522f508c490891711559175a912be8b7f4db04d8a55cdac983fd482",
7
+ "sourceHook": "block_prototype_imports.py",
8
+ "bucket": "SHIP_AS_IS"
9
+ },
10
+ {
11
+ "file": "hooks/check_chrome_header_avatar_canonical.sh",
12
+ "sha256": "ffa91559c19d3f2aab50c69c4b247c15a29376d10b116f6223afb3289b4f91a2",
13
+ "sourceHook": "check_chrome_header_avatar_canonical.sh",
14
+ "bucket": "SHIP_AS_IS"
15
+ },
16
+ {
17
+ "file": "hooks/check_consumer_app_invariants.sh",
18
+ "sha256": "e2d63b142759bf791ca3c4462342d91623827aeb54c15398c94853485684900b",
19
+ "sourceHook": "check_consumer_app_invariants.sh",
20
+ "bucket": "SHIP_AS_IS"
21
+ },
22
+ {
23
+ "file": "hooks/check_ds_anchor_preflight.sh",
24
+ "sha256": "15fb44c8b35042efd03e1992f8b5b7b121a7633cebe556d4ca0a1a7f5483dc35",
25
+ "sourceHook": "check_ds_anchor_preflight.sh",
26
+ "bucket": "SHIP_REWRITTEN"
27
+ },
28
+ {
29
+ "file": "hooks/check_escape_marker_abuse.sh",
30
+ "sha256": "4f9d8dc91275145204f0bc760c4378dd53f7ad4389d89da737aef23f84b2502b",
31
+ "sourceHook": "check_escape_marker_abuse.sh",
32
+ "bucket": "SHIP_REWRITTEN"
33
+ },
34
+ {
35
+ "file": "hooks/check_field_family_invariants.sh",
36
+ "sha256": "1beeb2b347cacf5d8a912470bce0b9ab6b54c2595873155389456cdbe6125d80",
37
+ "sourceHook": "check_field_family_invariants.sh",
38
+ "bucket": "SHIP_AS_IS"
39
+ },
40
+ {
41
+ "file": "hooks/check_fork_product_quality.sh",
42
+ "sha256": "1985d7607de85ae71b07b4b302c27b3dbb51670bbe68421489e27c75a2b64ffa",
43
+ "sourceHook": "check_substantive_edit_approval_preflight.sh",
44
+ "bucket": "REPLACE"
45
+ },
46
+ {
47
+ "file": "hooks/check_item_list_gap.sh",
48
+ "sha256": "4e779e5894f16873f1bc322f64571a7ff869d3b75ed5383a5b0f662c7b533d99",
49
+ "sourceHook": "check_item_list_gap.sh",
50
+ "bucket": "SHIP_AS_IS"
51
+ },
52
+ {
53
+ "file": "hooks/check_layout_space_magic_numbers.sh",
54
+ "sha256": "09c74c67c61a366b14bb1cce2ac27d4b8d0541a8698f85d50e4afe9783ad7309",
55
+ "sourceHook": "check_layout_space_magic_numbers.sh",
56
+ "bucket": "SHIP_AS_IS"
57
+ },
58
+ {
59
+ "file": "hooks/check_opacity_token_usage.sh",
60
+ "sha256": "1772e83242520f569a9a44e96d08d74e121c119c940c019c8ed50989f14de646",
61
+ "sourceHook": "check_opacity_token_usage.sh",
62
+ "bucket": "SHIP_REWRITTEN"
63
+ },
64
+ {
65
+ "file": "hooks/check_pattern_invariants.sh",
66
+ "sha256": "c6cf3288cbc2bdb689091aef678073470f58b7f1bf98cdefb55afc9724ad277b",
67
+ "sourceHook": "check_pattern_invariants.sh",
68
+ "bucket": "SHIP_AS_IS"
69
+ },
70
+ {
71
+ "file": "hooks/check_sidebar_menu_button_implicit_wrap.sh",
72
+ "sha256": "240807737e9c75bd137a8abd9a7194ffcb4a92b1015f626f14539fd8dbf73ea8",
73
+ "sourceHook": "check_sidebar_menu_button_implicit_wrap.sh",
74
+ "bucket": "SHIP_AS_IS"
75
+ },
76
+ {
77
+ "file": "hooks/check_tailwind_wildcard_in_docs.sh",
78
+ "sha256": "51fcf04d3adc2a15b6c06312753e51412ed8ff88d088a5e8fe4ec0c784c7aa96",
79
+ "sourceHook": "check_tailwind_wildcard_in_docs.sh",
80
+ "bucket": "SHIP_AS_IS"
81
+ },
82
+ {
83
+ "file": "hooks/inject_deploy_url_after_push.sh",
84
+ "sha256": "f5cd8597574f1b061b132a289337731f7dabac0c6666f1ca611d8316504b401c",
85
+ "sourceHook": "inject_deploy_url_after_push.sh",
86
+ "bucket": "SHIP_REWRITTEN"
87
+ },
88
+ {
89
+ "file": "launchers/fork-governance-dispatcher.sh",
90
+ "sha256": "6a99ad2d7404a4d721a611a19e4537ebfe8cf5e2ddba99edc7f6b386d86e8b5d",
91
+ "source": "template/.claude/hooks"
92
+ },
93
+ {
94
+ "file": "launchers/inject_fork_governance_preamble.sh",
95
+ "sha256": "eccf9dbb5ccd3a2e0bea6e3e225de2eb0f1634a6c12c349aab89439cf6e1fb89",
96
+ "source": "template/.claude/hooks"
97
+ },
98
+ {
99
+ "file": "launchers/settings-hooks.json",
100
+ "sha256": "b040779f18032dc382bb83ce8ccac3ebae4c2280976e73f14e3b78e39dc9367b",
101
+ "source": "template/.claude/settings.json"
102
+ },
103
+ {
104
+ "file": "manifest.json",
105
+ "sha256": "ee4f619b722c7d3a4f80dddb52dcee4bf900c7e6923945cd59d290d4a8236e5a"
106
+ },
107
+ {
108
+ "file": "preamble.md",
109
+ "sha256": "940d812f228bd8b09e53baeef8291d581a256c91743f6445b7bc376539304ad2"
110
+ }
111
+ ]
112
+ }
@@ -0,0 +1,111 @@
1
+ #!/usr/bin/env python3
2
+ import json
3
+ import os
4
+ import re
5
+ import sys
6
+ import time
7
+
8
+ # Per-hook fire logging(enables /knowledge-prune D2 dead-hook detection)
9
+ # Resolve project root from this script's location(stable; cwd may be anywhere
10
+ # depending on how Claude Code invokes the hook)to avoid stray .claude/ trees.
11
+ try:
12
+ _project_root = os.environ.get('CLAUDE_PROJECT_DIR') or os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
13
+ _log_dir = os.path.join(_project_root, '.claude', 'logs')
14
+ os.makedirs(_log_dir, exist_ok=True)
15
+ with open(os.path.join(_log_dir, 'hook-fires-per-hook.jsonl'), 'a') as _f:
16
+ _f.write(json.dumps({'ts': time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime()), 'hook': os.path.basename(__file__)}) + '\n')
17
+ except Exception:
18
+ pass
19
+
20
+ EXPLORATION_PREFIX = "src/explorations/"
21
+ SRC_PREFIX = "src/"
22
+
23
+ def load_event():
24
+ try:
25
+ return json.load(sys.stdin)
26
+ except Exception:
27
+ return None
28
+
29
+ def collect_file_paths(tool_input):
30
+ paths = []
31
+
32
+ if not isinstance(tool_input, dict):
33
+ return paths
34
+
35
+ file_path = tool_input.get("file_path")
36
+ if isinstance(file_path, str):
37
+ paths.append(file_path)
38
+
39
+ edits = tool_input.get("edits")
40
+ if isinstance(edits, list):
41
+ for item in edits:
42
+ if isinstance(item, dict):
43
+ p = item.get("file_path")
44
+ if isinstance(p, str):
45
+ paths.append(p)
46
+
47
+ files = tool_input.get("files")
48
+ if isinstance(files, list):
49
+ for item in files:
50
+ if isinstance(item, dict):
51
+ p = item.get("file_path")
52
+ if isinstance(p, str):
53
+ paths.append(p)
54
+
55
+ return list(dict.fromkeys(paths))
56
+
57
+ def should_check(path):
58
+ if not path.startswith(SRC_PREFIX):
59
+ return False
60
+ if path.startswith(EXPLORATION_PREFIX):
61
+ return False
62
+ if not (path.endswith(".ts") or path.endswith(".tsx")):
63
+ return False
64
+ return True
65
+
66
+ def contains_exploration_import(content):
67
+ patterns = [
68
+ r'from\s+[\'"].*src/explorations/.*[\'"]',
69
+ r'from\s+[\'"].*explorations/.*[\'"]',
70
+ r'import\s+[\'"].*src/explorations/.*[\'"]',
71
+ r'import\s+[\'"].*explorations/.*[\'"]'
72
+ ]
73
+ return any(re.search(p, content) for p in patterns)
74
+
75
+ def main():
76
+ event = load_event()
77
+ if not event:
78
+ sys.exit(0)
79
+
80
+ tool_input = event.get("tool_input", {})
81
+ touched_paths = collect_file_paths(tool_input)
82
+
83
+ offenders = []
84
+
85
+ for path in touched_paths:
86
+ if not should_check(path):
87
+ continue
88
+ if not os.path.exists(path):
89
+ continue
90
+
91
+ try:
92
+ with open(path, "r", encoding="utf-8") as f:
93
+ content = f.read()
94
+ except Exception:
95
+ continue
96
+
97
+ if contains_exploration_import(content):
98
+ offenders.append(path)
99
+
100
+ if offenders:
101
+ lines = [
102
+ "Blocked: 正式程式碼不得 import src/explorations/ 內的檔案。"
103
+ ]
104
+ lines.extend(f"- {p}" for p in offenders)
105
+ print("\n".join(lines))
106
+ sys.exit(2)
107
+
108
+ sys.exit(0)
109
+
110
+ if __name__ == "__main__":
111
+ main()
@@ -0,0 +1,95 @@
1
+ #!/bin/bash
2
+ # check_chrome_header_avatar_canonical.sh — PreToolUse Edit/Write 攔 chrome header descendant 用 ItemAvatar(2026-05-27)
3
+ #
4
+ # Per user 2026-05-27 抓 UserFooter vertical stack drift + codex collab Step 4 cite battle:
5
+ # header-canonical.spec.md:57-72 + sidebar.spec.md:241-247 + item-anatomy.spec.md:513-537 明文:
6
+ # 「Chrome header 不是 row context → 必 raw <Avatar size={24}>,禁 <ItemAvatar>(會誤啟動 row anatomy lookup)」
7
+ #
8
+ # Detection:
9
+ # PreToolUse Edit/Write content 偵測 `<SidebarHeader>` block 內含 `<ItemAvatar` → soft BLOCKER inject
10
+ # (允許 SidebarFooter 內 ItemAvatar — footer 是 SidebarMenu row context)
11
+ #
12
+ # Scope:
13
+ # - packages/design-system/src/components/Sidebar/**.tsx + **.stories.tsx
14
+ # - apps/**.tsx (consumer)
15
+ # - node_modules/@qijenchen/design-system/**(禁改 — block_prototype_imports 已攔)
16
+ #
17
+ # 對應 audit dim 預留 — TBD 升 audit dim 65
18
+
19
+ source "$(dirname "$0")/_log-fire.sh" 2>/dev/null && log_hook_fire
20
+
21
+ set -uo pipefail
22
+ INPUT=$(cat 2>/dev/null || echo "{}")
23
+ TOOL=$(echo "$INPUT" | jq -r '.tool_name // ""' 2>/dev/null)
24
+ FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // ""' 2>/dev/null)
25
+ EVENT=$(echo "$INPUT" | jq -r '.hook_event_name // ""' 2>/dev/null)
26
+ NEW=$(echo "$INPUT" | jq -r '.tool_input.content // .tool_input.new_string // ""' 2>/dev/null)
27
+
28
+ [ "$EVENT" != "PreToolUse" ] && exit 0
29
+ case "$TOOL" in Edit|Write|MultiEdit) ;; *) exit 0 ;; esac
30
+ case "$FILE_PATH" in *.tsx) ;; *) exit 0 ;; esac
31
+ case "$FILE_PATH" in *.test.tsx|*.spec.md) exit 0 ;; esac
32
+
33
+ # Multi-line detection:`<SidebarHeader>...<ItemAvatar...>...</SidebarHeader>` block
34
+ # Use python for proper multiline match
35
+ # 2026-06-11 R2 held-item #9:strip 註解再 match — apps/template/src/App.tsx:57 canonical citation
36
+ # 註解({/* ... 禁用 <ItemAvatar> ... */})在 SidebarHeader block 內被當真 JSX 誤發 P0(code 實際正確
37
+ # 用 raw <Avatar size={24}>)。Strip 順序:JSX comment {/* */} → block comment /* */ → 行首 // 整行
38
+ # (不 strip 行內 //,避免 mutilate https:// URL — 對齊 check_story_invariants.sh R9 idiom)。
39
+ HAS_DRIFT=$(printf '%s' "$NEW" | python3 -c '
40
+ import sys, re
41
+ content = sys.stdin.read()
42
+ # Strip comments(citation 註解含 <ItemAvatar> 字樣不是 drift)
43
+ content = re.sub(r"\{/\*.*?\*/\}", "", content, flags=re.DOTALL)
44
+ content = re.sub(r"/\*.*?\*/", "", content, flags=re.DOTALL)
45
+ content = re.sub(r"(?m)^[ \t]*//.*$", "", content)
46
+ # Find SidebarHeader blocks(opening tag → closing tag,non-greedy)
47
+ blocks = re.findall(r"<SidebarHeader[^>]*>.*?</SidebarHeader>", content, re.DOTALL)
48
+ for block in blocks:
49
+ if re.search(r"<ItemAvatar\b", block):
50
+ print("DRIFT")
51
+ sys.exit(0)
52
+ ' 2>/dev/null)
53
+
54
+ [ "$HAS_DRIFT" != "DRIFT" ] && exit 0
55
+
56
+ # Override env var
57
+ if [ "${CLAUDE_BYPASS_CHROME_HEADER_AVATAR:-0}" = "1" ]; then
58
+ mkdir -p "$(dirname "$0")/../logs" 2>/dev/null
59
+ printf '{"ts":"%s","event":"chrome-header-avatar-bypass","file":"%s"}\n' \
60
+ "$(date -u +%Y-%m-%dT%H:%M:%SZ)" "$FILE_PATH" >> "$(dirname "$0")/../logs/governance-bypass.jsonl" 2>/dev/null
61
+ exit 0
62
+ fi
63
+
64
+ REL=${FILE_PATH#"$CLAUDE_PROJECT_DIR"/}
65
+
66
+ cat >&2 <<EOF
67
+ 🚨 Chrome header avatar canonical violation(per user 2026-05-27 抓 + codex collab cite battle):
68
+
69
+ 📁 File: $REL
70
+ 🔍 偵測:<SidebarHeader> block 內含 <ItemAvatar>(禁用)
71
+
72
+ Canonical citation:
73
+ - header-canonical.spec.md:57-72:「Chrome header 不是 row context → 必用 raw <Avatar size={24}>,禁用 <ItemAvatar>(會誤啟動 row anatomy lookup)」
74
+ - sidebar.spec.md:241-247:「consumer 用 raw <Avatar size={24}>(chrome header 不是 row context → 不該用 <ItemAvatar>)」
75
+ - item-anatomy.spec.md:513-537:「ItemAvatar scope = row context only;Chrome header 有自己的 canonical = raw <Avatar size={24}>」
76
+
77
+ 修法(per DS canonical):
78
+ ❌ <SidebarHeader>
79
+ <ItemAvatar alt="..." shape="square" color="..." solid />
80
+ <span>brand</span>
81
+ </SidebarHeader>
82
+
83
+ ✅ <SidebarHeader>
84
+ <Avatar size={24} shape="square" color="..." solid alt="..." />
85
+ <span className="text-body-lg font-medium truncate">brand</span>
86
+ </SidebarHeader>
87
+
88
+ 注意:SidebarFooter 內 ItemAvatar OK(footer 是 SidebarMenu row context)。本 hook 只攔 SidebarHeader。
89
+
90
+ Bypass(極罕見):CLAUDE_BYPASS_CHROME_HEADER_AVATAR=1 env var(audit-logged)。
91
+ EOF
92
+ # 2026-05-31:exit 0 → exit 2(folded-hook-audit:原宣稱 BLOCKER 但 exit 0 = 假 enforcement;
93
+ # chrome-header avatar 是 SSOT canonical [feedback_ssot_mechanical_p0_not_p1 = 必 P0 BLOCK],
94
+ # verified clean on 現有 canonical sidebar code + 有 env escape 兜 false-positive)。
95
+ exit 2