@qijenchen/design-system 0.1.0-beta.6 → 0.1.0-beta.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +154 -0
- package/dist/components/Alert/alert.d.ts +1 -1
- package/dist/components/Breadcrumb/breadcrumb.d.ts +1 -1
- package/dist/components/Breadcrumb/breadcrumb.d.ts.map +1 -1
- package/dist/components/Breadcrumb/breadcrumb.js +16 -21
- package/dist/components/Breadcrumb/breadcrumb.js.map +1 -1
- package/dist/components/Checkbox/checkbox.d.ts +1 -1
- package/dist/components/Combobox/combobox.d.ts +2 -2
- package/dist/components/DatePicker/date-picker.d.ts +2 -2
- package/dist/components/Dialog/dialog.d.ts +1 -1
- package/dist/components/Dialog/dialog.js.map +1 -1
- package/dist/components/DropdownMenu/dropdown-menu.d.ts +2 -2
- package/dist/components/FieldControlGroup/field-control-group.d.ts +1 -1
- package/dist/components/Input/input.d.ts +3 -3
- package/dist/components/LinkInput/link-input.d.ts +2 -2
- package/dist/components/Menu/menu-item.d.ts +2 -2
- package/dist/components/NameCard/name-card.d.ts +1 -1
- package/dist/components/NumberInput/number-input.d.ts +3 -3
- package/dist/components/PeoplePicker/people-picker-helpers.d.ts +1 -1
- package/dist/components/PeoplePicker/people-picker.d.ts +1 -1
- package/dist/components/Popover/popover.js +2 -1
- package/dist/components/Popover/popover.js.map +1 -1
- package/dist/components/RadioGroup/radio-group.d.ts +1 -1
- package/dist/components/Select/select.d.ts +2 -2
- package/dist/components/SelectMenu/select-menu.d.ts +1 -1
- package/dist/components/SelectionControl/selection-item.d.ts +1 -1
- package/dist/components/Sheet/sheet.d.ts +1 -1
- package/dist/components/Sheet/sheet.js.map +1 -1
- package/dist/components/Sidebar/sidebar.d.ts +5 -5
- package/dist/components/Switch/switch.d.ts +1 -1
- package/dist/components/Textarea/textarea.d.ts +1 -1
- package/dist/components/TimePicker/time-picker.d.ts +2 -2
- package/dist/components/TimePicker/time-picker.js.map +1 -1
- package/dist/components/Toast/toast.d.ts +1 -1
- package/dist/components/TreeView/tree-view.d.ts +2 -2
- package/dist/lib/i18n/i18n-context.d.ts +3 -3
- package/dist/patterns/element-anatomy/item-anatomy.d.ts +3 -3
- package/dist/patterns/horizontal-overflow/horizontal-overflow.d.ts +1 -1
- package/dist/tokens/uiSize/icon-size.d.ts +3 -3
- package/package.json +10 -8
- package/src/components/Breadcrumb/breadcrumb.tsx +26 -16
- package/src/components/Dialog/dialog.tsx +4 -4
- package/src/components/Popover/popover.tsx +1 -1
- package/src/components/Sheet/sheet.tsx +1 -1
- package/src/components/TimePicker/time-picker.tsx +4 -4
- /package/dist/{style.css → react-day-picker.css} +0 -0
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { type VariantProps } from 'class-variance-authority';
|
|
3
|
-
import type { FieldMode, FieldVariant } from '
|
|
4
|
-
import type { InlineActionConfig } from '
|
|
5
|
-
import { fieldWrapperStyles } from '
|
|
3
|
+
import type { FieldMode, FieldVariant } from '../../components/Field/field-types';
|
|
4
|
+
import type { InlineActionConfig } from '../../patterns/element-anatomy/item-anatomy';
|
|
5
|
+
import { fieldWrapperStyles } from '../../components/Field/field-wrapper';
|
|
6
6
|
export interface NumberFormatOptions {
|
|
7
7
|
/** 小數位數 */
|
|
8
8
|
precision?: number;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { SelectOption } from '
|
|
1
|
+
import type { SelectOption } from '../../components/Select/select';
|
|
2
2
|
import { type PersonValue } from './person-display';
|
|
3
3
|
export declare const PEOPLE_PICKER_LENGTH1_WRAPPER_CLASS = "flex-1 min-w-0 inline-flex items-center group-data-[row-mode=auto]/cell:items-start";
|
|
4
4
|
export declare function getPeoplePickerTagWrapperClass(selectedCount: number): string;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import type { FieldMode, FieldVariant } from '
|
|
2
|
+
import type { FieldMode, FieldVariant } from '../../components/Field/field-types';
|
|
3
3
|
import { type PersonValue } from './person-display';
|
|
4
4
|
import { PEOPLE_PICKER_LENGTH1_WRAPPER_CLASS, getPeoplePickerTagWrapperClass } from './people-picker-helpers';
|
|
5
5
|
export { PEOPLE_PICKER_LENGTH1_WRAPPER_CLASS, getPeoplePickerTagWrapperClass };
|
|
@@ -60,7 +60,8 @@ const PopoverHeader = React.forwardRef(
|
|
|
60
60
|
...props,
|
|
61
61
|
children: [
|
|
62
62
|
/* @__PURE__ */ jsx("div", { className: "flex-1 min-w-0", children }),
|
|
63
|
-
!hideClose &&
|
|
63
|
+
!hideClose && // Dismiss X = native sm,SurfaceHeader 負 my trick 讓 layout 佔位 24 → 匹配 inner 24
|
|
64
|
+
/* @__PURE__ */ jsx(PopoverPrimitive.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { "data-dismiss": true, iconOnly: true, dismiss: true, size: "sm", startIcon: X, "aria-label": "關閉" }) })
|
|
64
65
|
]
|
|
65
66
|
}
|
|
66
67
|
)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"popover.js","sources":["../../../src/components/Popover/popover.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 PopoverPrimitive from \"@radix-ui/react-popover\"\nimport { X as XIcon } from \"lucide-react\"\n\nimport { cn } from \"@/lib/utils\"\nimport { SurfaceHeader, SurfaceBody, SurfaceFooter } from \"@/design-system/patterns/overlay-surface/overlay-surface\"\nimport { Button } from \"@/design-system/components/Button/button\"\nimport { OVERLAY_SIDE_OFFSET, OVERLAY_COLLISION_PADDING } from \"@/design-system/tokens/elevation/overlay-geometry\"\n\n/**\n * Popover — Radix Popover + 設計系統 token\n *\n * ── 視覺 ──\n * 與 Dialog 對齊:bg-surface-raised / rounded-lg / border-border / elevation-200。\n * density 永遠鎖 md(non-modal 輕量浮層不隨頁面 density 放大)。\n *\n * ── 結構 ──\n * PopoverContent:外殼(bg / border / radius / shadow / density),無內距。\n * PopoverHeader / PopoverBody / PopoverFooter:消費 overlay-surface pattern\n * 共用的 SurfaceHeader / SurfaceBody / SurfaceFooter primitives(padding SSOT)。\n *\n * ── Header dismiss X(2026-04-20 決策) ──\n * 所有 PopoverHeader 一律附右上 X 按鈕(對齊 Dialog 的 canonical)。Popover 雖是\n * non-modal + click-outside-to-close,但有 header 的 Popover 通常結構化程度高\n * (title / 多區塊),明確的「關閉」入口讓使用者更易退出。無 header 的簡單 Popover\n * 不加 X(click-outside / Esc 即可)。\n */\n\nconst Popover = PopoverPrimitive.Root\nconst PopoverTrigger = PopoverPrimitive.Trigger\nconst PopoverAnchor = PopoverPrimitive.Anchor\nconst PopoverClose = PopoverPrimitive.Close\n\n// AutoFocus canonical(對齊 Dialog / Sheet / Material / Polaris)—\n// 開啟時 focus 落在 body 第一個有意義互動元素,避免 focus 到 close X 觸發 tooltip leak\nconst handlePopoverOpenAutoFocus = (e: Event) => {\n e.preventDefault()\n const content = e.currentTarget as HTMLElement\n const firstBodyTarget = content.querySelector<HTMLElement>(\n '[data-popover-body] input:not([disabled]),[data-popover-body] textarea:not([disabled]),[data-popover-body] select:not([disabled]),[data-popover-body] button:not([disabled]):not([data-dismiss]),input:not([disabled]),textarea:not([disabled]),button:not([disabled]):not([data-dismiss])'\n )\n const firstFooterButton = content.querySelector<HTMLElement>(\n '[data-popover-footer] button:not([disabled]):not([data-dismiss])'\n )\n ;(firstBodyTarget ?? firstFooterButton ?? content).focus({ preventScroll: true })\n}\n\nconst PopoverContent = React.forwardRef<\n React.ElementRef<typeof PopoverPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>\n>(({ className, align = \"center\", sideOffset = OVERLAY_SIDE_OFFSET, collisionPadding = OVERLAY_COLLISION_PADDING, onOpenAutoFocus, ...props }, ref) => (\n <PopoverPrimitive.Portal>\n <PopoverPrimitive.Content\n ref={ref}\n align={align}\n sideOffset={sideOffset}\n collisionPadding={collisionPadding}\n data-density=\"md\"\n onOpenAutoFocus={onOpenAutoFocus ?? handlePopoverOpenAutoFocus}\n className={cn(\n \"z-50 w-72 rounded-lg border border-border bg-surface-raised text-foreground shadow-[var(--elevation-200)] outline-none\",\n // 2026-05-04 viewport-aware max-h SSOT(從 NameCard 升 DS-wide):header/footer 永遠 in-viewport,body 壓縮 scroll\n // 2026-05-05 audit dim 35 補:加 `min-h-0` 完成 M25 chain invariant(flex item default min-h: auto 阻 shrink)\n \"max-h-[var(--radix-popover-content-available-height,100vh)] flex flex-col overflow-hidden min-h-0\",\n \"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 motion-reduce:animate-none\",\n \"data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2\",\n \"origin-[var(--radix-popover-content-transform-origin)]\",\n className\n )}\n {...props}\n />\n </PopoverPrimitive.Portal>\n))\nPopoverContent.displayName = PopoverPrimitive.Content.displayName\n\n// PopoverHeader: SurfaceHeader + Close X(對齊 Dialog 的 canonical,見 docblock)\n// justify-between 讓 children 與 Close 分左右。\ninterface PopoverHeaderProps extends React.HTMLAttributes<HTMLDivElement> {\n /**\n * 隱藏右上 close X(預設 false,顯示)。\n * Coachmark / Tour 類 composition 用 Skip / Done 自管 close,不需 X。\n */\n hideClose?: boolean\n}\n\nconst PopoverHeader = React.forwardRef<HTMLDivElement, PopoverHeaderProps>(\n ({ className, children, hideClose = false, ...props }, ref) => (\n // Popover lightweight chrome canonical(2026-05-04 重思 v2):\n // 覆寫 `--chrome-slot-h: 1.25rem` (20px) → unbounded button 佔位縮成 20,**匹配 PopoverTitle\n // text-body line-height (14×1.5≈21,floor 20)**。Header 維持 padding-based 自然撐開:\n // max(21 title, 20 slot) + py-tight(12*2) = 45 → 自然比 Dialog/Sheet 48 輕一級。\n // Q10 穩定:title-only / title+close 都 = title + py 主導,slot 不 dominate。\n // 無 min-h / 無 py override — 修正前一版過度設計。\n <SurfaceHeader\n ref={ref}\n className={cn(\"justify-between [--chrome-slot-h:1.25rem]\", className)}\n {...props}\n >\n <div className=\"flex-1 min-w-0\">{children}</div>\n {!hideClose && (\n <PopoverPrimitive.Close asChild>\n {/* Dismiss X = native sm,SurfaceHeader 負 my trick 讓 layout 佔位 24 → 匹配 inner 24 */}\n <Button data-dismiss iconOnly dismiss size=\"sm\" startIcon={XIcon} aria-label=\"關閉\" />\n </PopoverPrimitive.Close>\n )}\n </SurfaceHeader>\n ),\n)\nPopoverHeader.displayName = \"PopoverHeader\"\n\n// PopoverBody / PopoverFooter: wrap SurfaceBody / SurfaceFooter with data-popover-*\n// attributes so handlePopoverOpenAutoFocus 可正確定位 body 內第一個 interactive 元素\n//\n// ── List-as-region 場景(menu / Cmd+K / nav)──\n// 不再提供 `flush` variant(2026-05-01 移除,對齊 DialogBody / SheetBody canonical)。\n// consumer 用 SurfaceBody className override 撤掉 chrome padding + 自管 list outer wrapper:\n// `<PopoverBody className=\"!px-0 !py-0\"><div className=\"py-2\">{items}</div></PopoverBody>`\n// 或乾脆不用 PopoverBody,直接 PopoverContent > 自管 list 結構(naked popover)。\n// 詳 DialogBody comment + `tokens/layoutSpace/layoutSpace.spec.md`「List-as-region in overlay body」\nconst PopoverBody = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(\n ({ ...props }, ref) => <SurfaceBody ref={ref} data-popover-body {...props} />,\n)\nPopoverBody.displayName = \"PopoverBody\"\n\nconst PopoverFooter = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(\n ({ ...props }, ref) => <SurfaceFooter ref={ref} data-popover-footer {...props} />\n)\nPopoverFooter.displayName = \"PopoverFooter\"\n\n// PopoverTitle(2026-04-22 v4 non-modal canonical):`text-body font-medium`(14px)\n// Rationale:Popover / Coachmark 屬 **non-modal 輕量浮層**,跟 density 鎖 md 同源的視覺語言 —\n// chrome 全體輕量:\n// - density 鎖 md(不隨 page 放大)\n// - dismiss X 透過 v5 unbounded trick layout 佔位 24\n// - **title `text-body`(14px)跟 Dialog / Sheet modal 的 body-lg(16px)形成重量級 vs 輕量級視覺區分**\n// 世界級對照:Figma / Notion / Linear / Material 的 popover / filter panel / inline settings\n// 的 header title 多半比 modal dialog title 小一級(16→14 或同比),視覺宣告「此浮層可忽略」\n//\n// Coachmark 同樣消費 PopoverTitle 作 header 小標籤(如 \"新功能介紹\" / \"Tip 1 of 3\"),\n// CoachmarkBody 的主 title 另走 text-body-lg(見 coachmark.tsx L178)。\nconst PopoverTitle = React.forwardRef<\n HTMLHeadingElement,\n React.HTMLAttributes<HTMLHeadingElement>\n>(({ className, ...props }, ref) => (\n <h2\n ref={ref}\n className={cn(\"text-body font-medium truncate\", className)}\n {...props}\n />\n))\nPopoverTitle.displayName = \"PopoverTitle\"\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 popoverMeta = {\n component: 'Popover',\n family: null, // non-family composite / overlay / layout\n variants: {\n\n },\n sizes: {\n\n },\n states: ['default', 'hover', 'active', 'focus-visible', 'disabled'],\n tokens: {\n bg: ['bg-surface-raised'],\n fg: ['text-foreground'],\n ring: [],\n },\n} as const\n\nexport {\n Popover,\n PopoverTrigger,\n PopoverAnchor,\n PopoverContent,\n PopoverClose,\n PopoverHeader,\n PopoverBody,\n PopoverFooter,\n PopoverTitle,\n}\n"],"names":["XIcon"],"mappings":";;;;;;;;AA6BA,MAAM,UAAU,iBAAiB;AACjC,MAAM,iBAAiB,iBAAiB;AACxC,MAAM,gBAAgB,iBAAiB;AACvC,MAAM,eAAe,iBAAiB;AAItC,MAAM,6BAA6B,CAAC,MAAa;AAC/C,IAAE,eAAA;AACF,QAAM,UAAU,EAAE;AAClB,QAAM,kBAAkB,QAAQ;AAAA,IAC9B;AAAA,EAAA;AAEF,QAAM,oBAAoB,QAAQ;AAAA,IAChC;AAAA,EAAA;AAED,GAAC,mBAAmB,qBAAqB,SAAS,MAAM,EAAE,eAAe,MAAM;AAClF;AAEA,MAAM,iBAAiB,MAAM,WAG3B,CAAC,EAAE,WAAW,QAAQ,UAAU,aAAa,qBAAqB,mBAAmB,2BAA2B,iBAAiB,GAAG,MAAA,GAAS,QAC7I,oBAAC,iBAAiB,QAAjB,EACC,UAAA;AAAA,EAAC,iBAAiB;AAAA,EAAjB;AAAA,IACC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,gBAAa;AAAA,IACb,iBAAiB,mBAAmB;AAAA,IACpC,WAAW;AAAA,MACT;AAAA;AAAA;AAAA,MAGA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IAAA;AAAA,IAED,GAAG;AAAA,EAAA;AACN,GACF,CACD;AACD,eAAe,cAAc,iBAAiB,QAAQ;AAYtD,MAAM,gBAAgB,MAAM;AAAA,EAC1B,CAAC,EAAE,WAAW,UAAU,YAAY,OAAO,GAAG,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOrD;AAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA,WAAW,GAAG,6CAA6C,SAAS;AAAA,QACnE,GAAG;AAAA,QAEJ,UAAA;AAAA,UAAA,oBAAC,OAAA,EAAI,WAAU,kBAAkB,SAAA,CAAS;AAAA,UACzC,CAAC,aACA,oBAAC,iBAAiB,OAAjB,EAAuB,SAAO,MAE7B,UAAA,oBAAC,QAAA,EAAO,gBAAY,MAAC,UAAQ,MAAC,SAAO,MAAC,MAAK,MAAK,WAAWA,GAAO,cAAW,KAAA,CAAK,EAAA,CACpF;AAAA,QAAA;AAAA,MAAA;AAAA,IAAA;AAAA;AAIR;AACA,cAAc,cAAc;AAW5B,MAAM,cAAc,MAAM;AAAA,EACxB,CAAC,EAAE,GAAG,SAAS,QAAQ,oBAAC,aAAA,EAAY,KAAU,qBAAiB,MAAE,GAAG,MAAA,CAAO;AAC7E;AACA,YAAY,cAAc;AAE1B,MAAM,gBAAgB,MAAM;AAAA,EAC1B,CAAC,EAAE,GAAG,SAAS,QAAQ,oBAAC,eAAA,EAAc,KAAU,uBAAmB,MAAE,GAAG,MAAA,CAAO;AACjF;AACA,cAAc,cAAc;AAa5B,MAAM,eAAe,MAAM,WAGzB,CAAC,EAAE,WAAW,GAAG,MAAA,GAAS,QAC1B;AAAA,EAAC;AAAA,EAAA;AAAA,IACC;AAAA,IACA,WAAW,GAAG,kCAAkC,SAAS;AAAA,IACxD,GAAG;AAAA,EAAA;AACN,CACD;AACD,aAAa,cAAc;AAIpB,MAAM,cAAc;AAAA,EACzB,WAAW;AAAA,EACX,QAAQ;AAAA;AAAA,EACR,UAAU,CAAA;AAAA,EAGV,OAAO,CAAA;AAAA,EAGP,QAAQ,CAAC,WAAW,SAAS,UAAU,iBAAiB,UAAU;AAAA,EAClE,QAAQ;AAAA,IACN,IAAI,CAAC,mBAAmB;AAAA,IACxB,IAAI,CAAC,iBAAiB;AAAA,IACtB,MAAM,CAAA;AAAA,EAAC;AAEX;"}
|
|
1
|
+
{"version":3,"file":"popover.js","sources":["../../../src/components/Popover/popover.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 PopoverPrimitive from \"@radix-ui/react-popover\"\nimport { X as XIcon } from \"lucide-react\"\n\nimport { cn } from \"@/lib/utils\"\nimport { SurfaceHeader, SurfaceBody, SurfaceFooter } from \"@/design-system/patterns/overlay-surface/overlay-surface\"\nimport { Button } from \"@/design-system/components/Button/button\"\nimport { OVERLAY_SIDE_OFFSET, OVERLAY_COLLISION_PADDING } from \"@/design-system/tokens/elevation/overlay-geometry\"\n\n/**\n * Popover — Radix Popover + 設計系統 token\n *\n * ── 視覺 ──\n * 與 Dialog 對齊:bg-surface-raised / rounded-lg / border-border / elevation-200。\n * density 永遠鎖 md(non-modal 輕量浮層不隨頁面 density 放大)。\n *\n * ── 結構 ──\n * PopoverContent:外殼(bg / border / radius / shadow / density),無內距。\n * PopoverHeader / PopoverBody / PopoverFooter:消費 overlay-surface pattern\n * 共用的 SurfaceHeader / SurfaceBody / SurfaceFooter primitives(padding SSOT)。\n *\n * ── Header dismiss X(2026-04-20 決策) ──\n * 所有 PopoverHeader 一律附右上 X 按鈕(對齊 Dialog 的 canonical)。Popover 雖是\n * non-modal + click-outside-to-close,但有 header 的 Popover 通常結構化程度高\n * (title / 多區塊),明確的「關閉」入口讓使用者更易退出。無 header 的簡單 Popover\n * 不加 X(click-outside / Esc 即可)。\n */\n\nconst Popover = PopoverPrimitive.Root\nconst PopoverTrigger = PopoverPrimitive.Trigger\nconst PopoverAnchor = PopoverPrimitive.Anchor\nconst PopoverClose = PopoverPrimitive.Close\n\n// AutoFocus canonical(對齊 Dialog / Sheet / Material / Polaris)—\n// 開啟時 focus 落在 body 第一個有意義互動元素,避免 focus 到 close X 觸發 tooltip leak\nconst handlePopoverOpenAutoFocus = (e: Event) => {\n e.preventDefault()\n const content = e.currentTarget as HTMLElement\n const firstBodyTarget = content.querySelector<HTMLElement>(\n '[data-popover-body] input:not([disabled]),[data-popover-body] textarea:not([disabled]),[data-popover-body] select:not([disabled]),[data-popover-body] button:not([disabled]):not([data-dismiss]),input:not([disabled]),textarea:not([disabled]),button:not([disabled]):not([data-dismiss])'\n )\n const firstFooterButton = content.querySelector<HTMLElement>(\n '[data-popover-footer] button:not([disabled]):not([data-dismiss])'\n )\n ;(firstBodyTarget ?? firstFooterButton ?? content).focus({ preventScroll: true })\n}\n\nconst PopoverContent = React.forwardRef<\n React.ElementRef<typeof PopoverPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>\n>(({ className, align = \"center\", sideOffset = OVERLAY_SIDE_OFFSET, collisionPadding = OVERLAY_COLLISION_PADDING, onOpenAutoFocus, ...props }, ref) => (\n <PopoverPrimitive.Portal>\n <PopoverPrimitive.Content\n ref={ref}\n align={align}\n sideOffset={sideOffset}\n collisionPadding={collisionPadding}\n data-density=\"md\"\n onOpenAutoFocus={onOpenAutoFocus ?? handlePopoverOpenAutoFocus}\n className={cn(\n \"z-50 w-72 rounded-lg border border-border bg-surface-raised text-foreground shadow-[var(--elevation-200)] outline-none\",\n // 2026-05-04 viewport-aware max-h SSOT(從 NameCard 升 DS-wide):header/footer 永遠 in-viewport,body 壓縮 scroll\n // 2026-05-05 audit dim 35 補:加 `min-h-0` 完成 M25 chain invariant(flex item default min-h: auto 阻 shrink)\n \"max-h-[var(--radix-popover-content-available-height,100vh)] flex flex-col overflow-hidden min-h-0\",\n \"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 motion-reduce:animate-none\",\n \"data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2\",\n \"origin-[var(--radix-popover-content-transform-origin)]\",\n className\n )}\n {...props}\n />\n </PopoverPrimitive.Portal>\n))\nPopoverContent.displayName = PopoverPrimitive.Content.displayName\n\n// PopoverHeader: SurfaceHeader + Close X(對齊 Dialog 的 canonical,見 docblock)\n// justify-between 讓 children 與 Close 分左右。\ninterface PopoverHeaderProps extends React.HTMLAttributes<HTMLDivElement> {\n /**\n * 隱藏右上 close X(預設 false,顯示)。\n * Coachmark / Tour 類 composition 用 Skip / Done 自管 close,不需 X。\n */\n hideClose?: boolean\n}\n\nconst PopoverHeader = React.forwardRef<HTMLDivElement, PopoverHeaderProps>(\n ({ className, children, hideClose = false, ...props }, ref) => (\n // Popover lightweight chrome canonical(2026-05-04 重思 v2):\n // 覆寫 `--chrome-slot-h: 1.25rem` (20px) → unbounded button 佔位縮成 20,**匹配 PopoverTitle\n // text-body line-height (14×1.5≈21,floor 20)**。Header 維持 padding-based 自然撐開:\n // max(21 title, 20 slot) + py-tight(12*2) = 45 → 自然比 Dialog/Sheet 48 輕一級。\n // Q10 穩定:title-only / title+close 都 = title + py 主導,slot 不 dominate。\n // 無 min-h / 無 py override — 修正前一版過度設計。\n <SurfaceHeader\n ref={ref}\n className={cn(\"justify-between [--chrome-slot-h:1.25rem]\", className)}\n {...props}\n >\n <div className=\"flex-1 min-w-0\">{children}</div>\n {!hideClose && (\n // Dismiss X = native sm,SurfaceHeader 負 my trick 讓 layout 佔位 24 → 匹配 inner 24\n <PopoverPrimitive.Close asChild>\n <Button data-dismiss iconOnly dismiss size=\"sm\" startIcon={XIcon} aria-label=\"關閉\" />\n </PopoverPrimitive.Close>\n )}\n </SurfaceHeader>\n ),\n)\nPopoverHeader.displayName = \"PopoverHeader\"\n\n// PopoverBody / PopoverFooter: wrap SurfaceBody / SurfaceFooter with data-popover-*\n// attributes so handlePopoverOpenAutoFocus 可正確定位 body 內第一個 interactive 元素\n//\n// ── List-as-region 場景(menu / Cmd+K / nav)──\n// 不再提供 `flush` variant(2026-05-01 移除,對齊 DialogBody / SheetBody canonical)。\n// consumer 用 SurfaceBody className override 撤掉 chrome padding + 自管 list outer wrapper:\n// `<PopoverBody className=\"!px-0 !py-0\"><div className=\"py-2\">{items}</div></PopoverBody>`\n// 或乾脆不用 PopoverBody,直接 PopoverContent > 自管 list 結構(naked popover)。\n// 詳 DialogBody comment + `tokens/layoutSpace/layoutSpace.spec.md`「List-as-region in overlay body」\nconst PopoverBody = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(\n ({ ...props }, ref) => <SurfaceBody ref={ref} data-popover-body {...props} />,\n)\nPopoverBody.displayName = \"PopoverBody\"\n\nconst PopoverFooter = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(\n ({ ...props }, ref) => <SurfaceFooter ref={ref} data-popover-footer {...props} />\n)\nPopoverFooter.displayName = \"PopoverFooter\"\n\n// PopoverTitle(2026-04-22 v4 non-modal canonical):`text-body font-medium`(14px)\n// Rationale:Popover / Coachmark 屬 **non-modal 輕量浮層**,跟 density 鎖 md 同源的視覺語言 —\n// chrome 全體輕量:\n// - density 鎖 md(不隨 page 放大)\n// - dismiss X 透過 v5 unbounded trick layout 佔位 24\n// - **title `text-body`(14px)跟 Dialog / Sheet modal 的 body-lg(16px)形成重量級 vs 輕量級視覺區分**\n// 世界級對照:Figma / Notion / Linear / Material 的 popover / filter panel / inline settings\n// 的 header title 多半比 modal dialog title 小一級(16→14 或同比),視覺宣告「此浮層可忽略」\n//\n// Coachmark 同樣消費 PopoverTitle 作 header 小標籤(如 \"新功能介紹\" / \"Tip 1 of 3\"),\n// CoachmarkBody 的主 title 另走 text-body-lg(見 coachmark.tsx L178)。\nconst PopoverTitle = React.forwardRef<\n HTMLHeadingElement,\n React.HTMLAttributes<HTMLHeadingElement>\n>(({ className, ...props }, ref) => (\n <h2\n ref={ref}\n className={cn(\"text-body font-medium truncate\", className)}\n {...props}\n />\n))\nPopoverTitle.displayName = \"PopoverTitle\"\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 popoverMeta = {\n component: 'Popover',\n family: null, // non-family composite / overlay / layout\n variants: {\n\n },\n sizes: {\n\n },\n states: ['default', 'hover', 'active', 'focus-visible', 'disabled'],\n tokens: {\n bg: ['bg-surface-raised'],\n fg: ['text-foreground'],\n ring: [],\n },\n} as const\n\nexport {\n Popover,\n PopoverTrigger,\n PopoverAnchor,\n PopoverContent,\n PopoverClose,\n PopoverHeader,\n PopoverBody,\n PopoverFooter,\n PopoverTitle,\n}\n"],"names":["XIcon"],"mappings":";;;;;;;;AA6BA,MAAM,UAAU,iBAAiB;AACjC,MAAM,iBAAiB,iBAAiB;AACxC,MAAM,gBAAgB,iBAAiB;AACvC,MAAM,eAAe,iBAAiB;AAItC,MAAM,6BAA6B,CAAC,MAAa;AAC/C,IAAE,eAAA;AACF,QAAM,UAAU,EAAE;AAClB,QAAM,kBAAkB,QAAQ;AAAA,IAC9B;AAAA,EAAA;AAEF,QAAM,oBAAoB,QAAQ;AAAA,IAChC;AAAA,EAAA;AAED,GAAC,mBAAmB,qBAAqB,SAAS,MAAM,EAAE,eAAe,MAAM;AAClF;AAEA,MAAM,iBAAiB,MAAM,WAG3B,CAAC,EAAE,WAAW,QAAQ,UAAU,aAAa,qBAAqB,mBAAmB,2BAA2B,iBAAiB,GAAG,MAAA,GAAS,QAC7I,oBAAC,iBAAiB,QAAjB,EACC,UAAA;AAAA,EAAC,iBAAiB;AAAA,EAAjB;AAAA,IACC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,gBAAa;AAAA,IACb,iBAAiB,mBAAmB;AAAA,IACpC,WAAW;AAAA,MACT;AAAA;AAAA;AAAA,MAGA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IAAA;AAAA,IAED,GAAG;AAAA,EAAA;AACN,GACF,CACD;AACD,eAAe,cAAc,iBAAiB,QAAQ;AAYtD,MAAM,gBAAgB,MAAM;AAAA,EAC1B,CAAC,EAAE,WAAW,UAAU,YAAY,OAAO,GAAG,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOrD;AAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA,WAAW,GAAG,6CAA6C,SAAS;AAAA,QACnE,GAAG;AAAA,QAEJ,UAAA;AAAA,UAAA,oBAAC,OAAA,EAAI,WAAU,kBAAkB,SAAA,CAAS;AAAA,UACzC,CAAC;AAAA,UAEA,oBAAC,iBAAiB,OAAjB,EAAuB,SAAO,MAC7B,UAAA,oBAAC,UAAO,gBAAY,MAAC,UAAQ,MAAC,SAAO,MAAC,MAAK,MAAK,WAAWA,GAAO,cAAW,MAAK,EAAA,CACpF;AAAA,QAAA;AAAA,MAAA;AAAA,IAAA;AAAA;AAIR;AACA,cAAc,cAAc;AAW5B,MAAM,cAAc,MAAM;AAAA,EACxB,CAAC,EAAE,GAAG,SAAS,QAAQ,oBAAC,aAAA,EAAY,KAAU,qBAAiB,MAAE,GAAG,MAAA,CAAO;AAC7E;AACA,YAAY,cAAc;AAE1B,MAAM,gBAAgB,MAAM;AAAA,EAC1B,CAAC,EAAE,GAAG,SAAS,QAAQ,oBAAC,eAAA,EAAc,KAAU,uBAAmB,MAAE,GAAG,MAAA,CAAO;AACjF;AACA,cAAc,cAAc;AAa5B,MAAM,eAAe,MAAM,WAGzB,CAAC,EAAE,WAAW,GAAG,MAAA,GAAS,QAC1B;AAAA,EAAC;AAAA,EAAA;AAAA,IACC;AAAA,IACA,WAAW,GAAG,kCAAkC,SAAS;AAAA,IACxD,GAAG;AAAA,EAAA;AACN,CACD;AACD,aAAa,cAAc;AAIpB,MAAM,cAAc;AAAA,EACzB,WAAW;AAAA,EACX,QAAQ;AAAA;AAAA,EACR,UAAU,CAAA;AAAA,EAGV,OAAO,CAAA;AAAA,EAGP,QAAQ,CAAC,WAAW,SAAS,UAAU,iBAAiB,UAAU;AAAA,EAClE,QAAQ;AAAA,IACN,IAAI,CAAC,mBAAmB;AAAA,IACxB,IAAI,CAAC,iBAAiB;AAAA,IACtB,MAAM,CAAA;AAAA,EAAC;AAEX;"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import * as RadioGroupPrimitive from "@radix-ui/react-radio-group";
|
|
3
3
|
import { type VariantProps } from "class-variance-authority";
|
|
4
|
-
import type { FieldMode, FieldVariant } from "
|
|
4
|
+
import type { FieldMode, FieldVariant } from "../../components/Field/field-types";
|
|
5
5
|
export interface RadioGroupProps extends React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Root> {
|
|
6
6
|
/**
|
|
7
7
|
* Field mode(2026-05-05 Phase B3 align):
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import type { LucideIcon } from 'lucide-react';
|
|
3
|
-
import type { FieldMode, FieldVariant } from '
|
|
4
|
-
import { type SelectMenuOption } from '
|
|
3
|
+
import type { FieldMode, FieldVariant } from '../../components/Field/field-types';
|
|
4
|
+
import { type SelectMenuOption } from '../../components/SelectMenu/select-menu';
|
|
5
5
|
/**
|
|
6
6
|
* Select 用的 option schema(2026-05-10 Issue 4 + post-prune unify):**explicit extends
|
|
7
7
|
* SelectMenuOption(primitive SSOT)** — 任何 SelectMenuOption 加 field 都自動繼承,不會 drift。
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import type { LucideIcon } from 'lucide-react';
|
|
3
|
-
import type { AvatarData } from '
|
|
3
|
+
import type { AvatarData } from '../../components/Avatar/avatar';
|
|
4
4
|
/**
|
|
5
5
|
* SelectMenu — Popover + Command 組成的完整下拉選單
|
|
6
6
|
*
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { type VariantProps } from 'class-variance-authority';
|
|
3
3
|
import type { LucideIcon } from 'lucide-react';
|
|
4
|
-
import { type AvatarData } from '
|
|
4
|
+
import { type AvatarData } from '../../components/Avatar/avatar';
|
|
5
5
|
export declare const selectionItemStyles: (props?: ({
|
|
6
6
|
size?: "sm" | "md" | "lg" | null | undefined;
|
|
7
7
|
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import * as SheetPrimitive from "@radix-ui/react-dialog";
|
|
3
3
|
import { type VariantProps } from "class-variance-authority";
|
|
4
|
-
import { type SurfaceHeaderProps } from "
|
|
4
|
+
import { type SurfaceHeaderProps } from "../../patterns/overlay-surface/overlay-surface";
|
|
5
5
|
/**
|
|
6
6
|
* Sheet — **右側 Dialog primitive**(給消費者的 canonical)。
|
|
7
7
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sheet.js","sources":["../../../src/components/Sheet/sheet.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 SheetPrimitive from \"@radix-ui/react-dialog\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\nimport { X as XIcon } from \"lucide-react\"\n\nimport { cn } from \"@/lib/utils\"\nimport {\n SurfaceHeader,\n SurfaceFooter,\n type SurfaceHeaderProps,\n} from \"@/design-system/patterns/overlay-surface/overlay-surface\"\nimport { Button } from \"@/design-system/components/Button/button\"\nimport { ScrollArea } from \"@/design-system/components/ScrollArea/scroll-area\"\n\n/**\n * Sheet — **右側 Dialog primitive**(給消費者的 canonical)。\n *\n * ── 定位(2026-04-21 canonical)──\n * Sheet 給**消費者**用的唯一合法形式 = **右側開啟的 modal**(side=\"right\"),\n * 內部結構跟 `Dialog` 一致:`SheetHeader` / `SheetBody` / `SheetFooter`(各自消費\n * `SurfaceHeader` / `SurfaceBody` / `SurfaceFooter` primitive,padding token SSOT\n * 在 `patterns/overlay-surface/`)。side=\"right\" 是 defaultVariants,消費者不傳 side。\n *\n * ── 其他 side(top / bottom / left)——**非消費者 API**,內部基建用 ──\n * top / bottom / left 變體保留給 DS 內部基建(例:Sidebar 在小尺寸視口時從 left 滑入)。\n * 消費者 code **禁止** 傳 `side=\"top\" | \"bottom\" | \"left\"` — 這些用途需 user 授權。\n *\n * ── 跟 Dialog 的差異 ──\n * - Dialog = 中央 modal,用於「明確決策 / 表單 / 確認」\n * - Sheet(side=\"right\")= 側滑 modal,用於「補充資訊 / 多欄位表單 / 編輯 flow」\n * - 兩者 API 結構 1:1 對應,差異只在 side / 動畫 / 初始寬度\n *\n * ── Header / Body / Footer 消費 SurfaceXxx SSOT ──\n * 避免 padding 漂移 — Dialog / Popover / Sheet / Coachmark 共用同一套 overlay-surface\n * padding token(px-loose / py-tight),改 overlay-surface.tsx 四者自動跟進。\n */\n\nconst Sheet = SheetPrimitive.Root\n\nconst SheetTrigger = SheetPrimitive.Trigger\n\nconst SheetClose = SheetPrimitive.Close\n\nconst SheetPortal = SheetPrimitive.Portal\n\nconst SheetOverlay = React.forwardRef<\n React.ElementRef<typeof SheetPrimitive.Overlay>,\n React.ComponentPropsWithoutRef<typeof SheetPrimitive.Overlay>\n>(({ className, ...props }, ref) => (\n <SheetPrimitive.Overlay\n className={cn(\n \"fixed inset-0 z-50 bg-overlay data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0\",\n className\n )}\n {...props}\n ref={ref}\n />\n))\nSheetOverlay.displayName = SheetPrimitive.Overlay.displayName\n\n// ── sheetVariants ─────────────────────────────────────────────────────────\n// side=\"right\" 給**消費者**。top/bottom/left 給 **DS 內部基建**用(如 Sidebar 在\n// narrow viewport 時切 side=\"left\")。消費者 code 不傳 side,用 default。\nconst sheetVariants = cva(\n // 核心容器 — 無 padding(由 SheetBody / SheetHeader / SheetFooter 自理 padding,\n // 對齊 overlay-surface pattern + Dialog canonical)\n // Animation canonical:300ms 雙向一致(D4 audit:500ms 太久 sluggish)+ motion-reduce 豁免\n \"fixed z-50 flex flex-col bg-surface-raised shadow-[var(--elevation-200)] transition ease-in-out data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:duration-300 motion-reduce:transition-none motion-reduce:data-[state=open]:duration-0 motion-reduce:data-[state=closed]:duration-0\",\n {\n variants: {\n side: {\n top: \"inset-x-0 top-0 border-b border-divider data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top\",\n bottom:\n \"inset-x-0 bottom-0 border-t border-divider data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom\",\n left: \"inset-y-0 left-0 h-full w-3/4 border-r border-divider data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-md\",\n right:\n \"inset-y-0 right-0 h-full w-3/4 border-l border-divider data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-md\",\n },\n },\n defaultVariants: {\n side: \"right\",\n },\n }\n)\n\ninterface SheetContentProps\n extends React.ComponentPropsWithoutRef<typeof SheetPrimitive.Content>,\n VariantProps<typeof sheetVariants> {}\n\n// AutoFocus canonical(對齊 Dialog / Material / Polaris)— 見 dialog.tsx handleOpenAutoFocus 註解\nconst handleSheetOpenAutoFocus = (e: Event) => {\n e.preventDefault()\n const content = e.currentTarget as HTMLElement\n const firstBodyTarget = content.querySelector<HTMLElement>(\n '[data-sheet-body] input:not([disabled]),[data-sheet-body] textarea:not([disabled]),[data-sheet-body] select:not([disabled]),[data-sheet-body] button:not([disabled]):not([data-dismiss])'\n )\n const firstFooterButton = content.querySelector<HTMLElement>(\n '[data-sheet-footer] button:not([disabled]):not([data-dismiss])'\n )\n ;(firstBodyTarget ?? firstFooterButton ?? content).focus({ preventScroll: true })\n}\n\nconst SheetContent = React.forwardRef<\n React.ElementRef<typeof SheetPrimitive.Content>,\n SheetContentProps\n>(({ side = \"right\", className, children, ...props }, ref) => (\n <SheetPortal>\n <SheetOverlay />\n <SheetPrimitive.Content\n ref={ref}\n onOpenAutoFocus={handleSheetOpenAutoFocus}\n // Sheet 不自設 density,繼承 page 層級的 `html[data-density]`(2026-04-21 canonical 定案)\n className={cn(sheetVariants({ side }), className)}\n {...props}\n >\n {children}\n </SheetPrimitive.Content>\n </SheetPortal>\n))\nSheetContent.displayName = SheetPrimitive.Content.displayName\n\n// ── SheetHeader:SurfaceHeader + Close X(對齊 DialogHeader canonical)──────────\n// 2026-05-18 audit gap fix:type 對齊 SurfaceHeaderProps,withTabs / lockDensity expose\n// 給 consumer(per header-canonical.spec.md W1 跨 6 consumer 同契約)。Spread 早 forward\n// 過去,只是 TS type 沒 expose 導致 consumer 不能 type-safe 用 `<SheetHeader withTabs>`。\nconst SheetHeader = React.forwardRef<\n HTMLDivElement,\n SurfaceHeaderProps\n>(({ className, children, ...props }, ref) => (\n // 2026-05-18:className 不再硬加 justify-between(同 DialogHeader 邏輯,避 column mode 破裂)。\n <SurfaceHeader\n ref={ref}\n className={className}\n {...props}\n >\n <div className=\"flex-1 min-w-0\">{children}</div>\n <SheetPrimitive.Close asChild>\n {/* Dismiss X = native sm,SurfaceHeader 負 my trick 讓 layout 佔位 24 → chrome-header-height */}\n <Button data-dismiss iconOnly dismiss size=\"sm\" startIcon={XIcon} aria-label=\"關閉\" />\n </SheetPrimitive.Close>\n </SurfaceHeader>\n))\nSheetHeader.displayName = \"SheetHeader\"\n\n// ── SheetBody:flex-1 ScrollArea + chrome padding(對齊 DialogBody + ScrollArea canonical) ──\n// 捲軸必用 ScrollArea(跨 OS 一致、不吃寬度)— 不自寫 overflow-y-auto。\n// padding 搬進 viewport inner div:px-loose / pt-tight / pb-bottom。\n// data-sheet-body:讓 SheetContent onOpenAutoFocus 找得到 body 第一個互動元素\n//\n// ── List-as-region 場景(menu / nav / settings list)──\n// 不再提供 `flush` variant(2026-05-01 移除)。canonical = consumer 用 className override:\n// `<SheetBody className=\"!px-0 !pt-0 !pb-0\"><div className=\"py-2\">{items}</div></SheetBody>`\n// 詳 DialogBody comment + `tokens/layoutSpace/layoutSpace.spec.md`「List-as-region in overlay body」\n// `className` forward 到 **inner content div**(非外層 ScrollArea wrapper)——\n// consumer `<SheetBody className=\"flex flex-col gap-X\">` 期望作用於 children 排列;\n// 套在 ScrollArea 上會 0 效果(children 住 inner div),曾造成 Sheet form field 完全貼邊。\nconst SheetBody = React.forwardRef<\n HTMLDivElement,\n React.ComponentPropsWithoutRef<typeof ScrollArea>\n>(({ className, children, ...props }, ref) => (\n <ScrollArea ref={ref} data-sheet-body className=\"flex-1 min-h-0\" {...props}>\n <div\n className={cn(\n \"px-[var(--layout-space-loose)] pt-[var(--layout-space-tight)] pb-[var(--layout-space-bottom)]\",\n className,\n )}\n >\n {children}\n </div>\n </ScrollArea>\n))\nSheetBody.displayName = \"SheetBody\"\n\n// ── SheetFooter:SurfaceFooter wrap 加 data-sheet-footer(autoFocus fallback target)──\nconst SheetFooter = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ ...props }, ref) => <SurfaceFooter ref={ref} data-sheet-footer {...props} />)\nSheetFooter.displayName = \"SheetFooter\"\n\nconst SheetTitle = React.forwardRef<\n React.ElementRef<typeof SheetPrimitive.Title>,\n React.ComponentPropsWithoutRef<typeof SheetPrimitive.Title>\n>(({ className, ...props }, ref) => (\n <SheetPrimitive.Title\n ref={ref}\n className={cn(\"text-body-lg font-medium truncate text-foreground\", className)}\n {...props}\n />\n))\nSheetTitle.displayName = SheetPrimitive.Title.displayName\n\nconst SheetDescription = React.forwardRef<\n React.ElementRef<typeof SheetPrimitive.Description>,\n React.ComponentPropsWithoutRef<typeof SheetPrimitive.Description>\n>(({ className, ...props }, ref) => (\n <SheetPrimitive.Description\n ref={ref}\n // title → description 間距 canonical:SheetTitle body-lg(16)+ desc body(14)→ reading-lg token\n // (label tier 決定;對齊 Dialog canonical。Tailwind preflight reset h2/p margin=0 → 必顯式 mt)\n className={cn(\"mt-[var(--item-gap-label-desc-reading-lg)] text-body text-fg-secondary\", className)}\n {...props}\n />\n))\nSheetDescription.displayName = SheetPrimitive.Description.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 sheetMeta = {\n component: 'Sheet',\n family: null, // non-family composite / overlay / layout\n variants: {\n\n },\n sizes: {\n\n },\n states: ['default', 'hover', 'active', 'focus-visible', 'disabled'],\n tokens: {\n bg: ['bg-surface-raised'],\n fg: ['text-fg-secondary', 'text-foreground'],\n ring: [],\n },\n} as const\n\nexport {\n Sheet,\n SheetPortal,\n SheetOverlay,\n SheetTrigger,\n SheetClose,\n SheetContent,\n SheetHeader,\n SheetBody,\n SheetFooter,\n SheetTitle,\n SheetDescription,\n sheetVariants,\n}\n"],"names":["SheetPrimitive","XIcon"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"sheet.js","sources":["../../../src/components/Sheet/sheet.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 SheetPrimitive from \"@radix-ui/react-dialog\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\nimport { X as XIcon } from \"lucide-react\"\n\nimport { cn } from \"@/lib/utils\"\nimport {\n SurfaceHeader,\n SurfaceFooter,\n type SurfaceHeaderProps,\n} from \"@/design-system/patterns/overlay-surface/overlay-surface\"\nimport { Button } from \"@/design-system/components/Button/button\"\nimport { ScrollArea } from \"@/design-system/components/ScrollArea/scroll-area\"\n\n/**\n * Sheet — **右側 Dialog primitive**(給消費者的 canonical)。\n *\n * ── 定位(2026-04-21 canonical)──\n * Sheet 給**消費者**用的唯一合法形式 = **右側開啟的 modal**(side=\"right\"),\n * 內部結構跟 `Dialog` 一致:`SheetHeader` / `SheetBody` / `SheetFooter`(各自消費\n * `SurfaceHeader` / `SurfaceBody` / `SurfaceFooter` primitive,padding token SSOT\n * 在 `patterns/overlay-surface/`)。side=\"right\" 是 defaultVariants,消費者不傳 side。\n *\n * ── 其他 side(top / bottom / left)——**非消費者 API**,內部基建用 ──\n * top / bottom / left 變體保留給 DS 內部基建(例:Sidebar 在小尺寸視口時從 left 滑入)。\n * 消費者 code **禁止** 傳 `side=\"top\" | \"bottom\" | \"left\"` — 這些用途需 user 授權。\n *\n * ── 跟 Dialog 的差異 ──\n * - Dialog = 中央 modal,用於「明確決策 / 表單 / 確認」\n * - Sheet(side=\"right\")= 側滑 modal,用於「補充資訊 / 多欄位表單 / 編輯 flow」\n * - 兩者 API 結構 1:1 對應,差異只在 side / 動畫 / 初始寬度\n *\n * ── Header / Body / Footer 消費 SurfaceXxx SSOT ──\n * 避免 padding 漂移 — Dialog / Popover / Sheet / Coachmark 共用同一套 overlay-surface\n * padding token(px-loose / py-tight),改 overlay-surface.tsx 四者自動跟進。\n */\n\nconst Sheet = SheetPrimitive.Root\n\nconst SheetTrigger = SheetPrimitive.Trigger\n\nconst SheetClose = SheetPrimitive.Close\n\nconst SheetPortal = SheetPrimitive.Portal\n\nconst SheetOverlay = React.forwardRef<\n React.ElementRef<typeof SheetPrimitive.Overlay>,\n React.ComponentPropsWithoutRef<typeof SheetPrimitive.Overlay>\n>(({ className, ...props }, ref) => (\n <SheetPrimitive.Overlay\n className={cn(\n \"fixed inset-0 z-50 bg-overlay data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0\",\n className\n )}\n {...props}\n ref={ref}\n />\n))\nSheetOverlay.displayName = SheetPrimitive.Overlay.displayName\n\n// ── sheetVariants ─────────────────────────────────────────────────────────\n// side=\"right\" 給**消費者**。top/bottom/left 給 **DS 內部基建**用(如 Sidebar 在\n// narrow viewport 時切 side=\"left\")。消費者 code 不傳 side,用 default。\nconst sheetVariants = cva(\n // 核心容器 — 無 padding(由 SheetBody / SheetHeader / SheetFooter 自理 padding,\n // 對齊 overlay-surface pattern + Dialog canonical)\n // Animation canonical:300ms 雙向一致(D4 audit:500ms 太久 sluggish)+ motion-reduce 豁免\n \"fixed z-50 flex flex-col bg-surface-raised shadow-[var(--elevation-200)] transition ease-in-out data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:duration-300 motion-reduce:transition-none motion-reduce:data-[state=open]:duration-0 motion-reduce:data-[state=closed]:duration-0\",\n {\n variants: {\n side: {\n top: \"inset-x-0 top-0 border-b border-divider data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top\",\n bottom:\n \"inset-x-0 bottom-0 border-t border-divider data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom\",\n left: \"inset-y-0 left-0 h-full w-3/4 border-r border-divider data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-md\",\n right:\n \"inset-y-0 right-0 h-full w-3/4 border-l border-divider data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-md\",\n },\n },\n defaultVariants: {\n side: \"right\",\n },\n }\n)\n\ninterface SheetContentProps\n extends React.ComponentPropsWithoutRef<typeof SheetPrimitive.Content>,\n VariantProps<typeof sheetVariants> {}\n\n// AutoFocus canonical(對齊 Dialog / Material / Polaris)— 見 dialog.tsx handleOpenAutoFocus 註解\nconst handleSheetOpenAutoFocus = (e: Event) => {\n e.preventDefault()\n const content = e.currentTarget as HTMLElement\n const firstBodyTarget = content.querySelector<HTMLElement>(\n '[data-sheet-body] input:not([disabled]),[data-sheet-body] textarea:not([disabled]),[data-sheet-body] select:not([disabled]),[data-sheet-body] button:not([disabled]):not([data-dismiss])'\n )\n const firstFooterButton = content.querySelector<HTMLElement>(\n '[data-sheet-footer] button:not([disabled]):not([data-dismiss])'\n )\n ;(firstBodyTarget ?? firstFooterButton ?? content).focus({ preventScroll: true })\n}\n\nconst SheetContent = React.forwardRef<\n React.ElementRef<typeof SheetPrimitive.Content>,\n SheetContentProps\n>(({ side = \"right\", className, children, ...props }, ref) => (\n <SheetPortal>\n <SheetOverlay />\n <SheetPrimitive.Content\n ref={ref}\n onOpenAutoFocus={handleSheetOpenAutoFocus}\n // Sheet 不自設 density,繼承 page 層級的 `html[data-density]`(2026-04-21 canonical 定案)\n className={cn(sheetVariants({ side }), className)}\n {...props}\n >\n {children}\n </SheetPrimitive.Content>\n </SheetPortal>\n))\nSheetContent.displayName = SheetPrimitive.Content.displayName\n\n// ── SheetHeader:SurfaceHeader + Close X(對齊 DialogHeader canonical)──────────\n// 2026-05-18 audit gap fix:type 對齊 SurfaceHeaderProps,withTabs / lockDensity expose\n// 給 consumer(per header-canonical.spec.md W1 跨 6 consumer 同契約)。Spread 早 forward\n// 過去,只是 TS type 沒 expose 導致 consumer 不能 type-safe 用 `<SheetHeader withTabs>`。\nconst SheetHeader = React.forwardRef<\n HTMLDivElement,\n SurfaceHeaderProps\n>(({ className, children, ...props }, ref) => (\n // 2026-05-18:className 不再硬加 justify-between(同 DialogHeader 邏輯,避 column mode 破裂)。\n <SurfaceHeader\n ref={ref}\n className={className}\n {...props}\n >\n <div className=\"flex-1 min-w-0\">{children}</div>\n {/* Dismiss X = native sm,SurfaceHeader 負 my trick 讓 layout 佔位 24 → chrome-header-height */}\n <SheetPrimitive.Close asChild>\n <Button data-dismiss iconOnly dismiss size=\"sm\" startIcon={XIcon} aria-label=\"關閉\" />\n </SheetPrimitive.Close>\n </SurfaceHeader>\n))\nSheetHeader.displayName = \"SheetHeader\"\n\n// ── SheetBody:flex-1 ScrollArea + chrome padding(對齊 DialogBody + ScrollArea canonical) ──\n// 捲軸必用 ScrollArea(跨 OS 一致、不吃寬度)— 不自寫 overflow-y-auto。\n// padding 搬進 viewport inner div:px-loose / pt-tight / pb-bottom。\n// data-sheet-body:讓 SheetContent onOpenAutoFocus 找得到 body 第一個互動元素\n//\n// ── List-as-region 場景(menu / nav / settings list)──\n// 不再提供 `flush` variant(2026-05-01 移除)。canonical = consumer 用 className override:\n// `<SheetBody className=\"!px-0 !pt-0 !pb-0\"><div className=\"py-2\">{items}</div></SheetBody>`\n// 詳 DialogBody comment + `tokens/layoutSpace/layoutSpace.spec.md`「List-as-region in overlay body」\n// `className` forward 到 **inner content div**(非外層 ScrollArea wrapper)——\n// consumer `<SheetBody className=\"flex flex-col gap-X\">` 期望作用於 children 排列;\n// 套在 ScrollArea 上會 0 效果(children 住 inner div),曾造成 Sheet form field 完全貼邊。\nconst SheetBody = React.forwardRef<\n HTMLDivElement,\n React.ComponentPropsWithoutRef<typeof ScrollArea>\n>(({ className, children, ...props }, ref) => (\n <ScrollArea ref={ref} data-sheet-body className=\"flex-1 min-h-0\" {...props}>\n <div\n className={cn(\n \"px-[var(--layout-space-loose)] pt-[var(--layout-space-tight)] pb-[var(--layout-space-bottom)]\",\n className,\n )}\n >\n {children}\n </div>\n </ScrollArea>\n))\nSheetBody.displayName = \"SheetBody\"\n\n// ── SheetFooter:SurfaceFooter wrap 加 data-sheet-footer(autoFocus fallback target)──\nconst SheetFooter = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ ...props }, ref) => <SurfaceFooter ref={ref} data-sheet-footer {...props} />)\nSheetFooter.displayName = \"SheetFooter\"\n\nconst SheetTitle = React.forwardRef<\n React.ElementRef<typeof SheetPrimitive.Title>,\n React.ComponentPropsWithoutRef<typeof SheetPrimitive.Title>\n>(({ className, ...props }, ref) => (\n <SheetPrimitive.Title\n ref={ref}\n className={cn(\"text-body-lg font-medium truncate text-foreground\", className)}\n {...props}\n />\n))\nSheetTitle.displayName = SheetPrimitive.Title.displayName\n\nconst SheetDescription = React.forwardRef<\n React.ElementRef<typeof SheetPrimitive.Description>,\n React.ComponentPropsWithoutRef<typeof SheetPrimitive.Description>\n>(({ className, ...props }, ref) => (\n <SheetPrimitive.Description\n ref={ref}\n // title → description 間距 canonical:SheetTitle body-lg(16)+ desc body(14)→ reading-lg token\n // (label tier 決定;對齊 Dialog canonical。Tailwind preflight reset h2/p margin=0 → 必顯式 mt)\n className={cn(\"mt-[var(--item-gap-label-desc-reading-lg)] text-body text-fg-secondary\", className)}\n {...props}\n />\n))\nSheetDescription.displayName = SheetPrimitive.Description.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 sheetMeta = {\n component: 'Sheet',\n family: null, // non-family composite / overlay / layout\n variants: {\n\n },\n sizes: {\n\n },\n states: ['default', 'hover', 'active', 'focus-visible', 'disabled'],\n tokens: {\n bg: ['bg-surface-raised'],\n fg: ['text-fg-secondary', 'text-foreground'],\n ring: [],\n },\n} as const\n\nexport {\n Sheet,\n SheetPortal,\n SheetOverlay,\n SheetTrigger,\n SheetClose,\n SheetContent,\n SheetHeader,\n SheetBody,\n SheetFooter,\n SheetTitle,\n SheetDescription,\n sheetVariants,\n}\n"],"names":["SheetPrimitive","XIcon"],"mappings":";;;;;;;;;AAsCA,MAAM,QAAQA,gBAAe;AAE7B,MAAM,eAAeA,gBAAe;AAEpC,MAAM,aAAaA,gBAAe;AAElC,MAAM,cAAcA,gBAAe;AAEnC,MAAM,eAAe,MAAM,WAGzB,CAAC,EAAE,WAAW,GAAG,MAAA,GAAS,QAC1B;AAAA,EAACA,gBAAe;AAAA,EAAf;AAAA,IACC,WAAW;AAAA,MACT;AAAA,MACA;AAAA,IAAA;AAAA,IAED,GAAG;AAAA,IACJ;AAAA,EAAA;AACF,CACD;AACD,aAAa,cAAcA,gBAAe,QAAQ;AAKlD,MAAM,gBAAgB;AAAA;AAAA;AAAA;AAAA,EAIpB;AAAA,EACA;AAAA,IACE,UAAU;AAAA,MACR,MAAM;AAAA,QACJ,KAAK;AAAA,QACL,QACE;AAAA,QACF,MAAM;AAAA,QACN,OACE;AAAA,MAAA;AAAA,IACJ;AAAA,IAEF,iBAAiB;AAAA,MACf,MAAM;AAAA,IAAA;AAAA,EACR;AAEJ;AAOA,MAAM,2BAA2B,CAAC,MAAa;AAC7C,IAAE,eAAA;AACF,QAAM,UAAU,EAAE;AAClB,QAAM,kBAAkB,QAAQ;AAAA,IAC9B;AAAA,EAAA;AAEF,QAAM,oBAAoB,QAAQ;AAAA,IAChC;AAAA,EAAA;AAED,GAAC,mBAAmB,qBAAqB,SAAS,MAAM,EAAE,eAAe,MAAM;AAClF;AAEA,MAAM,eAAe,MAAM,WAGzB,CAAC,EAAE,OAAO,SAAS,WAAW,UAAU,GAAG,MAAA,GAAS,6BACnD,aAAA,EACC,UAAA;AAAA,EAAA,oBAAC,cAAA,EAAa;AAAA,EACd;AAAA,IAACA,gBAAe;AAAA,IAAf;AAAA,MACC;AAAA,MACA,iBAAiB;AAAA,MAEjB,WAAW,GAAG,cAAc,EAAE,KAAA,CAAM,GAAG,SAAS;AAAA,MAC/C,GAAG;AAAA,MAEH;AAAA,IAAA;AAAA,EAAA;AACH,GACF,CACD;AACD,aAAa,cAAcA,gBAAe,QAAQ;AAMlD,MAAM,cAAc,MAAM,WAGxB,CAAC,EAAE,WAAW,UAAU,GAAG,MAAA,GAAS;AAAA;AAAA,EAEpC;AAAA,IAAC;AAAA,IAAA;AAAA,MACC;AAAA,MACA;AAAA,MACC,GAAG;AAAA,MAEJ,UAAA;AAAA,QAAA,oBAAC,OAAA,EAAI,WAAU,kBAAkB,SAAA,CAAS;AAAA,QAE1C,oBAACA,gBAAe,OAAf,EAAqB,SAAO,MAC3B,UAAA,oBAAC,UAAO,gBAAY,MAAC,UAAQ,MAAC,SAAO,MAAC,MAAK,MAAK,WAAWC,GAAO,cAAW,MAAK,EAAA,CACpF;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAAA,CAEH;AACD,YAAY,cAAc;AAc1B,MAAM,YAAY,MAAM,WAGtB,CAAC,EAAE,WAAW,UAAU,GAAG,MAAA,GAAS,QACpC,oBAAC,cAAW,KAAU,mBAAe,MAAC,WAAU,kBAAkB,GAAG,OACnE,UAAA;AAAA,EAAC;AAAA,EAAA;AAAA,IACC,WAAW;AAAA,MACT;AAAA,MACA;AAAA,IAAA;AAAA,IAGD;AAAA,EAAA;AACH,GACF,CACD;AACD,UAAU,cAAc;AAGxB,MAAM,cAAc,MAAM,WAGxB,CAAC,EAAE,GAAG,MAAA,GAAS,QAAQ,oBAAC,iBAAc,KAAU,qBAAiB,MAAE,GAAG,OAAO,CAAE;AACjF,YAAY,cAAc;AAE1B,MAAM,aAAa,MAAM,WAGvB,CAAC,EAAE,WAAW,GAAG,MAAA,GAAS,QAC1B;AAAA,EAACD,gBAAe;AAAA,EAAf;AAAA,IACC;AAAA,IACA,WAAW,GAAG,qDAAqD,SAAS;AAAA,IAC3E,GAAG;AAAA,EAAA;AACN,CACD;AACD,WAAW,cAAcA,gBAAe,MAAM;AAE9C,MAAM,mBAAmB,MAAM,WAG7B,CAAC,EAAE,WAAW,GAAG,MAAA,GAAS,QAC1B;AAAA,EAACA,gBAAe;AAAA,EAAf;AAAA,IACC;AAAA,IAGA,WAAW,GAAG,0EAA0E,SAAS;AAAA,IAChG,GAAG;AAAA,EAAA;AACN,CACD;AACD,iBAAiB,cAAcA,gBAAe,YAAY;AAInD,MAAM,YAAY;AAAA,EACvB,WAAW;AAAA,EACX,QAAQ;AAAA;AAAA,EACR,UAAU,CAAA;AAAA,EAGV,OAAO,CAAA;AAAA,EAGP,QAAQ,CAAC,WAAW,SAAS,UAAU,iBAAiB,UAAU;AAAA,EAClE,QAAQ;AAAA,IACN,IAAI,CAAC,mBAAmB;AAAA,IACxB,IAAI,CAAC,qBAAqB,iBAAiB;AAAA,IAC3C,MAAM,CAAA;AAAA,EAAC;AAEX;"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { type VariantProps } from "class-variance-authority";
|
|
3
3
|
import type { LucideIcon } from "lucide-react";
|
|
4
|
-
import { TooltipContent } from "
|
|
5
|
-
import { type RowSize, type InlineActionConfig } from "
|
|
4
|
+
import { TooltipContent } from "../../components/Tooltip/tooltip";
|
|
5
|
+
import { type RowSize, type InlineActionConfig } from "../../patterns/element-anatomy/item-anatomy";
|
|
6
6
|
type SidebarSize = RowSize;
|
|
7
7
|
type SidebarContextProps = {
|
|
8
8
|
state: "expanded" | "collapsed";
|
|
@@ -64,8 +64,8 @@ declare const Sidebar: React.ForwardRefExoticComponent<Omit<React.ClassAttribute
|
|
|
64
64
|
*/
|
|
65
65
|
viewportInsetTop?: string;
|
|
66
66
|
}, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
67
|
-
declare const SidebarTrigger: React.ForwardRefExoticComponent<Omit<import("
|
|
68
|
-
declare const SidebarInput: React.ForwardRefExoticComponent<Omit<import("
|
|
67
|
+
declare const SidebarTrigger: React.ForwardRefExoticComponent<Omit<import("../../components/Button/button").ButtonProps & React.RefAttributes<HTMLButtonElement>, "ref"> & React.RefAttributes<HTMLButtonElement>>;
|
|
68
|
+
declare const SidebarInput: React.ForwardRefExoticComponent<Omit<import("../../components/Input/input").InputProps & React.RefAttributes<HTMLInputElement>, "ref"> & React.RefAttributes<HTMLInputElement>>;
|
|
69
69
|
declare const SidebarHeader: React.ForwardRefExoticComponent<Omit<React.ClassAttributes<HTMLDivElement> & React.HTMLAttributes<HTMLDivElement> & {
|
|
70
70
|
withTabs?: boolean;
|
|
71
71
|
tabsSlot?: React.ReactNode;
|
|
@@ -152,7 +152,7 @@ declare const SidebarMenuAction: React.ForwardRefExoticComponent<Omit<React.Clas
|
|
|
152
152
|
asChild?: boolean;
|
|
153
153
|
showOnHover?: boolean;
|
|
154
154
|
}, "ref"> & React.RefAttributes<HTMLButtonElement>>;
|
|
155
|
-
declare const SidebarMenuBadge: React.ForwardRefExoticComponent<Omit<import("
|
|
155
|
+
declare const SidebarMenuBadge: React.ForwardRefExoticComponent<Omit<import("../../components/Badge/badge").BadgeProps & React.RefAttributes<HTMLSpanElement>, "ref"> & React.RefAttributes<HTMLSpanElement>>;
|
|
156
156
|
declare const SidebarMenuSkeleton: React.ForwardRefExoticComponent<Omit<React.ClassAttributes<HTMLDivElement> & React.HTMLAttributes<HTMLDivElement> & {
|
|
157
157
|
showIcon?: boolean;
|
|
158
158
|
} & VariantProps<(props?: ({
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import * as SwitchPrimitives from '@radix-ui/react-switch';
|
|
3
3
|
import { type VariantProps } from 'class-variance-authority';
|
|
4
|
-
import type { FieldMode, FieldVariant } from '
|
|
4
|
+
import type { FieldMode, FieldVariant } from '../../components/Field/field-types';
|
|
5
5
|
/**
|
|
6
6
|
* Switch — 開關控件
|
|
7
7
|
*
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { type VariantProps } from 'class-variance-authority';
|
|
3
|
-
import type { FieldMode, FieldVariant } from '
|
|
3
|
+
import type { FieldMode, FieldVariant } from '../../components/Field/field-types';
|
|
4
4
|
/**
|
|
5
5
|
* Textarea — 多行文字輸入
|
|
6
6
|
*
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import type { LucideIcon } from 'lucide-react';
|
|
3
|
-
import type { FieldMode, FieldVariant } from '
|
|
4
|
-
import { type TimeParts, type TimeStep } from '
|
|
3
|
+
import type { FieldMode, FieldVariant } from '../../components/Field/field-types';
|
|
4
|
+
import { type TimeParts, type TimeStep } from '../../components/TimePicker/time-columns';
|
|
5
5
|
/**
|
|
6
6
|
* TimePicker — 單一時間(時/分/秒)輸入與顯示元件
|
|
7
7
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"time-picker.js","sources":["../../../src/components/TimePicker/time-picker.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 { X, Clock } from 'lucide-react'\nimport type { LucideIcon } from 'lucide-react'\nimport { cn } from '@/lib/utils'\nimport type { FieldMode, FieldVariant } from '@/design-system/components/Field/field-types'\nimport {\n fieldWrapperStyles,\n bareInputStyles,\n EMPTY_DISPLAY,\n fieldDisplayTextClass,\n} from '@/design-system/components/Field/field-wrapper'\nimport { ItemInlineAction, ItemSuffix } from '@/design-system/patterns/element-anatomy/item-anatomy'\nimport { Popover, PopoverTrigger, PopoverContent } from '@/design-system/components/Popover/popover'\nimport { useFieldContext } from '@/design-system/components/Field/field-context'\nimport { Button } from '@/design-system/components/Button/button'\nimport {\n TimeColumns,\n isoToTimeParts,\n timePartsToString,\n type TimeParts,\n type TimeStep,\n type TimeColumnsDisabled,\n} from '@/design-system/components/TimePicker/time-columns'\nimport { ICON_SIZE } from '@/design-system/tokens/uiSize/icon-size'\n\n/**\n * TimePicker — 單一時間(時/分/秒)輸入與顯示元件\n *\n * ── 定位(同 DatePicker 家族)──\n * Value 以 ISO time string 儲存(\"HH:mm\" 或 \"HH:mm:ss\"),local-time 語義(不帶時區)。\n * Edit 用本 DS 自建 time column panel + Popover 呈現,視覺與 DatePicker 一致。\n * Display 用 Intl.DateTimeFormat 格式化(跨 locale / 12h-24h 統一經過此 API)。\n *\n * ── Layout Family ──\n * CLAUDE.md 4-Family Model Family 4(Field control layout)消費者。結構繼承\n * `fieldWrapperStyles + [<editable>] [endIcon=Clock]`,視覺對齊 DatePicker(同\n * 「點擊觸發浮層」role:indicator 在 suffix slot,對齊 Material `endAdornment` /\n * Ant DatePicker / Polaris Picker 共識)。\n *\n * ── 實作基礎 ──\n * Trigger:`<button>` + `fieldWrapperStyles`(視覺仍是 Input wrapper,改為可點擊觸發浮層)\n * Popup:`Popover`(消費 overlay-surface pattern)\n * Panel 主體:自建 column picker(三欄 scrollable list),不引入第三方 time library\n *\n * ── 共用規則 ──\n * Mode / size / disabled / error 等詳見 `../Field/field-controls.spec.md`。\n */\n\n// ── Time ISO <-> parts conversion ───────────────────────────────────────────\n// Value 用 ISO time string(HH:mm 或 HH:mm:ss),local-time 語義(不帶時區/日期)。\n// 跟 DatePicker 的 ISO date string 策略一致。\n// `isoToTimeParts` / `timePartsToString` 改 import from time-columns(M17 SSOT)。\n\n// ── Display formatting ──────────────────────────────────────────────────────\n\nexport interface TimeFormatOptions {\n /** Intl.DateTimeFormat options(預設 { hour: '2-digit', minute: '2-digit', hour12: false }) */\n formatOptions?: Intl.DateTimeFormatOptions\n /** locale(預設 'en-US') */\n locale?: string\n}\n\nfunction formatTime(\n iso: string,\n options: TimeFormatOptions = {},\n): string {\n const parts = isoToTimeParts(iso)\n if (!parts) return iso\n const {\n formatOptions = { hour: '2-digit', minute: '2-digit', hour12: false },\n locale = 'en-US',\n } = options\n // 借用 Date 讓 Intl.DateTimeFormat 處理 locale / 12h-24h\n const d = new Date()\n d.setHours(parts.hours, parts.minutes, parts.seconds, 0)\n return new Intl.DateTimeFormat(locale, formatOptions).format(d)\n}\n\n// ── Disabled time callback ──────────────────────────────────────────────────\n// `Step` / `buildRange` / `TimeColumn`(內部欄位實作)拔掉,改 import `TimeColumns` primitive。\n\n// code-quality-allow: dead-export — public API surface — consumer-exposed for future use\nexport interface DisabledTimeResult {\n disabledHours?: number[]\n disabledMinutes?: number[]\n disabledSeconds?: number[]\n}\n\n// ── Component props ─────────────────────────────────────────────────────────\n\nexport interface TimePickerProps\n extends TimeFormatOptions,\n Omit<\n React.HTMLAttributes<HTMLDivElement>,\n 'onChange' | 'placeholder'\n > {\n mode?: FieldMode\n /** Field chrome variant. Default = context.variant ?? 'default'. Per-prop override. */\n variant?: FieldVariant\n error?: boolean\n size?: 'sm' | 'md' | 'lg'\n /** ISO time string(\"HH:mm\" 或 \"HH:mm:ss\") */\n value?: string | null\n onChange?: (value: string) => void\n placeholder?: string\n className?: string\n disabled?: boolean\n /** 允許清空已選值 */\n clearable?: boolean\n /**\n * 是否顯示秒欄(三欄 picker)。預設 false(兩欄:時/分)。\n * format 自動對應:false → \"HH:mm\",true → \"HH:mm:ss\"。\n */\n showSeconds?: boolean\n /** 分鐘步進(會議常用 15)。預設 1 */\n minuteStep?: TimeStep\n /** 秒步進。預設 1。僅 showSeconds=true 有效 */\n secondStep?: TimeStep\n /** 動態 disabled 某些時/分/秒(基於已選其他欄位)。 */\n disabledTime?: (parts: TimeParts) => DisabledTimeResult\n /**\n * Suffix indicator(2026-05-05 v9 canonical fix):「點擊觸發浮層」indicator 一律 suffix\n * (對齊 DatePicker calendar / Material endAdornment)。預設 Clock,傳 null 可關閉。\n */\n endIcon?: LucideIcon | null\n /**\n * Display 是否渲 endIcon + Field naked wrapper(D-path opt-in,2026-05-08)\n * — DataTable cell display↔edit 像素級對齊用。預設 false(裸 span,backward compat)。\n * 設 true 時 display 也走 fieldWrapperStyles(naked variant)+ ItemSuffix Clock,\n * 與 edit 同 DOM 結構,消除 Layer-B padding mismatch。\n */\n showDisplayEndIcon?: boolean\n /** Initial open state(uncontrolled)— DataTable cell-as-input 1-step open canonical */\n defaultOpen?: boolean\n /** open state 變更 callback。DataTable cell-as-input 用:open=false → cell exit edit */\n onOpenChange?: (open: boolean) => void\n}\n\n// code-quality-allow: long-function — foundational composite main body — 拆 sub-fn 會複雜化 local state / ref / context binding\nconst TimePicker = React.forwardRef<HTMLDivElement, TimePickerProps>(\n (\n {\n mode = 'edit',\n variant: variantProp,\n error: errorProp = false,\n size = 'md',\n value,\n onChange,\n placeholder,\n className,\n disabled: disabledProp,\n clearable = false,\n showSeconds = false,\n minuteStep = 1,\n secondStep = 1,\n disabledTime,\n endIcon,\n showDisplayEndIcon = false,\n formatOptions,\n locale,\n defaultOpen = false,\n onOpenChange,\n id: idProp,\n 'aria-describedby': ariaDescribedByProp,\n 'aria-errormessage': ariaErrorMessageProp,\n ...props\n },\n ref,\n ) => {\n const fieldCtx = useFieldContext()\n const error = errorProp || (fieldCtx?.invalid ?? false)\n const disabled = disabledProp ?? fieldCtx?.disabled\n const resolvedMode = disabled ? 'disabled' : mode\n const variant: FieldVariant = variantProp ?? fieldCtx?.variant ?? 'default'\n const isEditable = resolvedMode === 'edit'\n // 2026-05-18 改 import ICON_SIZE SSOT(per user『做完』approval,消除 M17 違反 7+ 重複 ternary)\n const iconSize = ICON_SIZE[size as 'sm' | 'md' | 'lg']\n const EndIconCmp: LucideIcon | null =\n endIcon === null ? null : (endIcon ?? Clock)\n const defaultPlaceholder = showSeconds ? 'HH:MM:SS' : 'HH:MM'\n const resolvedPlaceholder = placeholder ?? defaultPlaceholder\n const showClear = clearable && !!value && isEditable\n const [open, setOpenState] = React.useState(defaultOpen)\n const setOpen = React.useCallback((next: boolean) => { setOpenState(next); onOpenChange?.(next) }, [onOpenChange])\n\n const currentParts = React.useMemo(() => isoToTimeParts(value), [value])\n // draft 僅在 panel 開啟時用來處理 commit(OK button)的暫存\n const [draft, setDraft] = React.useState<TimeParts>(\n () => currentParts ?? { hours: 0, minutes: 0, seconds: 0 },\n )\n\n // 每次 popover 開啟時以當前 value 初始化 draft\n React.useEffect(() => {\n if (open) {\n setDraft(currentParts ?? { hours: 0, minutes: 0, seconds: 0 })\n }\n }, [open, currentParts])\n\n const disabledForColumns: TimeColumnsDisabled | undefined = React.useMemo(() => {\n if (!disabledTime) return undefined\n const res = disabledTime(draft)\n return {\n hours: res.disabledHours,\n minutes: res.disabledMinutes,\n seconds: res.disabledSeconds,\n }\n }, [disabledTime, draft])\n\n const commitDraft = (next: TimeParts) => {\n setDraft(next)\n onChange?.(timePartsToString(next, showSeconds))\n }\n\n const handleNow = () => {\n const now = new Date()\n // 按照 minuteStep / secondStep 對齊\n const m = Math.round(now.getMinutes() / minuteStep) * minuteStep\n const s = showSeconds\n ? Math.round(now.getSeconds() / secondStep) * secondStep\n : 0\n const next: TimeParts = {\n hours: now.getHours(),\n minutes: Math.min(m, 59),\n seconds: Math.min(s, 59),\n }\n commitDraft(next)\n setOpen(false)\n }\n\n // mode='display'(Phase B2 2026-05-05):純內容輸出 — 對齊原 TimePickerDisplay sub-component(retired)。\n // Default(showDisplayEndIcon=false):無 Field wrapper / 無 Clock icon — backward compat 裸 span。\n // Opt-in(showDisplayEndIcon=true,2026-05-08 D-path):Field naked wrapper + ItemSuffix Clock,\n // 與 edit 同結構消除 cell display↔edit 像素偏移(Layer-B padding mismatch)。\n if (resolvedMode === 'display') {\n if (!showDisplayEndIcon) {\n // 2026-05-14 I2 fix(spec contract (e) display typography canonical):bare span 套\n // `fieldDisplayTextClass(size)`(sm/md→text-body,lg→text-body-lg)— 對齊 Field family 統一。\n if (!value) return <span className={cn(fieldDisplayTextClass(size), 'text-fg-muted', className)}>{EMPTY_DISPLAY}</span>\n return <span className={cn(fieldDisplayTextClass(size), 'truncate', className)}>{formatTime(value, { formatOptions, locale })}</span>\n }\n return (\n <div\n className={cn(fieldWrapperStyles({ mode: 'display', variant, size }), className)}\n data-field-mode=\"display\"\n >\n <span className={cn(bareInputStyles, 'flex-1 min-w-0 truncate', !value && 'text-fg-muted')}>\n {value ? formatTime(value, { formatOptions, locale }) : EMPTY_DISPLAY}\n </span>\n {EndIconCmp && (\n <ItemSuffix className=\"pointer-events-none\">\n <EndIconCmp size={iconSize} className=\"text-fg-muted\" aria-hidden />\n </ItemSuffix>\n )}\n </div>\n )\n }\n\n // readonly / disabled\n if (!isEditable) {\n return (\n <div\n className={cn(fieldWrapperStyles({ mode: resolvedMode, variant: variant, size }), className)}\n data-field-mode={resolvedMode}\n {...(props as React.HTMLAttributes<HTMLDivElement>)}\n >\n <span\n className={cn(\n 'flex-1 min-w-0',\n resolvedMode === 'disabled' && 'text-fg-disabled',\n )}\n >\n {value\n ? formatTime(value, { formatOptions, locale })\n : <span className=\"text-fg-muted\">{EMPTY_DISPLAY}</span>\n }\n </span>\n {EndIconCmp && (\n <ItemSuffix className=\"pointer-events-none\">\n <EndIconCmp\n size={iconSize}\n className={resolvedMode === 'disabled' ? 'text-fg-disabled' : 'text-fg-muted'}\n aria-hidden\n />\n </ItemSuffix>\n )}\n </div>\n )\n }\n\n const displayText = value\n ? formatTime(value, { formatOptions, locale })\n : <span className=\"text-fg-muted\">{resolvedPlaceholder}</span>\n\n return (\n <Popover open={open} onOpenChange={setOpen}>\n <PopoverTrigger asChild>\n {/* a11y(2026-04-25 nested-interactive fix):trigger 改 <div role='combobox'>\n (對齊 Select / Combobox 同 pattern),原 <button> 會與內層 ItemInlineAction\n 清除 button 構成 nested-interactive。Radix Popover 在 trigger asChild 下會\n 自動 inject keyboard handler(Enter / Space 開啟)+ 正確 aria attributes。 */}\n <div\n ref={ref}\n id={idProp ?? fieldCtx?.id}\n role=\"combobox\"\n tabIndex={disabled ? -1 : 0}\n aria-disabled={disabled || undefined}\n aria-labelledby={fieldCtx?.labelId}\n aria-invalid={error || undefined}\n aria-required={fieldCtx?.required || undefined}\n aria-describedby={ariaDescribedByProp ?? fieldCtx?.descriptionId}\n aria-errormessage={ariaErrorMessageProp ?? (error ? fieldCtx?.errorId : undefined)}\n aria-haspopup=\"dialog\"\n aria-expanded={open}\n data-field-mode=\"edit\"\n data-error={error ? '' : undefined}\n className={cn(\n fieldWrapperStyles({ mode: 'edit', variant: variant, size }),\n 'text-left cursor-pointer',\n 'focus-visible:outline-none',\n error && [\n 'border-error hover:border-error-hover',\n 'focus-within:border-error focus-within:hover:border-error',\n ],\n className,\n )}\n {...props}\n >\n <span className={cn(bareInputStyles, 'truncate', !value && 'text-fg-muted')}>\n {displayText}\n </span>\n {showClear && (\n <ItemInlineAction\n size={size ?? 'md'}\n action={{\n icon: X,\n label: '清除時間', // i18n-allow: DS default inline-action label\n onClick: (e) => {\n e?.stopPropagation()\n onChange?.('')\n },\n }}\n />\n )}\n {EndIconCmp && (\n <ItemSuffix className=\"pointer-events-none\">\n <EndIconCmp size={iconSize} className=\"text-fg-muted\" aria-hidden />\n </ItemSuffix>\n )}\n </div>\n </PopoverTrigger>\n <PopoverContent className=\"w-auto p-0\" align=\"start\">\n {/* Panel 對齊 ref/timepicker.png:2-3 個 SelectMenu 式欄位並排,分隔線分開。\n Width 依欄數由 TimeColumns 決定:2 欄 w-40 / 3 欄 w-60。\n Height 由 wrapper 控:216px 預設(~7 items)。\n TimeColumns 本身 h-full,parent 控 height — 讓 DatePicker showTime / Range 可\n 用 flex-row items-stretch 自動同 calendar 高。 */}\n <div className=\"flex flex-col h-[216px]\">\n <TimeColumns\n value={draft}\n onChange={commitDraft}\n showSeconds={showSeconds}\n minuteStep={minuteStep}\n secondStep={secondStep}\n disabled={disabledForColumns}\n // 2026-05-06 v9.1 M25 chain fix:TimeColumns 自然高 = 24 buttons × ~28.7px = 688px\n // 會撐破 parent h-[216px]。flex-1 + min-h-0 讓 TimeColumns 取 parent 剩餘空間\n // (216 - footer 40 = 176px)→ ScrollArea h-full 才能正確收斂 →\n // listbox scrollIntoView 找對 nearest scrollable ancestor(內部 viewport),\n // 不會走到 document body 把 popover 內容推出畫面(user 報「hours 欄空白」根因)。\n className=\"flex-1 min-h-0\"\n />\n {/* Footer:Now + OK */}\n <div\n className={cn(\n 'flex items-center justify-between gap-2',\n 'border-t border-divider',\n 'px-[var(--layout-space-tight)] py-[var(--layout-space-tight)]',\n )}\n >\n <Button variant=\"text\" size=\"sm\" onClick={handleNow}>\n 此刻\n </Button>\n <Button\n variant=\"primary\"\n size=\"sm\"\n onClick={() => setOpen(false)}\n >\n 確定\n </Button>\n </div>\n </div>\n </PopoverContent>\n </Popover>\n )\n },\n)\nTimePicker.displayName = 'TimePicker'\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 timePickerMeta = {\n component: 'TimePicker',\n family: 4,\n variants: {\n\n },\n sizes: {\n\n },\n states: ['default', 'hover', 'active', 'focus-visible', 'disabled'],\n tokens: {\n bg: ['bg-neutral-hover', 'bg-primary', 'bg-transparent'],\n fg: ['text-fg-disabled', 'text-fg-muted', 'text-foreground'],\n ring: [],\n },\n} as const\n\nexport { TimePicker }\n"],"names":[],"mappings":";;;;;;;;;;AA+DA,SAAS,WACP,KACA,UAA6B,IACrB;AACR,QAAM,QAAQ,eAAe,GAAG;AAChC,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM;AAAA,IACJ,gBAAgB,EAAE,MAAM,WAAW,QAAQ,WAAW,QAAQ,MAAA;AAAA,IAC9D,SAAS;AAAA,EAAA,IACP;AAEJ,QAAM,wBAAQ,KAAA;AACd,IAAE,SAAS,MAAM,OAAO,MAAM,SAAS,MAAM,SAAS,CAAC;AACvD,SAAO,IAAI,KAAK,eAAe,QAAQ,aAAa,EAAE,OAAO,CAAC;AAChE;AA+DA,MAAM,aAAa,MAAM;AAAA,EACvB,CACE;AAAA,IACE,OAAO;AAAA,IACP,SAAS;AAAA,IACT,OAAO,YAAY;AAAA,IACnB,OAAO;AAAA,IACP;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,aAAa;AAAA,IACb,aAAa;AAAA,IACb;AAAA,IACA;AAAA,IACA,qBAAqB;AAAA,IACrB;AAAA,IACA;AAAA,IACA,cAAc;AAAA,IACd;AAAA,IACA,IAAI;AAAA,IACJ,oBAAoB;AAAA,IACpB,qBAAqB;AAAA,IACrB,GAAG;AAAA,EAAA,GAEL,QACG;AACH,UAAM,WAAW,gBAAA;AACjB,UAAM,QAAQ,eAAc,qCAAU,YAAW;AACjD,UAAM,WAAW,iBAAgB,qCAAU;AAC3C,UAAM,eAAe,WAAW,aAAa;AAC7C,UAAM,UAAwB,gBAAe,qCAAU,YAAW;AAClE,UAAM,aAAa,iBAAiB;AAEtC,UAAM,WAAW,UAAU,IAA0B;AACnD,UAAM,aACJ,YAAY,OAAO,OAAQ,WAAW;AACxC,UAAM,qBAAqB,cAAc,aAAa;AACtD,UAAM,sBAAsB,eAAe;AAC3C,UAAM,YAAY,aAAa,CAAC,CAAC,SAAS;AAC1C,UAAM,CAAC,MAAM,YAAY,IAAI,MAAM,SAAS,WAAW;AACvD,UAAM,UAAU,MAAM,YAAY,CAAC,SAAkB;AAAE,mBAAa,IAAI;AAAG,mDAAe;AAAA,IAAM,GAAG,CAAC,YAAY,CAAC;AAEjH,UAAM,eAAe,MAAM,QAAQ,MAAM,eAAe,KAAK,GAAG,CAAC,KAAK,CAAC;AAEvE,UAAM,CAAC,OAAO,QAAQ,IAAI,MAAM;AAAA,MAC9B,MAAM,gBAAgB,EAAE,OAAO,GAAG,SAAS,GAAG,SAAS,EAAA;AAAA,IAAE;AAI3D,UAAM,UAAU,MAAM;AACpB,UAAI,MAAM;AACR,iBAAS,gBAAgB,EAAE,OAAO,GAAG,SAAS,GAAG,SAAS,GAAG;AAAA,MAC/D;AAAA,IACF,GAAG,CAAC,MAAM,YAAY,CAAC;AAEvB,UAAM,qBAAsD,MAAM,QAAQ,MAAM;AAC9E,UAAI,CAAC,aAAc,QAAO;AAC1B,YAAM,MAAM,aAAa,KAAK;AAC9B,aAAO;AAAA,QACL,OAAO,IAAI;AAAA,QACX,SAAS,IAAI;AAAA,QACb,SAAS,IAAI;AAAA,MAAA;AAAA,IAEjB,GAAG,CAAC,cAAc,KAAK,CAAC;AAExB,UAAM,cAAc,CAAC,SAAoB;AACvC,eAAS,IAAI;AACb,2CAAW,kBAAkB,MAAM,WAAW;AAAA,IAChD;AAEA,UAAM,YAAY,MAAM;AACtB,YAAM,0BAAU,KAAA;AAEhB,YAAM,IAAI,KAAK,MAAM,IAAI,WAAA,IAAe,UAAU,IAAI;AACtD,YAAM,IAAI,cACN,KAAK,MAAM,IAAI,eAAe,UAAU,IAAI,aAC5C;AACJ,YAAM,OAAkB;AAAA,QACtB,OAAO,IAAI,SAAA;AAAA,QACX,SAAS,KAAK,IAAI,GAAG,EAAE;AAAA,QACvB,SAAS,KAAK,IAAI,GAAG,EAAE;AAAA,MAAA;AAEzB,kBAAY,IAAI;AAChB,cAAQ,KAAK;AAAA,IACf;AAMA,QAAI,iBAAiB,WAAW;AAC9B,UAAI,CAAC,oBAAoB;AAGvB,YAAI,CAAC,MAAO,QAAO,oBAAC,QAAA,EAAK,WAAW,GAAG,sBAAsB,IAAI,GAAG,iBAAiB,SAAS,GAAI,UAAA,cAAA,CAAc;AAChH,mCAAQ,QAAA,EAAK,WAAW,GAAG,sBAAsB,IAAI,GAAG,YAAY,SAAS,GAAI,qBAAW,OAAO,EAAE,eAAe,OAAA,CAAQ,GAAE;AAAA,MAChI;AACA,aACE;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,WAAW,GAAG,mBAAmB,EAAE,MAAM,WAAW,SAAS,MAAM,GAAG,SAAS;AAAA,UAC/E,mBAAgB;AAAA,UAEhB,UAAA;AAAA,YAAA,oBAAC,UAAK,WAAW,GAAG,iBAAiB,2BAA2B,CAAC,SAAS,eAAe,GACtF,UAAA,QAAQ,WAAW,OAAO,EAAE,eAAe,OAAA,CAAQ,IAAI,eAC1D;AAAA,YACC,cACC,oBAAC,YAAA,EAAW,WAAU,uBACpB,UAAA,oBAAC,YAAA,EAAW,MAAM,UAAU,WAAU,iBAAgB,eAAW,MAAC,EAAA,CACpE;AAAA,UAAA;AAAA,QAAA;AAAA,MAAA;AAAA,IAIR;AAGA,QAAI,CAAC,YAAY;AACf,aACE;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,WAAW,GAAG,mBAAmB,EAAE,MAAM,cAAc,SAAkB,MAAM,GAAG,SAAS;AAAA,UAC3F,mBAAiB;AAAA,UAChB,GAAI;AAAA,UAEL,UAAA;AAAA,YAAA;AAAA,cAAC;AAAA,cAAA;AAAA,gBACC,WAAW;AAAA,kBACT;AAAA,kBACA,iBAAiB,cAAc;AAAA,gBAAA;AAAA,gBAGhC,UAAA,QACG,WAAW,OAAO,EAAE,eAAe,OAAA,CAAQ,IAC3C,oBAAC,QAAA,EAAK,WAAU,iBAAiB,UAAA,cAAA,CAAc;AAAA,cAAA;AAAA,YAAA;AAAA,YAGpD,cACC,oBAAC,YAAA,EAAW,WAAU,uBACpB,UAAA;AAAA,cAAC;AAAA,cAAA;AAAA,gBACC,MAAM;AAAA,gBACN,WAAW,iBAAiB,aAAa,qBAAqB;AAAA,gBAC9D,eAAW;AAAA,cAAA;AAAA,YAAA,EACb,CACF;AAAA,UAAA;AAAA,QAAA;AAAA,MAAA;AAAA,IAIR;AAEA,UAAM,cAAc,QAChB,WAAW,OAAO,EAAE,eAAe,OAAA,CAAQ,IAC3C,oBAAC,QAAA,EAAK,WAAU,iBAAiB,UAAA,qBAAoB;AAEzD,WACE,qBAAC,SAAA,EAAQ,MAAY,cAAc,SACjC,UAAA;AAAA,MAAA,oBAAC,gBAAA,EAAe,SAAO,MAKrB,UAAA;AAAA,QAAC;AAAA,QAAA;AAAA,UACC;AAAA,UACA,IAAI,WAAU,qCAAU;AAAA,UACxB,MAAK;AAAA,UACL,UAAU,WAAW,KAAK;AAAA,UAC1B,iBAAe,YAAY;AAAA,UAC3B,mBAAiB,qCAAU;AAAA,UAC3B,gBAAc,SAAS;AAAA,UACvB,kBAAe,qCAAU,aAAY;AAAA,UACrC,oBAAkB,wBAAuB,qCAAU;AAAA,UACnD,qBAAmB,yBAAyB,QAAQ,qCAAU,UAAU;AAAA,UACxE,iBAAc;AAAA,UACd,iBAAe;AAAA,UACf,mBAAgB;AAAA,UAChB,cAAY,QAAQ,KAAK;AAAA,UACzB,WAAW;AAAA,YACT,mBAAmB,EAAE,MAAM,QAAQ,SAAkB,MAAM;AAAA,YAC3D;AAAA,YACA;AAAA,YACA,SAAS;AAAA,cACP;AAAA,cACA;AAAA,YAAA;AAAA,YAEF;AAAA,UAAA;AAAA,UAED,GAAG;AAAA,UAEJ,UAAA;AAAA,YAAA,oBAAC,QAAA,EAAK,WAAW,GAAG,iBAAiB,YAAY,CAAC,SAAS,eAAe,GACvE,UAAA,YAAA,CACH;AAAA,YACC,aACC;AAAA,cAAC;AAAA,cAAA;AAAA,gBACC,MAAM,QAAQ;AAAA,gBACd,QAAQ;AAAA,kBACN,MAAM;AAAA,kBACN,OAAO;AAAA;AAAA,kBACP,SAAS,CAAC,MAAM;AACd,2CAAG;AACH,yDAAW;AAAA,kBACb;AAAA,gBAAA;AAAA,cACF;AAAA,YAAA;AAAA,YAGH,cACC,oBAAC,YAAA,EAAW,WAAU,uBACpB,UAAA,oBAAC,YAAA,EAAW,MAAM,UAAU,WAAU,iBAAgB,eAAW,MAAC,EAAA,CACpE;AAAA,UAAA;AAAA,QAAA;AAAA,MAAA,GAGN;AAAA,MACA,oBAAC,kBAAe,WAAU,cAAa,OAAM,SAM3C,UAAA,qBAAC,OAAA,EAAI,WAAU,2BACb,UAAA;AAAA,QAAA;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,OAAO;AAAA,YACP,UAAU;AAAA,YACV;AAAA,YACA;AAAA,YACA;AAAA,YACA,UAAU;AAAA,YAMV,WAAU;AAAA,UAAA;AAAA,QAAA;AAAA,QAGZ;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,WAAW;AAAA,cACT;AAAA,cACA;AAAA,cACA;AAAA,YAAA;AAAA,YAGF,UAAA;AAAA,cAAA,oBAAC,UAAO,SAAQ,QAAO,MAAK,MAAK,SAAS,WAAW,UAAA,KAAA,CAErD;AAAA,cACA;AAAA,gBAAC;AAAA,gBAAA;AAAA,kBACC,SAAQ;AAAA,kBACR,MAAK;AAAA,kBACL,SAAS,MAAM,QAAQ,KAAK;AAAA,kBAC7B,UAAA;AAAA,gBAAA;AAAA,cAAA;AAAA,YAED;AAAA,UAAA;AAAA,QAAA;AAAA,MACF,EAAA,CACF,EAAA,CACF;AAAA,IAAA,GACF;AAAA,EAEJ;AACF;AACA,WAAW,cAAc;AAIlB,MAAM,iBAAiB;AAAA,EAC5B,WAAW;AAAA,EACX,QAAQ;AAAA,EACR,UAAU,CAAA;AAAA,EAGV,OAAO,CAAA;AAAA,EAGP,QAAQ,CAAC,WAAW,SAAS,UAAU,iBAAiB,UAAU;AAAA,EAClE,QAAQ;AAAA,IACN,IAAI,CAAC,oBAAoB,cAAc,gBAAgB;AAAA,IACvD,IAAI,CAAC,oBAAoB,iBAAiB,iBAAiB;AAAA,IAC3D,MAAM,CAAA;AAAA,EAAC;AAEX;"}
|
|
1
|
+
{"version":3,"file":"time-picker.js","sources":["../../../src/components/TimePicker/time-picker.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 { X, Clock } from 'lucide-react'\nimport type { LucideIcon } from 'lucide-react'\nimport { cn } from '@/lib/utils'\nimport type { FieldMode, FieldVariant } from '@/design-system/components/Field/field-types'\nimport {\n fieldWrapperStyles,\n bareInputStyles,\n EMPTY_DISPLAY,\n fieldDisplayTextClass,\n} from '@/design-system/components/Field/field-wrapper'\nimport { ItemInlineAction, ItemSuffix } from '@/design-system/patterns/element-anatomy/item-anatomy'\nimport { Popover, PopoverTrigger, PopoverContent } from '@/design-system/components/Popover/popover'\nimport { useFieldContext } from '@/design-system/components/Field/field-context'\nimport { Button } from '@/design-system/components/Button/button'\nimport {\n TimeColumns,\n isoToTimeParts,\n timePartsToString,\n type TimeParts,\n type TimeStep,\n type TimeColumnsDisabled,\n} from '@/design-system/components/TimePicker/time-columns'\nimport { ICON_SIZE } from '@/design-system/tokens/uiSize/icon-size'\n\n/**\n * TimePicker — 單一時間(時/分/秒)輸入與顯示元件\n *\n * ── 定位(同 DatePicker 家族)──\n * Value 以 ISO time string 儲存(\"HH:mm\" 或 \"HH:mm:ss\"),local-time 語義(不帶時區)。\n * Edit 用本 DS 自建 time column panel + Popover 呈現,視覺與 DatePicker 一致。\n * Display 用 Intl.DateTimeFormat 格式化(跨 locale / 12h-24h 統一經過此 API)。\n *\n * ── Layout Family ──\n * CLAUDE.md 4-Family Model Family 4(Field control layout)消費者。結構繼承\n * `fieldWrapperStyles + [<editable>] [endIcon=Clock]`,視覺對齊 DatePicker(同\n * 「點擊觸發浮層」role:indicator 在 suffix slot,對齊 Material `endAdornment` /\n * Ant DatePicker / Polaris Picker 共識)。\n *\n * ── 實作基礎 ──\n * Trigger:`<button>` + `fieldWrapperStyles`(視覺仍是 Input wrapper,改為可點擊觸發浮層)\n * Popup:`Popover`(消費 overlay-surface pattern)\n * Panel 主體:自建 column picker(三欄 scrollable list),不引入第三方 time library\n *\n * ── 共用規則 ──\n * Mode / size / disabled / error 等詳見 `../Field/field-controls.spec.md`。\n */\n\n// ── Time ISO <-> parts conversion ───────────────────────────────────────────\n// Value 用 ISO time string(HH:mm 或 HH:mm:ss),local-time 語義(不帶時區/日期)。\n// 跟 DatePicker 的 ISO date string 策略一致。\n// `isoToTimeParts` / `timePartsToString` 改 import from time-columns(M17 SSOT)。\n\n// ── Display formatting ──────────────────────────────────────────────────────\n\nexport interface TimeFormatOptions {\n /** Intl.DateTimeFormat options(預設 { hour: '2-digit', minute: '2-digit', hour12: false }) */\n formatOptions?: Intl.DateTimeFormatOptions\n /** locale(預設 'en-US') */\n locale?: string\n}\n\nfunction formatTime(\n iso: string,\n options: TimeFormatOptions = {},\n): string {\n const parts = isoToTimeParts(iso)\n if (!parts) return iso\n const {\n formatOptions = { hour: '2-digit', minute: '2-digit', hour12: false },\n locale = 'en-US',\n } = options\n // 借用 Date 讓 Intl.DateTimeFormat 處理 locale / 12h-24h\n const d = new Date()\n d.setHours(parts.hours, parts.minutes, parts.seconds, 0)\n return new Intl.DateTimeFormat(locale, formatOptions).format(d)\n}\n\n// ── Disabled time callback ──────────────────────────────────────────────────\n// `Step` / `buildRange` / `TimeColumn`(內部欄位實作)拔掉,改 import `TimeColumns` primitive。\n\n// code-quality-allow: dead-export — public API surface — consumer-exposed for future use\nexport interface DisabledTimeResult {\n disabledHours?: number[]\n disabledMinutes?: number[]\n disabledSeconds?: number[]\n}\n\n// ── Component props ─────────────────────────────────────────────────────────\n\nexport interface TimePickerProps\n extends TimeFormatOptions,\n Omit<\n React.HTMLAttributes<HTMLDivElement>,\n 'onChange' | 'placeholder'\n > {\n mode?: FieldMode\n /** Field chrome variant. Default = context.variant ?? 'default'. Per-prop override. */\n variant?: FieldVariant\n error?: boolean\n size?: 'sm' | 'md' | 'lg'\n /** ISO time string(\"HH:mm\" 或 \"HH:mm:ss\") */\n value?: string | null\n onChange?: (value: string) => void\n placeholder?: string\n className?: string\n disabled?: boolean\n /** 允許清空已選值 */\n clearable?: boolean\n /**\n * 是否顯示秒欄(三欄 picker)。預設 false(兩欄:時/分)。\n * format 自動對應:false → \"HH:mm\",true → \"HH:mm:ss\"。\n */\n showSeconds?: boolean\n /** 分鐘步進(會議常用 15)。預設 1 */\n minuteStep?: TimeStep\n /** 秒步進。預設 1。僅 showSeconds=true 有效 */\n secondStep?: TimeStep\n /** 動態 disabled 某些時/分/秒(基於已選其他欄位)。 */\n disabledTime?: (parts: TimeParts) => DisabledTimeResult\n /**\n * Suffix indicator(2026-05-05 v9 canonical fix):「點擊觸發浮層」indicator 一律 suffix\n * (對齊 DatePicker calendar / Material endAdornment)。預設 Clock,傳 null 可關閉。\n */\n endIcon?: LucideIcon | null\n /**\n * Display 是否渲 endIcon + Field naked wrapper(D-path opt-in,2026-05-08)\n * — DataTable cell display↔edit 像素級對齊用。預設 false(裸 span,backward compat)。\n * 設 true 時 display 也走 fieldWrapperStyles(naked variant)+ ItemSuffix Clock,\n * 與 edit 同 DOM 結構,消除 Layer-B padding mismatch。\n */\n showDisplayEndIcon?: boolean\n /** Initial open state(uncontrolled)— DataTable cell-as-input 1-step open canonical */\n defaultOpen?: boolean\n /** open state 變更 callback。DataTable cell-as-input 用:open=false → cell exit edit */\n onOpenChange?: (open: boolean) => void\n}\n\n// code-quality-allow: long-function — foundational composite main body — 拆 sub-fn 會複雜化 local state / ref / context binding\nconst TimePicker = React.forwardRef<HTMLDivElement, TimePickerProps>(\n (\n {\n mode = 'edit',\n variant: variantProp,\n error: errorProp = false,\n size = 'md',\n value,\n onChange,\n placeholder,\n className,\n disabled: disabledProp,\n clearable = false,\n showSeconds = false,\n minuteStep = 1,\n secondStep = 1,\n disabledTime,\n endIcon,\n showDisplayEndIcon = false,\n formatOptions,\n locale,\n defaultOpen = false,\n onOpenChange,\n id: idProp,\n 'aria-describedby': ariaDescribedByProp,\n 'aria-errormessage': ariaErrorMessageProp,\n ...props\n },\n ref,\n ) => {\n const fieldCtx = useFieldContext()\n const error = errorProp || (fieldCtx?.invalid ?? false)\n const disabled = disabledProp ?? fieldCtx?.disabled\n const resolvedMode = disabled ? 'disabled' : mode\n const variant: FieldVariant = variantProp ?? fieldCtx?.variant ?? 'default'\n const isEditable = resolvedMode === 'edit'\n // 2026-05-18 改 import ICON_SIZE SSOT(per user『做完』approval,消除 M17 違反 7+ 重複 ternary)\n const iconSize = ICON_SIZE[size as 'sm' | 'md' | 'lg']\n const EndIconCmp: LucideIcon | null =\n endIcon === null ? null : (endIcon ?? Clock)\n const defaultPlaceholder = showSeconds ? 'HH:MM:SS' : 'HH:MM'\n const resolvedPlaceholder = placeholder ?? defaultPlaceholder\n const showClear = clearable && !!value && isEditable\n const [open, setOpenState] = React.useState(defaultOpen)\n const setOpen = React.useCallback((next: boolean) => { setOpenState(next); onOpenChange?.(next) }, [onOpenChange])\n\n const currentParts = React.useMemo(() => isoToTimeParts(value), [value])\n // draft 僅在 panel 開啟時用來處理 commit(OK button)的暫存\n const [draft, setDraft] = React.useState<TimeParts>(\n () => currentParts ?? { hours: 0, minutes: 0, seconds: 0 },\n )\n\n // 每次 popover 開啟時以當前 value 初始化 draft\n React.useEffect(() => {\n if (open) {\n setDraft(currentParts ?? { hours: 0, minutes: 0, seconds: 0 })\n }\n }, [open, currentParts])\n\n const disabledForColumns: TimeColumnsDisabled | undefined = React.useMemo(() => {\n if (!disabledTime) return undefined\n const res = disabledTime(draft)\n return {\n hours: res.disabledHours,\n minutes: res.disabledMinutes,\n seconds: res.disabledSeconds,\n }\n }, [disabledTime, draft])\n\n const commitDraft = (next: TimeParts) => {\n setDraft(next)\n onChange?.(timePartsToString(next, showSeconds))\n }\n\n const handleNow = () => {\n const now = new Date()\n // 按照 minuteStep / secondStep 對齊\n const m = Math.round(now.getMinutes() / minuteStep) * minuteStep\n const s = showSeconds\n ? Math.round(now.getSeconds() / secondStep) * secondStep\n : 0\n const next: TimeParts = {\n hours: now.getHours(),\n minutes: Math.min(m, 59),\n seconds: Math.min(s, 59),\n }\n commitDraft(next)\n setOpen(false)\n }\n\n // mode='display'(Phase B2 2026-05-05):純內容輸出 — 對齊原 TimePickerDisplay sub-component(retired)。\n // Default(showDisplayEndIcon=false):無 Field wrapper / 無 Clock icon — backward compat 裸 span。\n // Opt-in(showDisplayEndIcon=true,2026-05-08 D-path):Field naked wrapper + ItemSuffix Clock,\n // 與 edit 同結構消除 cell display↔edit 像素偏移(Layer-B padding mismatch)。\n if (resolvedMode === 'display') {\n if (!showDisplayEndIcon) {\n // 2026-05-14 I2 fix(spec contract (e) display typography canonical):bare span 套\n // `fieldDisplayTextClass(size)`(sm/md→text-body,lg→text-body-lg)— 對齊 Field family 統一。\n if (!value) return <span className={cn(fieldDisplayTextClass(size), 'text-fg-muted', className)}>{EMPTY_DISPLAY}</span>\n return <span className={cn(fieldDisplayTextClass(size), 'truncate', className)}>{formatTime(value, { formatOptions, locale })}</span>\n }\n return (\n <div\n className={cn(fieldWrapperStyles({ mode: 'display', variant, size }), className)}\n data-field-mode=\"display\"\n >\n <span className={cn(bareInputStyles, 'flex-1 min-w-0 truncate', !value && 'text-fg-muted')}>\n {value ? formatTime(value, { formatOptions, locale }) : EMPTY_DISPLAY}\n </span>\n {EndIconCmp && (\n <ItemSuffix className=\"pointer-events-none\">\n <EndIconCmp size={iconSize} className=\"text-fg-muted\" aria-hidden />\n </ItemSuffix>\n )}\n </div>\n )\n }\n\n // readonly / disabled\n if (!isEditable) {\n return (\n <div\n className={cn(fieldWrapperStyles({ mode: resolvedMode, variant: variant, size }), className)}\n data-field-mode={resolvedMode}\n {...(props as React.HTMLAttributes<HTMLDivElement>)}\n >\n <span\n className={cn(\n 'flex-1 min-w-0',\n resolvedMode === 'disabled' && 'text-fg-disabled',\n )}\n >\n {value\n ? formatTime(value, { formatOptions, locale })\n : <span className=\"text-fg-muted\">{EMPTY_DISPLAY}</span>\n }\n </span>\n {EndIconCmp && (\n <ItemSuffix className=\"pointer-events-none\">\n <EndIconCmp\n size={iconSize}\n className={resolvedMode === 'disabled' ? 'text-fg-disabled' : 'text-fg-muted'}\n aria-hidden\n />\n </ItemSuffix>\n )}\n </div>\n )\n }\n\n const displayText = value\n ? formatTime(value, { formatOptions, locale })\n : <span className=\"text-fg-muted\">{resolvedPlaceholder}</span>\n\n return (\n <Popover open={open} onOpenChange={setOpen}>\n {/* a11y(2026-04-25 nested-interactive fix):trigger 改 <div role='combobox'>\n (對齊 Select / Combobox 同 pattern),原 <button> 會與內層 ItemInlineAction\n 清除 button 構成 nested-interactive。Radix Popover 在 trigger asChild 下會\n 自動 inject keyboard handler(Enter / Space 開啟)+ 正確 aria attributes。 */}\n <PopoverTrigger asChild>\n <div\n ref={ref}\n id={idProp ?? fieldCtx?.id}\n role=\"combobox\"\n tabIndex={disabled ? -1 : 0}\n aria-disabled={disabled || undefined}\n aria-labelledby={fieldCtx?.labelId}\n aria-invalid={error || undefined}\n aria-required={fieldCtx?.required || undefined}\n aria-describedby={ariaDescribedByProp ?? fieldCtx?.descriptionId}\n aria-errormessage={ariaErrorMessageProp ?? (error ? fieldCtx?.errorId : undefined)}\n aria-haspopup=\"dialog\"\n aria-expanded={open}\n data-field-mode=\"edit\"\n data-error={error ? '' : undefined}\n className={cn(\n fieldWrapperStyles({ mode: 'edit', variant: variant, size }),\n 'text-left cursor-pointer',\n 'focus-visible:outline-none',\n error && [\n 'border-error hover:border-error-hover',\n 'focus-within:border-error focus-within:hover:border-error',\n ],\n className,\n )}\n {...props}\n >\n <span className={cn(bareInputStyles, 'truncate', !value && 'text-fg-muted')}>\n {displayText}\n </span>\n {showClear && (\n <ItemInlineAction\n size={size ?? 'md'}\n action={{\n icon: X,\n label: '清除時間', // i18n-allow: DS default inline-action label\n onClick: (e) => {\n e?.stopPropagation()\n onChange?.('')\n },\n }}\n />\n )}\n {EndIconCmp && (\n <ItemSuffix className=\"pointer-events-none\">\n <EndIconCmp size={iconSize} className=\"text-fg-muted\" aria-hidden />\n </ItemSuffix>\n )}\n </div>\n </PopoverTrigger>\n <PopoverContent className=\"w-auto p-0\" align=\"start\">\n {/* Panel 對齊 ref/timepicker.png:2-3 個 SelectMenu 式欄位並排,分隔線分開。\n Width 依欄數由 TimeColumns 決定:2 欄 w-40 / 3 欄 w-60。\n Height 由 wrapper 控:216px 預設(~7 items)。\n TimeColumns 本身 h-full,parent 控 height — 讓 DatePicker showTime / Range 可\n 用 flex-row items-stretch 自動同 calendar 高。 */}\n <div className=\"flex flex-col h-[216px]\">\n <TimeColumns\n value={draft}\n onChange={commitDraft}\n showSeconds={showSeconds}\n minuteStep={minuteStep}\n secondStep={secondStep}\n disabled={disabledForColumns}\n // 2026-05-06 v9.1 M25 chain fix:TimeColumns 自然高 = 24 buttons × ~28.7px = 688px\n // 會撐破 parent h-[216px]。flex-1 + min-h-0 讓 TimeColumns 取 parent 剩餘空間\n // (216 - footer 40 = 176px)→ ScrollArea h-full 才能正確收斂 →\n // listbox scrollIntoView 找對 nearest scrollable ancestor(內部 viewport),\n // 不會走到 document body 把 popover 內容推出畫面(user 報「hours 欄空白」根因)。\n className=\"flex-1 min-h-0\"\n />\n {/* Footer:Now + OK */}\n <div\n className={cn(\n 'flex items-center justify-between gap-2',\n 'border-t border-divider',\n 'px-[var(--layout-space-tight)] py-[var(--layout-space-tight)]',\n )}\n >\n <Button variant=\"text\" size=\"sm\" onClick={handleNow}>\n 此刻\n </Button>\n <Button\n variant=\"primary\"\n size=\"sm\"\n onClick={() => setOpen(false)}\n >\n 確定\n </Button>\n </div>\n </div>\n </PopoverContent>\n </Popover>\n )\n },\n)\nTimePicker.displayName = 'TimePicker'\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 timePickerMeta = {\n component: 'TimePicker',\n family: 4,\n variants: {\n\n },\n sizes: {\n\n },\n states: ['default', 'hover', 'active', 'focus-visible', 'disabled'],\n tokens: {\n bg: ['bg-neutral-hover', 'bg-primary', 'bg-transparent'],\n fg: ['text-fg-disabled', 'text-fg-muted', 'text-foreground'],\n ring: [],\n },\n} as const\n\nexport { TimePicker }\n"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import type { LucideIcon } from 'lucide-react';
|
|
3
|
-
import { type InlineActionConfig } from '
|
|
3
|
+
import { type InlineActionConfig } from '../../patterns/element-anatomy/item-anatomy';
|
|
4
4
|
/**
|
|
5
5
|
* TreeView — 階層結構的遞迴元件
|
|
6
6
|
*
|
|
@@ -75,7 +75,7 @@ export interface TreeViewProps extends Omit<React.HTMLAttributes<HTMLDivElement>
|
|
|
75
75
|
}
|
|
76
76
|
declare const TreeView: React.ForwardRefExoticComponent<TreeViewProps & React.RefAttributes<HTMLDivElement>>;
|
|
77
77
|
declare const treeItemVariants: (props?: ({
|
|
78
|
-
size?: import("
|
|
78
|
+
size?: import("../../patterns/element-anatomy/item-anatomy").RowSize | null | undefined;
|
|
79
79
|
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
80
80
|
export interface TreeItemProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'id'> {
|
|
81
81
|
/** 唯一 id。必填,用於 expand / select / keyboard 追蹤 */
|
|
@@ -19,7 +19,7 @@ import * as React from 'react';
|
|
|
19
19
|
*
|
|
20
20
|
* ```tsx
|
|
21
21
|
* // Consumer app root
|
|
22
|
-
* import { I18nProvider } from '
|
|
22
|
+
* import { I18nProvider } from '../../lib/i18n/i18n-context'
|
|
23
23
|
*
|
|
24
24
|
* const labels = {
|
|
25
25
|
* notice: { dismiss: 'Dismiss' },
|
|
@@ -34,7 +34,7 @@ import * as React from 'react';
|
|
|
34
34
|
*
|
|
35
35
|
* ```tsx
|
|
36
36
|
* // DS component internal(opt-in migration)
|
|
37
|
-
* import { useI18n } from '
|
|
37
|
+
* import { useI18n } from '../../lib/i18n/i18n-context'
|
|
38
38
|
*
|
|
39
39
|
* const { t } = useI18n()
|
|
40
40
|
* <button aria-label={props.dismissAriaLabel ?? t('notice', 'dismiss', '關閉通知')}>
|
|
@@ -55,7 +55,7 @@ import * as React from 'react';
|
|
|
55
55
|
* Consumer 可透過 module augmentation 擴充 type safety:
|
|
56
56
|
*
|
|
57
57
|
* ```ts
|
|
58
|
-
* declare module '
|
|
58
|
+
* declare module '../../lib/i18n/i18n-context' {
|
|
59
59
|
* interface I18nLabels {
|
|
60
60
|
* notice?: { dismiss?: string }
|
|
61
61
|
* fileViewer?: { close?: string; download?: string }
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import type { LucideIcon } from "lucide-react";
|
|
3
|
-
import { type AvatarProps } from "
|
|
3
|
+
import { type AvatarProps } from "../../components/Avatar/avatar";
|
|
4
4
|
export interface InlineActionConfig {
|
|
5
5
|
icon: LucideIcon;
|
|
6
6
|
/** aria-label,同時作為 tooltip 來源 */
|
|
@@ -34,7 +34,7 @@ export type RowSize = "sm" | "md" | "lg";
|
|
|
34
34
|
* `>` 直接子選擇器會失效,Lucide icon 會 fallback 到預設 24px。
|
|
35
35
|
*
|
|
36
36
|
* ```tsx
|
|
37
|
-
* import { ICON_SIZE } from "
|
|
37
|
+
* import { ICON_SIZE } from "../../patterns/element-anatomy/item-anatomy"
|
|
38
38
|
*
|
|
39
39
|
* const iconPx = ICON_SIZE[size] // size: RowSize
|
|
40
40
|
* <MyLucideIcon size={iconPx} />
|
|
@@ -54,7 +54,7 @@ export declare const ICON_SIZE: Record<RowSize, number>;
|
|
|
54
54
|
* 硬寫會讓 sm 變體的 avatar 尺寸錯誤、跟 ICON_SIZE 對齊規則脫鉤。
|
|
55
55
|
*
|
|
56
56
|
* ```tsx
|
|
57
|
-
* import { AVATAR_SIZE } from "
|
|
57
|
+
* import { AVATAR_SIZE } from "../../patterns/element-anatomy/item-anatomy"
|
|
58
58
|
*
|
|
59
59
|
* const { size } = useSidebar() // RowSize
|
|
60
60
|
* <Avatar size={AVATAR_SIZE.inline[size]} />
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* end-user app 直接 import 無 functioning UI;由 Tabs / ChipGroup 等 DS 元件 wrap 消費 hook + helper components。
|
|
4
4
|
*/
|
|
5
5
|
import * as React from 'react';
|
|
6
|
-
import { useScrollEdges, useOverflowIndices } from '
|
|
6
|
+
import { useScrollEdges, useOverflowIndices } from '../../hooks/use-overflow-items';
|
|
7
7
|
/**
|
|
8
8
|
* Horizontal Overflow — canonical primitives + helpers
|
|
9
9
|
*
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
*
|
|
22
22
|
* ── Consumer 用法 ──
|
|
23
23
|
* ```tsx
|
|
24
|
-
* import { ICON_SIZE } from '
|
|
24
|
+
* import { ICON_SIZE } from '../../tokens/uiSize/icon-size'
|
|
25
25
|
*
|
|
26
26
|
* // sm/md → 16, lg → 20
|
|
27
27
|
* <LucideIcon size={ICON_SIZE[size]} />
|
|
@@ -48,6 +48,6 @@
|
|
|
48
48
|
*
|
|
49
49
|
* 詳 uiSize.spec.md「跨 regime pointer index」段。
|
|
50
50
|
*/
|
|
51
|
-
export { ICON_SIZE } from '
|
|
52
|
-
export type { RowSize } from '
|
|
51
|
+
export { ICON_SIZE } from '../../patterns/element-anatomy/item-anatomy';
|
|
52
|
+
export type { RowSize } from '../../patterns/element-anatomy/item-anatomy';
|
|
53
53
|
//# sourceMappingURL=icon-size.d.ts.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@qijenchen/design-system",
|
|
3
|
-
"version": "0.1.0-beta.
|
|
3
|
+
"version": "0.1.0-beta.8",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "World-class design system — components, patterns, tokens, hooks (single source of truth for team distribution).",
|
|
6
6
|
"type": "module",
|
|
@@ -22,12 +22,11 @@
|
|
|
22
22
|
"types": "./dist/index.d.ts",
|
|
23
23
|
"import": "./dist/index.js"
|
|
24
24
|
},
|
|
25
|
-
"./tokens/*": "./
|
|
25
|
+
"./tokens/*": "./src/tokens/*",
|
|
26
26
|
"./hooks/*": {
|
|
27
27
|
"types": "./dist/hooks/*.d.ts",
|
|
28
28
|
"import": "./dist/hooks/*.js"
|
|
29
29
|
},
|
|
30
|
-
"./styles/globals.css": "./dist/globals.css",
|
|
31
30
|
"./styles/tokens.css": "./src/styles/tokens.css",
|
|
32
31
|
"./styles/tokens": "./src/styles/tokens.css",
|
|
33
32
|
"./package.json": "./package.json"
|
|
@@ -40,10 +39,13 @@
|
|
|
40
39
|
],
|
|
41
40
|
"scripts": {
|
|
42
41
|
"build": "vite build",
|
|
43
|
-
"build:dts": "tsc -p tsconfig.json",
|
|
42
|
+
"build:dts": "tsc -p tsconfig.json && tsc-alias -p tsconfig.json",
|
|
44
43
|
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
45
44
|
},
|
|
46
45
|
"dependencies": {
|
|
46
|
+
"@dnd-kit/core": "^6.3.1",
|
|
47
|
+
"@dnd-kit/sortable": "^10.0.0",
|
|
48
|
+
"@dnd-kit/utilities": "^3.2.2",
|
|
47
49
|
"@radix-ui/react-accordion": "^1.2.12",
|
|
48
50
|
"@radix-ui/react-aspect-ratio": "^1.1.8",
|
|
49
51
|
"@radix-ui/react-checkbox": "^1.3.3",
|
|
@@ -63,9 +65,6 @@
|
|
|
63
65
|
"@radix-ui/react-toggle": "^1.1.10",
|
|
64
66
|
"@radix-ui/react-toggle-group": "^1.1.11",
|
|
65
67
|
"@radix-ui/react-tooltip": "^1.2.8",
|
|
66
|
-
"@dnd-kit/core": "^6.3.1",
|
|
67
|
-
"@dnd-kit/sortable": "^10.0.0",
|
|
68
|
-
"@dnd-kit/utilities": "^3.2.2",
|
|
69
68
|
"@tanstack/react-table": "^8.21.3",
|
|
70
69
|
"@tanstack/react-virtual": "^3.13.23",
|
|
71
70
|
"class-variance-authority": "^0.7.1",
|
|
@@ -73,7 +72,6 @@
|
|
|
73
72
|
"cmdk": "^1.1.1",
|
|
74
73
|
"date-fns": "^4.1.0",
|
|
75
74
|
"embla-carousel-react": "^8.6.0",
|
|
76
|
-
"lucide-react": "^0.577.0",
|
|
77
75
|
"react-day-picker": "^9.14.0",
|
|
78
76
|
"react-zoom-pan-pinch": "^4.0.3",
|
|
79
77
|
"recharts": "^3.8.1",
|
|
@@ -81,8 +79,12 @@
|
|
|
81
79
|
"tailwind-merge": "^3.5.0"
|
|
82
80
|
},
|
|
83
81
|
"peerDependencies": {
|
|
82
|
+
"lucide-react": ">=0.400.0",
|
|
84
83
|
"react": ">=18.0.0",
|
|
85
84
|
"react-dom": ">=18.0.0",
|
|
86
85
|
"tailwindcss": ">=4.0.0"
|
|
86
|
+
},
|
|
87
|
+
"devDependencies": {
|
|
88
|
+
"tsc-alias": "^1.8.17"
|
|
87
89
|
}
|
|
88
90
|
}
|