@qijenchen/design-system 0.1.0-beta.95 → 0.1.0-beta.96
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/dist/components/Calendar/calendar.d.ts.map +1 -1
- package/dist/components/Calendar/calendar.js +47 -23
- package/dist/components/Calendar/calendar.js.map +1 -1
- package/dist/components/DataTable/cell-registry.d.ts.map +1 -1
- package/dist/components/DataTable/cell-registry.js +1 -5
- package/dist/components/DataTable/cell-registry.js.map +1 -1
- package/dist/components/DataTable/data-table.d.ts.map +1 -1
- package/dist/components/DataTable/data-table.js +3 -2
- package/dist/components/DataTable/data-table.js.map +1 -1
- package/dist/components/DatePicker/date-picker.d.ts.map +1 -1
- package/dist/components/DatePicker/date-picker.js +183 -156
- package/dist/components/DatePicker/date-picker.js.map +1 -1
- package/dist/components/Dialog/dialog.d.ts.map +1 -1
- package/dist/components/Dialog/dialog.js +4 -2
- package/dist/components/Dialog/dialog.js.map +1 -1
- package/dist/components/Field/field-context.d.ts +12 -0
- package/dist/components/Field/field-context.d.ts.map +1 -1
- package/dist/components/Field/field-context.js +10 -1
- package/dist/components/Field/field-context.js.map +1 -1
- package/dist/components/Field/field-wrapper.d.ts.map +1 -1
- package/dist/components/Field/field-wrapper.js +7 -1
- package/dist/components/Field/field-wrapper.js.map +1 -1
- package/dist/components/Field/field.d.ts.map +1 -1
- package/dist/components/Field/field.js +11 -2
- package/dist/components/Field/field.js.map +1 -1
- package/dist/components/InlineEdit/inline-edit.d.ts +5 -0
- package/dist/components/InlineEdit/inline-edit.d.ts.map +1 -1
- package/dist/components/InlineEdit/inline-edit.js +65 -33
- package/dist/components/InlineEdit/inline-edit.js.map +1 -1
- package/dist/components/Input/input.d.ts.map +1 -1
- package/dist/components/Input/input.js +3 -2
- package/dist/components/Input/input.js.map +1 -1
- package/dist/components/LinkInput/link-input.d.ts.map +1 -1
- package/dist/components/LinkInput/link-input.js +2 -1
- package/dist/components/LinkInput/link-input.js.map +1 -1
- package/dist/components/Popover/popover.d.ts.map +1 -1
- package/dist/components/Popover/popover.js +4 -2
- package/dist/components/Popover/popover.js.map +1 -1
- package/dist/components/Select/select.d.ts.map +1 -1
- package/dist/components/Select/select.js +59 -37
- package/dist/components/Select/select.js.map +1 -1
- package/dist/components/Textarea/textarea.d.ts +11 -0
- package/dist/components/Textarea/textarea.d.ts.map +1 -1
- package/dist/components/Textarea/textarea.js +22 -5
- package/dist/components/Textarea/textarea.js.map +1 -1
- package/dist/components/TimePicker/time-picker.d.ts.map +1 -1
- package/dist/components/TimePicker/time-picker.js +4 -3
- package/dist/components/TimePicker/time-picker.js.map +1 -1
- package/dist/patterns/element-anatomy/item-anatomy.d.ts +9 -0
- package/dist/patterns/element-anatomy/item-anatomy.d.ts.map +1 -1
- package/dist/patterns/element-anatomy/item-anatomy.js +71 -27
- package/dist/patterns/element-anatomy/item-anatomy.js.map +1 -1
- package/ds-canonical/fork/consumer/lock.json +4 -4
- package/ds-canonical/fork/governance.lock +1 -1
- package/ds-canonical/fork/manifest.json +6 -6
- package/llms-full.txt +1 -1
- package/llms.txt +1 -1
- package/package.json +1 -1
- package/src/components/Accordion/accordion.principles.stories.tsx +16 -26
- package/src/components/Accordion/accordion.stories.tsx +22 -40
- package/src/components/Calendar/calendar.spec.md +1 -1
- package/src/components/Calendar/calendar.tsx +59 -25
- package/src/components/DataTable/cell-registry.tsx +3 -7
- package/src/components/DataTable/data-table.spec.md +1 -0
- package/src/components/DataTable/data-table.tsx +9 -2
- package/src/components/DatePicker/date-picker.spec.md +1 -1
- package/src/components/DatePicker/date-picker.tsx +203 -147
- package/src/components/Dialog/dialog.spec.md +1 -1
- package/src/components/Dialog/dialog.tsx +8 -2
- package/src/components/Field/field-context.ts +25 -1
- package/src/components/Field/field-wrapper.tsx +7 -1
- package/src/components/Field/field.spec.md +7 -0
- package/src/components/Field/field.tsx +13 -2
- package/src/components/InlineEdit/inline-edit.spec.md +12 -0
- package/src/components/InlineEdit/inline-edit.stories.tsx +28 -17
- package/src/components/InlineEdit/inline-edit.tsx +94 -31
- package/src/components/Input/input.tsx +7 -2
- package/src/components/LinkInput/link-input.spec.md +1 -1
- package/src/components/LinkInput/link-input.tsx +5 -1
- package/src/components/Popover/popover.tsx +7 -2
- package/src/components/Select/select.principles.stories.tsx +4 -3
- package/src/components/Select/select.stories.tsx +7 -6
- package/src/components/Select/select.tsx +61 -29
- package/src/components/Textarea/textarea.spec.md +10 -1
- package/src/components/Textarea/textarea.tsx +38 -5
- package/src/components/TimePicker/time-picker.tsx +11 -5
- package/src/components/Tooltip/tooltip.spec.md +6 -0
- package/src/patterns/element-anatomy/item-anatomy.spec.md +8 -1
- package/src/patterns/element-anatomy/item-anatomy.tsx +111 -30
- package/src/patterns/element-anatomy/truncated-text.spec.md +13 -2
- package/src/tokens/uiSize/uiSize.css +11 -0
- package/src/tokens/uiSize/uiSize.spec.md +1 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"calendar.d.ts","sourceRoot":"","sources":["../../../src/components/Calendar/calendar.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAe9B,OAAO,EAAyB,KAAK,cAAc,EAAE,MAAM,0CAA0C,CAAA;
|
|
1
|
+
{"version":3,"file":"calendar.d.ts","sourceRoot":"","sources":["../../../src/components/Calendar/calendar.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAe9B,OAAO,EAAyB,KAAK,cAAc,EAAE,MAAM,0CAA0C,CAAA;AAOrG;;;;;;;;;;;;;;;;;;GAkBG;AAIH,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,8DAA8D;IAC9D,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;IAClB,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB;;;;OAIG;IACH,KAAK,CAAC,EAAE,cAAc,CAAA;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CACnC;AAED,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,MAAM,GAAG,KAAK,CAAA;AAEnD,MAAM,WAAW,aAAc,SAAQ,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,UAAU,CAAC;IAC3F;;;;OAIG;IACH,IAAI,CAAC,EAAE,YAAY,CAAA;IACnB,WAAW,CAAC,EAAE,YAAY,CAAA;IAC1B,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,IAAI,CAAA;IAE3C,wBAAwB;IACxB,aAAa,CAAC,EAAE,IAAI,CAAA;IACpB,oBAAoB,CAAC,EAAE,IAAI,CAAA;IAC3B,qBAAqB,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAA;IAE5C,WAAW;IACX,MAAM,CAAC,EAAE,aAAa,EAAE,CAAA;IAExB,sBAAsB;IACtB,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAA;IAC7C,uBAAuB;IACvB,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAA;IAClC,kBAAkB;IAClB,aAAa,CAAC,EAAE,MAAM,IAAI,CAAA;IAE1B,2DAA2D;IAC3D,YAAY,CAAC,EAAE,CAAC,GAAG,CAAC,CAAA;IAEpB,uBAAuB;IACvB,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,KAAK,CAAC,SAAS,CAAA;IAE3D;;;OAGG;IACH,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,CAAA;IAClB,SAAS,CAAC,EAAE,MAAM,CAAA;IAElB,yBAAyB;IACzB,MAAM,CAAC,EAAE,MAAM,CAAA;IAEf,0DAA0D;IAC1D,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,0DAA0D;IAC1D,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,iFAAiF;IACjF,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAkFD,QAAA,MAAM,QAAQ,sFAqSZ,CAAA;AAKF,eAAO,MAAM,YAAY;;;;;;;;;;;CAgBf,CAAA;AAEV,OAAO,EAAE,QAAQ,EAAE,CAAA"}
|
|
@@ -6,6 +6,9 @@ import { cn } from "../../lib/utils.js";
|
|
|
6
6
|
import { CAT_ACCENT, CAT_EVENT } from "../../tokens/categorical-color.js";
|
|
7
7
|
import { Button } from "../Button/button.js";
|
|
8
8
|
import { SegmentedControl, SegmentedControlItem } from "../SegmentedControl/segmented-control.js";
|
|
9
|
+
import { TruncatedText } from "../../patterns/element-anatomy/truncated-text.js";
|
|
10
|
+
import { Tooltip, TooltipTrigger, TooltipContent } from "../Tooltip/tooltip.js";
|
|
11
|
+
import { useTruncated } from "../../hooks/use-truncated.js";
|
|
9
12
|
const EVENT_COLOR_CLASSES = CAT_EVENT;
|
|
10
13
|
const EVENT_ALLDAY_ACCENT = CAT_ACCENT;
|
|
11
14
|
function coerceDate(value) {
|
|
@@ -18,6 +21,45 @@ function coerceDate(value) {
|
|
|
18
21
|
return new Date(value);
|
|
19
22
|
}
|
|
20
23
|
const MAX_TILES_PER_CELL = 3;
|
|
24
|
+
function MonthEventTile({
|
|
25
|
+
event,
|
|
26
|
+
colorClass,
|
|
27
|
+
onEventClick
|
|
28
|
+
}) {
|
|
29
|
+
const { ref: truncationRef, isTruncated } = useTruncated({ deps: [event.title] });
|
|
30
|
+
return (
|
|
31
|
+
// 恆 wrap、未截斷 open={false} 靜默(truncated-text.spec.md always-wrap:條件 wrap 會 remount 丟 RO 訂閱)
|
|
32
|
+
/* @__PURE__ */ jsxs(Tooltip, { open: isTruncated ? void 0 : false, children: [
|
|
33
|
+
/* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
|
|
34
|
+
"div",
|
|
35
|
+
{
|
|
36
|
+
role: "button",
|
|
37
|
+
tabIndex: 0,
|
|
38
|
+
onClick: (e) => {
|
|
39
|
+
e.stopPropagation();
|
|
40
|
+
onEventClick == null ? void 0 : onEventClick(event);
|
|
41
|
+
},
|
|
42
|
+
onKeyDown: (e) => {
|
|
43
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
44
|
+
e.preventDefault();
|
|
45
|
+
onEventClick == null ? void 0 : onEventClick(event);
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
"aria-label": `事件:${event.title}`,
|
|
49
|
+
className: cn(
|
|
50
|
+
"rounded-md px-1.5 py-0.5 text-caption truncate cursor-pointer transition-colors",
|
|
51
|
+
// 2026-05-31 #22:事件 tile 是 focusable(tabIndex=0 role=button)但原無 focus ring
|
|
52
|
+
// → WCAG 2.4.7 不合規。補 focus-visible ring 對齊日期格按鈕。
|
|
53
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
54
|
+
colorClass
|
|
55
|
+
),
|
|
56
|
+
children: /* @__PURE__ */ jsx("span", { ref: truncationRef, className: "block truncate", children: event.title })
|
|
57
|
+
}
|
|
58
|
+
) }),
|
|
59
|
+
/* @__PURE__ */ jsx(TooltipContent, { children: event.title })
|
|
60
|
+
] })
|
|
61
|
+
);
|
|
62
|
+
}
|
|
21
63
|
const Calendar = React.forwardRef(function Calendar2({
|
|
22
64
|
view: viewProp,
|
|
23
65
|
defaultView = "month",
|
|
@@ -163,7 +205,7 @@ const Calendar = React.forwardRef(function Calendar2({
|
|
|
163
205
|
}
|
|
164
206
|
)
|
|
165
207
|
] }),
|
|
166
|
-
/* @__PURE__ */ jsx("h2", { className: "text-body-lg font-medium text-foreground flex-1 min-w-0 truncate ml-2", children: monthTitle }),
|
|
208
|
+
/* @__PURE__ */ jsx("h2", { className: "text-body-lg font-medium text-foreground flex-1 min-w-0 truncate ml-2", children: /* @__PURE__ */ jsx(TruncatedText, { display: "block", children: monthTitle }) }),
|
|
167
209
|
/* @__PURE__ */ jsxs(
|
|
168
210
|
SegmentedControl,
|
|
169
211
|
{
|
|
@@ -256,29 +298,11 @@ const Calendar = React.forwardRef(function Calendar2({
|
|
|
256
298
|
);
|
|
257
299
|
}
|
|
258
300
|
return /* @__PURE__ */ jsx(
|
|
259
|
-
|
|
301
|
+
MonthEventTile,
|
|
260
302
|
{
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
e.stopPropagation();
|
|
265
|
-
onEventClick == null ? void 0 : onEventClick(event);
|
|
266
|
-
},
|
|
267
|
-
onKeyDown: (e) => {
|
|
268
|
-
if (e.key === "Enter" || e.key === " ") {
|
|
269
|
-
e.preventDefault();
|
|
270
|
-
onEventClick == null ? void 0 : onEventClick(event);
|
|
271
|
-
}
|
|
272
|
-
},
|
|
273
|
-
"aria-label": `事件:${event.title}`,
|
|
274
|
-
className: cn(
|
|
275
|
-
"rounded-md px-1.5 py-0.5 text-caption truncate cursor-pointer transition-colors",
|
|
276
|
-
// 2026-05-31 #22:事件 tile 是 focusable(tabIndex=0 role=button)但原無 focus ring
|
|
277
|
-
// → WCAG 2.4.7 不合規。補 focus-visible ring 對齊日期格按鈕。
|
|
278
|
-
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
279
|
-
colorClass
|
|
280
|
-
),
|
|
281
|
-
children: event.title
|
|
303
|
+
event,
|
|
304
|
+
colorClass,
|
|
305
|
+
onEventClick
|
|
282
306
|
},
|
|
283
307
|
event.id
|
|
284
308
|
);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"calendar.js","sources":["../../../src/components/Calendar/calendar.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 { ChevronLeft, ChevronRight, Plus } from 'lucide-react'\nimport {\n startOfMonth,\n endOfMonth,\n startOfWeek,\n endOfWeek,\n eachDayOfInterval,\n format,\n isSameMonth,\n isSameDay,\n addMonths,\n subMonths,\n} from 'date-fns'\nimport { cn } from '@/lib/utils'\nimport { CAT_EVENT, CAT_ACCENT, type CategoricalHue } from '@/design-system/tokens/categorical-color'\nimport { Button } from '@/design-system/components/Button/button'\nimport { SegmentedControl, SegmentedControlItem } from '@/design-system/components/SegmentedControl/segmented-control'\n\n/**\n * Calendar — 事件檢視 canvas(月 view MVP)\n *\n * 定位:看事件的 page-level canvas,對齊 Notion Calendar / Google Calendar。\n * 完整 spec 見 `calendar.spec.md`。\n *\n * ── Layout Family ──\n * 非 4-Family,屬 page-composite(多區塊 Toolbar + Grid + EventTile)。\n *\n * ── MVP scope ──\n * - 月 view 完整(toolbar / grid / event tile / today highlight / outside days)\n * - 週 / 日 view + size lg = **roadmap:尚未實作,目前只渲染月檢視**(誠實 API,\n * props 保留給未來增量,2026-07-14 user 拍板;行為明細見 spec「狀態 > 邊界案例」)\n * - 拖拉增刪 event 是 roadmap(見 spec「MVP vs 後續增量」)\n *\n * ── 與 DatePicker 的區分 ──\n * DatePicker 是「選日期」form control;Calendar 是「看事件」page canvas。\n * 名字相近但職責完全不同,spec 頂段明示分界。\n */\n\n// ── Types ──────────────────────────────────────────────────────────────────\n\nexport interface CalendarEvent {\n id: string\n title: string\n /** ISO 字串 \"YYYY-MM-DD\"(all-day)或 \"YYYY-MM-DDTHH:mm\"(timed) */\n start: string | Date\n end: string | Date\n allDay?: boolean\n /**\n * 事件類別色(categorical 色相,1:1 對 `--color-{hue}-*`)。**消費 categorical-color SSOT**,\n * 與 Tag / Avatar 共用同一組 12 色相。2026-06-04 修:原 `orange` 與 `red` 都誤接 deep-orange;\n * 改消費 SSOT 後 orange→`--color-orange-*`、red→`--color-red-*`(品牌紅 hue 25),各自獨立。\n */\n color?: CategoricalHue\n metadata?: Record<string, unknown>\n}\n\nexport type CalendarView = 'month' | 'week' | 'day'\n\nexport interface CalendarProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onSelect'> {\n /**\n * 當前 view。**roadmap:`'week'` / `'day'` 尚未實作,目前只渲染月檢視**——\n * 傳入不報錯:grid 仍為月檢視,僅 `data-view` 同步 + SegmentedControl 週/日項 disabled\n * (誠實 API;見 calendar.spec.md「狀態 > 邊界案例」+「MVP vs 後續增量」)。\n */\n view?: CalendarView\n defaultView?: CalendarView\n onViewChange?: (view: CalendarView) => void\n\n /** 聚焦日期(月 view 的那個月) */\n referenceDate?: Date\n defaultReferenceDate?: Date\n onReferenceDateChange?: (date: Date) => void\n\n /** 事件資料 */\n events?: CalendarEvent[]\n\n /** 點 event tile 回調 */\n onEventClick?: (event: CalendarEvent) => void\n /** 點月 cell 回調(用於新增) */\n onDateClick?: (date: Date) => void\n /** 點新事件 CTA 回調 */\n onCreateEvent?: () => void\n\n /** 0 = Sunday, 1 = Monday。預設 0(對齊 Google Calendar 美系預設) */\n weekStartsOn?: 0 | 1\n\n /** 自訂 event tile 渲染 */\n renderEventTile?: (event: CalendarEvent) => React.ReactNode\n\n /**\n * size。**roadmap:`'lg'` 尚未實作,視覺與 `'md'` 相同**——傳入不報錯,\n * 僅設 `data-size` attribute,無任何 CSS 消費(誠實 API;prop 保留給未來 cell 密度增量)。\n */\n size?: 'md' | 'lg'\n className?: string\n\n /** locale(預設 'en-US') */\n locale?: string\n\n /** ARIA labels for chrome controls. Override for i18n. */\n prevAriaLabel?: string\n nextAriaLabel?: string\n /** 月份導覽 <nav> landmark 的 aria-label。Override for i18n. */\n navAriaLabel?: string\n viewToggleAriaLabel?: string\n todayLabel?: string\n /** 「新事件」CTA 文字。Override for i18n。CTA 僅在傳 `onCreateEvent` 時渲染(spec Toolbar 段)。 */\n createLabel?: string\n}\n\n// ── Event tile color tokens ─────────────────────────────────────────────────\n// **消費 categorical-color SSOT**(CAT_EVENT = subtle 底 + hover step-2;CAT_ACCENT = 左側 step-6\n// 實心條),與 Tag / Avatar 共用 12 色相,key X 一律對 `--color-X-*`(1:1)。\n// 2026-06-01 allDay:全天事件 = 淡底 tile + 左側實心 accent 條 + medium,視覺區分「全天長條」vs\n// 有時間事件;用 accent border 而非 solid fill 保文字對比安全。對齊 Google Calendar / Outlook 慣例。\nconst EVENT_COLOR_CLASSES = CAT_EVENT\nconst EVENT_ALLDAY_ACCENT = CAT_ACCENT\n\n// ── Helpers ────────────────────────────────────────────────────────────────\n\nfunction coerceDate(value: string | Date): Date {\n if (value instanceof Date) return value\n // date-only ISO(\"YYYY-MM-DD\")用本地午夜建構,不走 new Date(str)。\n // 原因:`new Date('2026-06-15')` 按 UTC 午夜解析,而 eventsByDate 分桶以本地\n // getFullYear/Month/Date 讀取 → 負 UTC 時區(西半球)的 all-day 事件被移到前一天\n // (真實 timezone bug)。手動 split 建本地 Date,與分桶的本地讀取一致。\n // 含時間的字串(YYYY-MM-DDTHH:mm,無 offset)ES 規範本就以本地解析,走原生 new Date()。\n const dateOnly = /^\\d{4}-\\d{2}-\\d{2}$/.exec(value)\n if (dateOnly) {\n const [y, m, d] = value.split('-').map(Number)\n return new Date(y, m - 1, d)\n }\n return new Date(value)\n}\n\n// eventsOnDate(per-cell 全 events 掃描)已由 eventsByDate bucketing memo 取代並移除\n// (2026-07-06 D3 perf;留著會觸發 noUnusedLocals TS6133)。\n\n// ── Component ──────────────────────────────────────────────────────────────\n\nconst MAX_TILES_PER_CELL = 3\n\nconst Calendar = React.forwardRef<HTMLDivElement, CalendarProps>(function Calendar({\n view: viewProp,\n defaultView = 'month',\n onViewChange,\n referenceDate: referenceDateProp,\n defaultReferenceDate,\n onReferenceDateChange,\n events = [],\n onEventClick,\n onDateClick,\n onCreateEvent,\n weekStartsOn = 0,\n renderEventTile,\n size = 'md',\n className,\n locale = 'en-US',\n prevAriaLabel = '上個月', // i18n-allow: DS default; consumer override via prevAriaLabel prop\n nextAriaLabel = '下個月', // i18n-allow: DS default; consumer override via nextAriaLabel prop\n navAriaLabel = '行事曆月份導覽', // i18n-allow: DS default; consumer override via navAriaLabel prop\n viewToggleAriaLabel = '檢視切換', // i18n-allow: DS default; consumer override via viewToggleAriaLabel prop\n todayLabel = '今天', // i18n-allow: DS default; consumer override via todayLabel prop\n createLabel = '新事件', // i18n-allow: DS default; consumer override via createLabel prop\n ...props\n}, ref) {\n // Controlled / uncontrolled refDate\n const [internalRef, setInternalRef] = React.useState<Date>(\n defaultReferenceDate ?? new Date(),\n )\n const refDate = referenceDateProp ?? internalRef\n const setRefDate = React.useCallback(\n (next: Date) => {\n if (referenceDateProp === undefined) setInternalRef(next)\n onReferenceDateChange?.(next)\n },\n [referenceDateProp, onReferenceDateChange],\n )\n\n // View state(roadmap:week/day 尚未實作,受控值照收但 grid 恆為月檢視)\n const [internalView, setInternalView] = React.useState<CalendarView>(defaultView)\n const currentView = viewProp ?? internalView\n const setView = React.useCallback(\n (next: CalendarView) => {\n if (viewProp === undefined) setInternalView(next)\n onViewChange?.(next)\n },\n [viewProp, onViewChange],\n )\n\n // Build month grid\n const days = React.useMemo(() => {\n const monthStart = startOfMonth(refDate)\n const monthEnd = endOfMonth(refDate)\n const gridStart = startOfWeek(monthStart, { weekStartsOn })\n const gridEnd = endOfWeek(monthEnd, { weekStartsOn })\n return eachDayOfInterval({ start: gridStart, end: gridEnd })\n }, [refDate, weekStartsOn])\n\n // 2026-07-06 D3 perf:formatter 依 locale memo(對齊 weekdayNames 既有做法),避免每 render 重建\n // Intl.DateTimeFormat(已知貴的 constructor);.format(refDate) 每 render 仍執行(cheap)。\n const monthTitleFormatter = React.useMemo(\n () => new Intl.DateTimeFormat(locale, { year: 'numeric', month: 'long' }),\n [locale],\n )\n const monthTitle = monthTitleFormatter.format(refDate)\n\n const today = new Date()\n\n const weekdayNames = React.useMemo(() => {\n // 取 `days[0..6]` 的名字(gridStart 開始 7 天,正好一週)\n return days.slice(0, 7).map((d) =>\n new Intl.DateTimeFormat(locale, { weekday: 'short' }).format(d),\n )\n }, [days, locale])\n\n // 2026-07-06 D3 perf:原每 render 對 42 cells 各跑 eventsOnDate 全 events filter = O(42×N) +\n // 每比較配 ~5 個 Date;數百-上千 events(行事曆真實規模)單次 render 數十 ms,且父層任何 re-render\n // 全額重付。改 useMemo 單趟 bucket:每 event 只 parse 一次,展開 [start..end](clamp 到可見 grid,\n // 避免長跨度 event 展開爆量)寫入 date→events Map,順便完成 allDay 排序。cell 內改 O(1) map.get。行為 Δ=0。\n const eventsByDate = React.useMemo(() => {\n const map = new Map<string, CalendarEvent[]>()\n if (days.length === 0) return map\n const first = days[0]\n const last = days[days.length - 1]\n const gridStart = new Date(first.getFullYear(), first.getMonth(), first.getDate()).getTime()\n const gridEnd = new Date(last.getFullYear(), last.getMonth(), last.getDate()).getTime()\n for (const e of events) {\n const start = coerceDate(e.start)\n const end = coerceDate(e.end)\n const eEnd = new Date(end.getFullYear(), end.getMonth(), end.getDate()).getTime()\n let sMs = new Date(start.getFullYear(), start.getMonth(), start.getDate()).getTime()\n if (eEnd < gridStart || sMs > gridEnd) continue // 可見窗外對 42 cells 無貢獻\n if (sMs < gridStart) sMs = gridStart\n const lastMs = Math.min(eEnd, gridEnd)\n const cursor = new Date(sMs)\n while (cursor.getTime() <= lastMs) {\n const key = `${cursor.getFullYear()}-${cursor.getMonth() + 1}-${cursor.getDate()}`\n const bucket = map.get(key)\n if (bucket) bucket.push(e)\n else map.set(key, [e])\n cursor.setDate(cursor.getDate() + 1)\n }\n }\n // allDay 排前(對齊 Google Calendar 全天列在上;V8 stable sort 保 events 原序 → 與舊 per-cell 一致)\n for (const bucket of map.values()) {\n bucket.sort((a, b) => Number(b.allDay ?? false) - Number(a.allDay ?? false))\n }\n return map\n }, [events, days])\n\n const handleToday = () => setRefDate(new Date())\n const handlePrev = () => setRefDate(subMonths(refDate, 1))\n const handleNext = () => setRefDate(addMonths(refDate, 1))\n\n return (\n <div\n ref={ref}\n className={cn(\n 'flex flex-col w-full h-full bg-surface rounded-md border border-divider overflow-hidden',\n className,\n )}\n data-view={currentView}\n data-size={size}\n {...props}\n >\n {/* Toolbar:[◀] [今天] [▶] title [view tabs] [+ new] */}\n <div\n className={cn(\n 'flex items-center gap-2 shrink-0 border-b border-divider',\n 'px-[var(--layout-space-loose)] py-[var(--layout-space-tight)]',\n )}\n >\n {/* 月份導覽 landmark:prev / 今天 / next 包成 <nav> 給 SR landmark 導航(per calendar.spec.md a11y 段) */}\n <nav className=\"flex items-center gap-2\" aria-label={navAriaLabel}>\n <Button\n variant=\"text\"\n size=\"sm\"\n iconOnly\n startIcon={ChevronLeft}\n aria-label={prevAriaLabel}\n onClick={handlePrev}\n />\n <Button variant=\"tertiary\" size=\"sm\" onClick={handleToday}>\n {todayLabel}\n </Button>\n <Button\n variant=\"text\"\n size=\"sm\"\n iconOnly\n startIcon={ChevronRight}\n aria-label={nextAriaLabel}\n onClick={handleNext}\n />\n </nav>\n\n <h2 className=\"text-body-lg font-medium text-foreground flex-1 min-w-0 truncate ml-2\">\n {monthTitle}\n </h2>\n\n {/* View switcher:用 SegmentedControl(互斥多選一 canonical)——\n 對齊 CLAUDE.md「互斥分類選擇走 SegmentedControl,非 checked Button group」原則。\n Button 的 pressed 是「toggle 持續狀態」語意,不適合「單選 view 切換」 */}\n <SegmentedControl\n size=\"sm\"\n value={currentView}\n onValueChange={(v) => setView(v as CalendarView)}\n aria-label={viewToggleAriaLabel}\n >\n <SegmentedControlItem value=\"day\" disabled>日</SegmentedControlItem>\n <SegmentedControlItem value=\"week\" disabled>週</SegmentedControlItem>\n <SegmentedControlItem value=\"month\">月</SegmentedControlItem>\n </SegmentedControl>\n\n {onCreateEvent && (\n <Button variant=\"primary\" size=\"sm\" startIcon={Plus} onClick={onCreateEvent}>\n {createLabel}\n </Button>\n )}\n </div>\n\n {/* Weekday header */}\n <div className=\"grid grid-cols-7 border-b border-divider bg-muted\">\n {weekdayNames.map((name, i) => (\n <div\n key={i}\n className=\"px-2 py-1.5 text-caption text-fg-muted font-normal text-center\"\n >\n {name}\n </div>\n ))}\n </div>\n\n {/* Month grid:7 cols, ~5-6 rows。a11y(2026-04-25):WAI-ARIA grid 要求 row > gridcell\n 階層,chunk days 7 一組,wrap 成 role='row'(display:contents 保 CSS grid 佈局)。 */}\n <div\n className=\"grid grid-cols-7 flex-1 min-h-0\"\n role=\"grid\"\n aria-label={`月行事曆,${monthTitle}`}\n >\n {Array.from({ length: Math.ceil(days.length / 7) }, (_, rowIdx) => (\n <div key={rowIdx} role=\"row\" style={{ display: 'contents' }}>\n {days.slice(rowIdx * 7, rowIdx * 7 + 7).map((date) => {\n const inMonth = isSameMonth(date, refDate)\n const isToday = isSameDay(date, today)\n // 2026-06-01 allDay:全天事件排 cell 頂端(對齊 Google Calendar 全天列在上)——\n // 排序已在 eventsByDate bucketing memo 內完成(D3 perf),cell 內 O(1) 查表\n const dayEvents = eventsByDate.get(`${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`) ?? []\n const visibleEvents = dayEvents.slice(0, MAX_TILES_PER_CELL)\n const overflowCount = dayEvents.length - visibleEvents.length\n\n return (\n // 2026-06-11 a11y(user 拍板 2c 修 code):cell 從 <button role=\"gridcell\"> 改非互動容器 —\n // W3C button 語義禁止互動後代,cell 內含 role=\"button\" 事件 tile = nested-interactive 違規。\n // 對齊 Google Calendar:gridcell = 容器,日期數字按鈕 = 日期級 keyboard 入口,tile 各自為 button。\n // div onClick 保留滑鼠「點 cell 空白處等同點日期」便利(keyboard 走日期數字按鈕,功能等價)。\n <div\n key={date.toISOString()}\n role=\"gridcell\"\n onClick={() => onDateClick?.(date)}\n className={cn(\n 'flex flex-col gap-1 min-h-28 p-1.5 text-left',\n 'border-r border-b border-divider last:border-r-0',\n '[&:nth-child(7n)]:border-r-0',\n 'hover:bg-neutral-hover transition-colors',\n !inMonth && 'bg-muted',\n )}\n >\n {/* Date number = keyboard 入口;今天/平日統一 24px 圓形 hit-area(WCAG 2.5.8 ≥24,\n 今天 pill 本就 24px,平日跟齊 → 跨 cell 數字光學對齊) */}\n <div className=\"flex items-start justify-end\">\n <button\n type=\"button\"\n aria-label={`${format(date, 'yyyy-MM-dd')},${dayEvents.length} 個事件`}\n onClick={(e) => {\n e.stopPropagation()\n onDateClick?.(date)\n }}\n className={cn(\n 'inline-flex items-center justify-center min-w-6 h-6 rounded-full text-body font-medium',\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',\n isToday && 'px-2 bg-info text-on-emphasis',\n !isToday && !inMonth && 'text-fg-disabled',\n )}\n >\n {format(date, 'd')}\n </button>\n </div>\n\n {/* Event tiles */}\n <div className=\"flex flex-col gap-0.5 min-h-0\">\n {visibleEvents.map((event) => {\n const ec = event.color ?? 'blue'\n // 2026-06-01 allDay:淡底 + 左 accent 條 + medium = 「全天長條」視覺(區分有時間事件)\n const colorClass = event.allDay\n ? cn(EVENT_COLOR_CLASSES[ec], EVENT_ALLDAY_ACCENT[ec], 'font-medium')\n : EVENT_COLOR_CLASSES[ec]\n if (renderEventTile) {\n return (\n <div\n key={event.id}\n onClick={(e) => {\n e.stopPropagation()\n onEventClick?.(event)\n }}\n >\n {renderEventTile(event)}\n </div>\n )\n }\n return (\n <div\n key={event.id}\n role=\"button\"\n tabIndex={0}\n onClick={(e) => {\n e.stopPropagation()\n onEventClick?.(event)\n }}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n onEventClick?.(event)\n }\n }}\n aria-label={`事件:${event.title}`}\n className={cn(\n 'rounded-md px-1.5 py-0.5 text-caption truncate cursor-pointer transition-colors',\n // 2026-05-31 #22:事件 tile 是 focusable(tabIndex=0 role=button)但原無 focus ring\n // → WCAG 2.4.7 不合規。補 focus-visible ring 對齊日期格按鈕。\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',\n colorClass,\n )}\n >\n {event.title}\n </div>\n )\n })}\n {overflowCount > 0 && (\n <div className=\"text-caption text-fg-muted px-1.5\">\n +{overflowCount} more\n </div>\n )}\n </div>\n </div>\n )\n })}\n </div>\n ))}\n </div>\n </div>\n )\n})\nCalendar.displayName = \"Calendar\"\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 calendarMeta = {\n component: 'Calendar',\n family: null, // non-family composite / overlay / layout\n variants: {\n\n },\n sizes: {\n\n },\n // 'active' 移除 — 日期格按壓視覺屬 DateGrid(其 meta 已 −active);nav 按壓屬內嵌 Button(2026-07-07 詞彙統一 DS-wide 按壓訊號盤點:檔內 0 active: utility / 0 *-active token)。\n states: ['default', 'hover', 'focus-visible', 'disabled'],\n tokens: {\n bg: ['bg-muted', 'bg-neutral-hover', 'bg-info', 'bg-surface'],\n fg: ['text-fg-disabled', 'text-fg-muted', 'text-foreground'],\n ring: ['ring-ring'],\n },\n} as const\n\nexport { Calendar }\n"],"names":["Calendar"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"calendar.js","sources":["../../../src/components/Calendar/calendar.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 { ChevronLeft, ChevronRight, Plus } from 'lucide-react'\nimport {\n startOfMonth,\n endOfMonth,\n startOfWeek,\n endOfWeek,\n eachDayOfInterval,\n format,\n isSameMonth,\n isSameDay,\n addMonths,\n subMonths,\n} from 'date-fns'\nimport { cn } from '@/lib/utils'\nimport { CAT_EVENT, CAT_ACCENT, type CategoricalHue } from '@/design-system/tokens/categorical-color'\nimport { Button } from '@/design-system/components/Button/button'\nimport { SegmentedControl, SegmentedControlItem } from '@/design-system/components/SegmentedControl/segmented-control'\nimport { TruncatedText } from '@/design-system/patterns/element-anatomy/truncated-text'\nimport { Tooltip, TooltipContent, TooltipTrigger } from '@/design-system/components/Tooltip/tooltip'\nimport { useTruncated } from '@/design-system/hooks/use-truncated'\n\n/**\n * Calendar — 事件檢視 canvas(月 view MVP)\n *\n * 定位:看事件的 page-level canvas,對齊 Notion Calendar / Google Calendar。\n * 完整 spec 見 `calendar.spec.md`。\n *\n * ── Layout Family ──\n * 非 4-Family,屬 page-composite(多區塊 Toolbar + Grid + EventTile)。\n *\n * ── MVP scope ──\n * - 月 view 完整(toolbar / grid / event tile / today highlight / outside days)\n * - 週 / 日 view + size lg = **roadmap:尚未實作,目前只渲染月檢視**(誠實 API,\n * props 保留給未來增量,2026-07-14 user 拍板;行為明細見 spec「狀態 > 邊界案例」)\n * - 拖拉增刪 event 是 roadmap(見 spec「MVP vs 後續增量」)\n *\n * ── 與 DatePicker 的區分 ──\n * DatePicker 是「選日期」form control;Calendar 是「看事件」page canvas。\n * 名字相近但職責完全不同,spec 頂段明示分界。\n */\n\n// ── Types ──────────────────────────────────────────────────────────────────\n\nexport interface CalendarEvent {\n id: string\n title: string\n /** ISO 字串 \"YYYY-MM-DD\"(all-day)或 \"YYYY-MM-DDTHH:mm\"(timed) */\n start: string | Date\n end: string | Date\n allDay?: boolean\n /**\n * 事件類別色(categorical 色相,1:1 對 `--color-{hue}-*`)。**消費 categorical-color SSOT**,\n * 與 Tag / Avatar 共用同一組 12 色相。2026-06-04 修:原 `orange` 與 `red` 都誤接 deep-orange;\n * 改消費 SSOT 後 orange→`--color-orange-*`、red→`--color-red-*`(品牌紅 hue 25),各自獨立。\n */\n color?: CategoricalHue\n metadata?: Record<string, unknown>\n}\n\nexport type CalendarView = 'month' | 'week' | 'day'\n\nexport interface CalendarProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onSelect'> {\n /**\n * 當前 view。**roadmap:`'week'` / `'day'` 尚未實作,目前只渲染月檢視**——\n * 傳入不報錯:grid 仍為月檢視,僅 `data-view` 同步 + SegmentedControl 週/日項 disabled\n * (誠實 API;見 calendar.spec.md「狀態 > 邊界案例」+「MVP vs 後續增量」)。\n */\n view?: CalendarView\n defaultView?: CalendarView\n onViewChange?: (view: CalendarView) => void\n\n /** 聚焦日期(月 view 的那個月) */\n referenceDate?: Date\n defaultReferenceDate?: Date\n onReferenceDateChange?: (date: Date) => void\n\n /** 事件資料 */\n events?: CalendarEvent[]\n\n /** 點 event tile 回調 */\n onEventClick?: (event: CalendarEvent) => void\n /** 點月 cell 回調(用於新增) */\n onDateClick?: (date: Date) => void\n /** 點新事件 CTA 回調 */\n onCreateEvent?: () => void\n\n /** 0 = Sunday, 1 = Monday。預設 0(對齊 Google Calendar 美系預設) */\n weekStartsOn?: 0 | 1\n\n /** 自訂 event tile 渲染 */\n renderEventTile?: (event: CalendarEvent) => React.ReactNode\n\n /**\n * size。**roadmap:`'lg'` 尚未實作,視覺與 `'md'` 相同**——傳入不報錯,\n * 僅設 `data-size` attribute,無任何 CSS 消費(誠實 API;prop 保留給未來 cell 密度增量)。\n */\n size?: 'md' | 'lg'\n className?: string\n\n /** locale(預設 'en-US') */\n locale?: string\n\n /** ARIA labels for chrome controls. Override for i18n. */\n prevAriaLabel?: string\n nextAriaLabel?: string\n /** 月份導覽 <nav> landmark 的 aria-label。Override for i18n. */\n navAriaLabel?: string\n viewToggleAriaLabel?: string\n todayLabel?: string\n /** 「新事件」CTA 文字。Override for i18n。CTA 僅在傳 `onCreateEvent` 時渲染(spec Toolbar 段)。 */\n createLabel?: string\n}\n\n// ── Event tile color tokens ─────────────────────────────────────────────────\n// **消費 categorical-color SSOT**(CAT_EVENT = subtle 底 + hover step-2;CAT_ACCENT = 左側 step-6\n// 實心條),與 Tag / Avatar 共用 12 色相,key X 一律對 `--color-X-*`(1:1)。\n// 2026-06-01 allDay:全天事件 = 淡底 tile + 左側實心 accent 條 + medium,視覺區分「全天長條」vs\n// 有時間事件;用 accent border 而非 solid fill 保文字對比安全。對齊 Google Calendar / Outlook 慣例。\nconst EVENT_COLOR_CLASSES = CAT_EVENT\nconst EVENT_ALLDAY_ACCENT = CAT_ACCENT\n\n// ── Helpers ────────────────────────────────────────────────────────────────\n\nfunction coerceDate(value: string | Date): Date {\n if (value instanceof Date) return value\n // date-only ISO(\"YYYY-MM-DD\")用本地午夜建構,不走 new Date(str)。\n // 原因:`new Date('2026-06-15')` 按 UTC 午夜解析,而 eventsByDate 分桶以本地\n // getFullYear/Month/Date 讀取 → 負 UTC 時區(西半球)的 all-day 事件被移到前一天\n // (真實 timezone bug)。手動 split 建本地 Date,與分桶的本地讀取一致。\n // 含時間的字串(YYYY-MM-DDTHH:mm,無 offset)ES 規範本就以本地解析,走原生 new Date()。\n const dateOnly = /^\\d{4}-\\d{2}-\\d{2}$/.exec(value)\n if (dateOnly) {\n const [y, m, d] = value.split('-').map(Number)\n return new Date(y, m - 1, d)\n }\n return new Date(value)\n}\n\n// eventsOnDate(per-cell 全 events 掃描)已由 eventsByDate bucketing memo 取代並移除\n// (2026-07-06 D3 perf;留著會觸發 noUnusedLocals TS6133)。\n\n// ── Component ──────────────────────────────────────────────────────────────\n\nconst MAX_TILES_PER_CELL = 3\n\n// 預設事件 tile 抽出 component:截斷 tooltip 需 useTruncated(hook 不能在 map callback 內)。\n// 截斷 → tooltip 顯完整標題(tooltip.spec.md:32,僅實際截斷時);tile 是 interactive host\n// (role=button,hover 直達)→ trigger = tile 本體、量測內層文字 span — useTruncated 自組\n// pattern(truncated-text.spec.md「trigger 需自控」指定解;範本 inline-edit.tsx:251 + tag.tsx)。\nfunction MonthEventTile({\n event,\n colorClass,\n onEventClick,\n}: {\n event: CalendarEvent\n colorClass: string\n onEventClick?: (event: CalendarEvent) => void\n}) {\n const { ref: truncationRef, isTruncated } = useTruncated<HTMLSpanElement>({ deps: [event.title] })\n return (\n // 恆 wrap、未截斷 open={false} 靜默(truncated-text.spec.md always-wrap:條件 wrap 會 remount 丟 RO 訂閱)\n <Tooltip open={isTruncated ? undefined : false}>\n <TooltipTrigger asChild>\n <div\n role=\"button\"\n tabIndex={0}\n onClick={(e) => {\n e.stopPropagation()\n onEventClick?.(event)\n }}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n onEventClick?.(event)\n }\n }}\n aria-label={`事件:${event.title}`}\n className={cn(\n 'rounded-md px-1.5 py-0.5 text-caption truncate cursor-pointer transition-colors',\n // 2026-05-31 #22:事件 tile 是 focusable(tabIndex=0 role=button)但原無 focus ring\n // → WCAG 2.4.7 不合規。補 focus-visible ring 對齊日期格按鈕。\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',\n colorClass,\n )}\n >\n <span ref={truncationRef} className=\"block truncate\">{event.title}</span>\n </div>\n </TooltipTrigger>\n <TooltipContent>{event.title}</TooltipContent>\n </Tooltip>\n )\n}\n\nconst Calendar = React.forwardRef<HTMLDivElement, CalendarProps>(function Calendar({\n view: viewProp,\n defaultView = 'month',\n onViewChange,\n referenceDate: referenceDateProp,\n defaultReferenceDate,\n onReferenceDateChange,\n events = [],\n onEventClick,\n onDateClick,\n onCreateEvent,\n weekStartsOn = 0,\n renderEventTile,\n size = 'md',\n className,\n locale = 'en-US',\n prevAriaLabel = '上個月', // i18n-allow: DS default; consumer override via prevAriaLabel prop\n nextAriaLabel = '下個月', // i18n-allow: DS default; consumer override via nextAriaLabel prop\n navAriaLabel = '行事曆月份導覽', // i18n-allow: DS default; consumer override via navAriaLabel prop\n viewToggleAriaLabel = '檢視切換', // i18n-allow: DS default; consumer override via viewToggleAriaLabel prop\n todayLabel = '今天', // i18n-allow: DS default; consumer override via todayLabel prop\n createLabel = '新事件', // i18n-allow: DS default; consumer override via createLabel prop\n ...props\n}, ref) {\n // Controlled / uncontrolled refDate\n const [internalRef, setInternalRef] = React.useState<Date>(\n defaultReferenceDate ?? new Date(),\n )\n const refDate = referenceDateProp ?? internalRef\n const setRefDate = React.useCallback(\n (next: Date) => {\n if (referenceDateProp === undefined) setInternalRef(next)\n onReferenceDateChange?.(next)\n },\n [referenceDateProp, onReferenceDateChange],\n )\n\n // View state(roadmap:week/day 尚未實作,受控值照收但 grid 恆為月檢視)\n const [internalView, setInternalView] = React.useState<CalendarView>(defaultView)\n const currentView = viewProp ?? internalView\n const setView = React.useCallback(\n (next: CalendarView) => {\n if (viewProp === undefined) setInternalView(next)\n onViewChange?.(next)\n },\n [viewProp, onViewChange],\n )\n\n // Build month grid\n const days = React.useMemo(() => {\n const monthStart = startOfMonth(refDate)\n const monthEnd = endOfMonth(refDate)\n const gridStart = startOfWeek(monthStart, { weekStartsOn })\n const gridEnd = endOfWeek(monthEnd, { weekStartsOn })\n return eachDayOfInterval({ start: gridStart, end: gridEnd })\n }, [refDate, weekStartsOn])\n\n // 2026-07-06 D3 perf:formatter 依 locale memo(對齊 weekdayNames 既有做法),避免每 render 重建\n // Intl.DateTimeFormat(已知貴的 constructor);.format(refDate) 每 render 仍執行(cheap)。\n const monthTitleFormatter = React.useMemo(\n () => new Intl.DateTimeFormat(locale, { year: 'numeric', month: 'long' }),\n [locale],\n )\n const monthTitle = monthTitleFormatter.format(refDate)\n\n const today = new Date()\n\n const weekdayNames = React.useMemo(() => {\n // 取 `days[0..6]` 的名字(gridStart 開始 7 天,正好一週)\n return days.slice(0, 7).map((d) =>\n new Intl.DateTimeFormat(locale, { weekday: 'short' }).format(d),\n )\n }, [days, locale])\n\n // 2026-07-06 D3 perf:原每 render 對 42 cells 各跑 eventsOnDate 全 events filter = O(42×N) +\n // 每比較配 ~5 個 Date;數百-上千 events(行事曆真實規模)單次 render 數十 ms,且父層任何 re-render\n // 全額重付。改 useMemo 單趟 bucket:每 event 只 parse 一次,展開 [start..end](clamp 到可見 grid,\n // 避免長跨度 event 展開爆量)寫入 date→events Map,順便完成 allDay 排序。cell 內改 O(1) map.get。行為 Δ=0。\n const eventsByDate = React.useMemo(() => {\n const map = new Map<string, CalendarEvent[]>()\n if (days.length === 0) return map\n const first = days[0]\n const last = days[days.length - 1]\n const gridStart = new Date(first.getFullYear(), first.getMonth(), first.getDate()).getTime()\n const gridEnd = new Date(last.getFullYear(), last.getMonth(), last.getDate()).getTime()\n for (const e of events) {\n const start = coerceDate(e.start)\n const end = coerceDate(e.end)\n const eEnd = new Date(end.getFullYear(), end.getMonth(), end.getDate()).getTime()\n let sMs = new Date(start.getFullYear(), start.getMonth(), start.getDate()).getTime()\n if (eEnd < gridStart || sMs > gridEnd) continue // 可見窗外對 42 cells 無貢獻\n if (sMs < gridStart) sMs = gridStart\n const lastMs = Math.min(eEnd, gridEnd)\n const cursor = new Date(sMs)\n while (cursor.getTime() <= lastMs) {\n const key = `${cursor.getFullYear()}-${cursor.getMonth() + 1}-${cursor.getDate()}`\n const bucket = map.get(key)\n if (bucket) bucket.push(e)\n else map.set(key, [e])\n cursor.setDate(cursor.getDate() + 1)\n }\n }\n // allDay 排前(對齊 Google Calendar 全天列在上;V8 stable sort 保 events 原序 → 與舊 per-cell 一致)\n for (const bucket of map.values()) {\n bucket.sort((a, b) => Number(b.allDay ?? false) - Number(a.allDay ?? false))\n }\n return map\n }, [events, days])\n\n const handleToday = () => setRefDate(new Date())\n const handlePrev = () => setRefDate(subMonths(refDate, 1))\n const handleNext = () => setRefDate(addMonths(refDate, 1))\n\n return (\n <div\n ref={ref}\n className={cn(\n 'flex flex-col w-full h-full bg-surface rounded-md border border-divider overflow-hidden',\n className,\n )}\n data-view={currentView}\n data-size={size}\n {...props}\n >\n {/* Toolbar:[◀] [今天] [▶] title [view tabs] [+ new] */}\n <div\n className={cn(\n 'flex items-center gap-2 shrink-0 border-b border-divider',\n 'px-[var(--layout-space-loose)] py-[var(--layout-space-tight)]',\n )}\n >\n {/* 月份導覽 landmark:prev / 今天 / next 包成 <nav> 給 SR landmark 導航(per calendar.spec.md a11y 段) */}\n <nav className=\"flex items-center gap-2\" aria-label={navAriaLabel}>\n <Button\n variant=\"text\"\n size=\"sm\"\n iconOnly\n startIcon={ChevronLeft}\n aria-label={prevAriaLabel}\n onClick={handlePrev}\n />\n <Button variant=\"tertiary\" size=\"sm\" onClick={handleToday}>\n {todayLabel}\n </Button>\n <Button\n variant=\"text\"\n size=\"sm\"\n iconOnly\n startIcon={ChevronRight}\n aria-label={nextAriaLabel}\n onClick={handleNext}\n />\n </nav>\n\n <h2 className=\"text-body-lg font-medium text-foreground flex-1 min-w-0 truncate ml-2\">\n {/* 2026-07-28:截斷必附 tooltip(tooltip.spec.md「截斷 → tooltip,僅實際截斷時顯示」)——\n 窄 toolbar 下標題被裁掉沒有補救路徑。display=\"block\":h2 是 block container。 */}\n <TruncatedText display=\"block\">{monthTitle}</TruncatedText>\n </h2>\n\n {/* View switcher:用 SegmentedControl(互斥多選一 canonical)——\n 對齊 CLAUDE.md「互斥分類選擇走 SegmentedControl,非 checked Button group」原則。\n Button 的 pressed 是「toggle 持續狀態」語意,不適合「單選 view 切換」 */}\n <SegmentedControl\n size=\"sm\"\n value={currentView}\n onValueChange={(v) => setView(v as CalendarView)}\n aria-label={viewToggleAriaLabel}\n >\n <SegmentedControlItem value=\"day\" disabled>日</SegmentedControlItem>\n <SegmentedControlItem value=\"week\" disabled>週</SegmentedControlItem>\n <SegmentedControlItem value=\"month\">月</SegmentedControlItem>\n </SegmentedControl>\n\n {onCreateEvent && (\n <Button variant=\"primary\" size=\"sm\" startIcon={Plus} onClick={onCreateEvent}>\n {createLabel}\n </Button>\n )}\n </div>\n\n {/* Weekday header */}\n <div className=\"grid grid-cols-7 border-b border-divider bg-muted\">\n {weekdayNames.map((name, i) => (\n <div\n key={i}\n className=\"px-2 py-1.5 text-caption text-fg-muted font-normal text-center\"\n >\n {name}\n </div>\n ))}\n </div>\n\n {/* Month grid:7 cols, ~5-6 rows。a11y(2026-04-25):WAI-ARIA grid 要求 row > gridcell\n 階層,chunk days 7 一組,wrap 成 role='row'(display:contents 保 CSS grid 佈局)。 */}\n <div\n className=\"grid grid-cols-7 flex-1 min-h-0\"\n role=\"grid\"\n aria-label={`月行事曆,${monthTitle}`}\n >\n {Array.from({ length: Math.ceil(days.length / 7) }, (_, rowIdx) => (\n <div key={rowIdx} role=\"row\" style={{ display: 'contents' }}>\n {days.slice(rowIdx * 7, rowIdx * 7 + 7).map((date) => {\n const inMonth = isSameMonth(date, refDate)\n const isToday = isSameDay(date, today)\n // 2026-06-01 allDay:全天事件排 cell 頂端(對齊 Google Calendar 全天列在上)——\n // 排序已在 eventsByDate bucketing memo 內完成(D3 perf),cell 內 O(1) 查表\n const dayEvents = eventsByDate.get(`${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`) ?? []\n const visibleEvents = dayEvents.slice(0, MAX_TILES_PER_CELL)\n const overflowCount = dayEvents.length - visibleEvents.length\n\n return (\n // 2026-06-11 a11y(user 拍板 2c 修 code):cell 從 <button role=\"gridcell\"> 改非互動容器 —\n // W3C button 語義禁止互動後代,cell 內含 role=\"button\" 事件 tile = nested-interactive 違規。\n // 對齊 Google Calendar:gridcell = 容器,日期數字按鈕 = 日期級 keyboard 入口,tile 各自為 button。\n // div onClick 保留滑鼠「點 cell 空白處等同點日期」便利(keyboard 走日期數字按鈕,功能等價)。\n <div\n key={date.toISOString()}\n role=\"gridcell\"\n onClick={() => onDateClick?.(date)}\n className={cn(\n 'flex flex-col gap-1 min-h-28 p-1.5 text-left',\n 'border-r border-b border-divider last:border-r-0',\n '[&:nth-child(7n)]:border-r-0',\n 'hover:bg-neutral-hover transition-colors',\n !inMonth && 'bg-muted',\n )}\n >\n {/* Date number = keyboard 入口;今天/平日統一 24px 圓形 hit-area(WCAG 2.5.8 ≥24,\n 今天 pill 本就 24px,平日跟齊 → 跨 cell 數字光學對齊) */}\n <div className=\"flex items-start justify-end\">\n <button\n type=\"button\"\n aria-label={`${format(date, 'yyyy-MM-dd')},${dayEvents.length} 個事件`}\n onClick={(e) => {\n e.stopPropagation()\n onDateClick?.(date)\n }}\n className={cn(\n 'inline-flex items-center justify-center min-w-6 h-6 rounded-full text-body font-medium',\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',\n isToday && 'px-2 bg-info text-on-emphasis',\n !isToday && !inMonth && 'text-fg-disabled',\n )}\n >\n {format(date, 'd')}\n </button>\n </div>\n\n {/* Event tiles */}\n <div className=\"flex flex-col gap-0.5 min-h-0\">\n {visibleEvents.map((event) => {\n const ec = event.color ?? 'blue'\n // 2026-06-01 allDay:淡底 + 左 accent 條 + medium = 「全天長條」視覺(區分有時間事件)\n const colorClass = event.allDay\n ? cn(EVENT_COLOR_CLASSES[ec], EVENT_ALLDAY_ACCENT[ec], 'font-medium')\n : EVENT_COLOR_CLASSES[ec]\n if (renderEventTile) {\n return (\n <div\n key={event.id}\n onClick={(e) => {\n e.stopPropagation()\n onEventClick?.(event)\n }}\n >\n {renderEventTile(event)}\n </div>\n )\n }\n return (\n <MonthEventTile\n key={event.id}\n event={event}\n colorClass={colorClass}\n onEventClick={onEventClick}\n />\n )\n })}\n {overflowCount > 0 && (\n <div className=\"text-caption text-fg-muted px-1.5\">\n +{overflowCount} more\n </div>\n )}\n </div>\n </div>\n )\n })}\n </div>\n ))}\n </div>\n </div>\n )\n})\nCalendar.displayName = \"Calendar\"\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 calendarMeta = {\n component: 'Calendar',\n family: null, // non-family composite / overlay / layout\n variants: {\n\n },\n sizes: {\n\n },\n // 'active' 移除 — 日期格按壓視覺屬 DateGrid(其 meta 已 −active);nav 按壓屬內嵌 Button(2026-07-07 詞彙統一 DS-wide 按壓訊號盤點:檔內 0 active: utility / 0 *-active token)。\n states: ['default', 'hover', 'focus-visible', 'disabled'],\n tokens: {\n bg: ['bg-muted', 'bg-neutral-hover', 'bg-info', 'bg-surface'],\n fg: ['text-fg-disabled', 'text-fg-muted', 'text-foreground'],\n ring: ['ring-ring'],\n },\n} as const\n\nexport { Calendar }\n"],"names":["Calendar"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cell-registry.d.ts","sourceRoot":"","sources":["../../../src/components/DataTable/cell-registry.tsx"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAA;AAG1C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAmChD,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,MAAM,CAAA;AACtC,MAAM,MAAM,QAAQ,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;AAEzC,MAAM,WAAW,kBAAkB;IAEjC,KAAK,EAAE,GAAG,CAAA;IAEV,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IACzB,IAAI,EAAE,QAAQ,CAAA;IACd,IAAI,EAAE,QAAQ,CAAA;IACd;;8FAE0F;IAC1F,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,aAAa,EAAE,OAAO,CAAA;IACtB,2EAA2E;IAC3E,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB;+GAC2G;IAC3G,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IAClC;;sFAEkF;IAClF,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACtC,yBAAyB;IACzB,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;IACrB,gFAAgF;IAChF,aAAa,CAAC,EAAE,MAAM,IAAI,CAAA;IAC1B;;;;qFAIiF;IACjF,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;CAClC;
|
|
1
|
+
{"version":3,"file":"cell-registry.d.ts","sourceRoot":"","sources":["../../../src/components/DataTable/cell-registry.tsx"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAA;AAG1C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAmChD,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,MAAM,CAAA;AACtC,MAAM,MAAM,QAAQ,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;AAEzC,MAAM,WAAW,kBAAkB;IAEjC,KAAK,EAAE,GAAG,CAAA;IAEV,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IACzB,IAAI,EAAE,QAAQ,CAAA;IACd,IAAI,EAAE,QAAQ,CAAA;IACd;;8FAE0F;IAC1F,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,aAAa,EAAE,OAAO,CAAA;IACtB,2EAA2E;IAC3E,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB;+GAC2G;IAC3G,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IAClC;;sFAEkF;IAClF,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACtC,yBAAyB;IACzB,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;IACrB,gFAAgF;IAChF,aAAa,CAAC,EAAE,MAAM,IAAI,CAAA;IAC1B;;;;qFAIiF;IACjF,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;CAClC;AAyZD,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,kBAAkB,CAAC,CAY9E,CAAA;AA4CD,wBAAgB,oBAAoB,CAAC,IAAI,CAAC,EAAE,UAAU,GAAG,aAAa,CAAC,kBAAkB,CAAC,CAEzF"}
|
|
@@ -43,9 +43,6 @@ function StringCell({ value, meta, mode, size, autoRowHeight, onCommit, onCancel
|
|
|
43
43
|
return autoRowHeight ? /* @__PURE__ */ jsx(Textarea, { variant: "naked", mode: "view", value: v, size, className: clampClass, "aria-label": ariaLabel }) : /* @__PURE__ */ jsx(Input, { variant: "naked", mode: "view", value: v, size, "aria-label": ariaLabel });
|
|
44
44
|
}
|
|
45
45
|
if (autoRowHeight) {
|
|
46
|
-
const newlineRows = (v.match(/\n/g) || []).length + 1;
|
|
47
|
-
const wrapRows = Math.ceil(v.length / 40);
|
|
48
|
-
const estimateRows = Math.min(10, Math.max(1, newlineRows, wrapRows));
|
|
49
46
|
return /* @__PURE__ */ jsx(
|
|
50
47
|
Textarea,
|
|
51
48
|
{
|
|
@@ -53,9 +50,8 @@ function StringCell({ value, meta, mode, size, autoRowHeight, onCommit, onCancel
|
|
|
53
50
|
variant: "naked",
|
|
54
51
|
"aria-label": ariaLabel,
|
|
55
52
|
size: sizeForInput(size),
|
|
56
|
-
|
|
53
|
+
autoSize: true,
|
|
57
54
|
defaultValue: v,
|
|
58
|
-
style: { fieldSizing: "content" },
|
|
59
55
|
onChange: (e) => onDraft == null ? void 0 : onDraft(e.target.value),
|
|
60
56
|
onBlur: (e) => onCommit == null ? void 0 : onCommit(e.target.value),
|
|
61
57
|
onKeyDown: makeEditSettleKeyHandler({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cell-registry.js","sources":["../../../src/components/DataTable/cell-registry.tsx"],"sourcesContent":["// @benchmark-unverified-blanket: file-level retraction per M22 (d) — claims herein not individually URL-cited; treat as unverified visual/usage rumor unless retrofit per-claim. Hook escape preserved.\n// code-quality-allow: file-size — Cell Registry 含 10 cell-type components(string/number/date/time/select/multiSelect/person/multiPerson/boolean/url)+ shared helpers,split-into-files 會破壞 type-keyed registry SSOT canonical\n// DataTable Cell Registry — type-keyed SSOT for cell rendering(Phase C 2026-05-05)\n//\n// 對齊 M17 SSOT consolidation + audit recommendation:\n// 原 `renderTypedValue` switch + `EditableCellContent` switch 兩條平行 type-switch 已 collapse\n// 為**一張 type → cell component** registry。每個 cell component 同時處理 view / edit mode,\n// 靠底層 Field control 的 `mode` prop 切換。\n//\n// 設計原則:\n// - 每個 cell component 接同一組 props(`CellComponentProps`)\n// - 用 `variant=\"naked\"` — DataTable cell-as-input substrate(Field chrome variant;bare 2026-07-09 退役)\n// - 消費 full Field 家族 primitive(無 stub)\n// - 不再用 `meta._editable` 私有 flag — `isEditable` 直接顯式入參(消除 M1 hack)\n//\n// World-class 對照(@benchmark-unverified):AG Grid cellRendererSelector / Material X-Grid\n// `valueGetter + renderCell` / Notion property type registry。\n\nimport * as React from 'react'\nimport type { ComponentType } from 'react'\nimport { Pencil } from 'lucide-react'\nimport { cn, lineClampClass } from '@/lib/utils'\nimport type { ColumnType } from './column-types'\nimport { Input as InputPublic } from '@/design-system/components/Input/input'\nimport { Textarea as TextareaPublic } from '@/design-system/components/Textarea/textarea'\nimport { NumberInput as NumberInputPublic } from '@/design-system/components/NumberInput/number-input'\nimport { Select as SelectPublic } from '@/design-system/components/Select/select'\nimport { Combobox as ComboboxPublic } from '@/design-system/components/Combobox/combobox'\nimport { DatePicker as DatePickerPublic } from '@/design-system/components/DatePicker/date-picker'\nimport { TimePicker as TimePickerPublic } from '@/design-system/components/TimePicker/time-picker'\nimport { PeoplePicker as PeoplePickerPublic } from '@/design-system/components/PeoplePicker/people-picker'\nimport { LinkInput as LinkInputPublic } from '@/design-system/components/LinkInput/link-input'\nimport { Checkbox as CheckboxPublic } from '@/design-system/components/Checkbox/checkbox'\nimport { Button } from '@/design-system/components/Button/button'\nimport type { PersonValue } from '@/design-system/components/PeoplePicker/person-display'\nimport { FieldSurfaceProvider, FieldSurfaceSizeProvider, FieldSurfaceEditableProvider } from '@/design-system/components/Field/field-context'\nimport { makeEditSettleKeyHandler } from '@/design-system/components/Field/field-edit-keys'\nimport type { WithFieldVariantInternal } from '@/design-system/components/Field/field-types'\n\n// ── @internal naked variant 通道(2026-07-14 API 策展 E,user 拍板「全部收窄」)──────────────\n// `naked` 已從公開 FieldVariant 拆出(field-types.ts `FieldVariantInternal`);本檔是唯一合法\n// naked 消費者(field-controls.spec.md「軸二 variant」明文)。以 `WithFieldVariantInternal`\n// 型別層 widen 各 Field control 的 `variant` prop — 純型別、零 runtime;元件內部 cva / resolver\n// 分支本就吃 FieldVariantInternal,widen 不引入 unsound 行為。\nconst Input = InputPublic as WithFieldVariantInternal<typeof InputPublic>\nconst Textarea = TextareaPublic as WithFieldVariantInternal<typeof TextareaPublic>\nconst NumberInput = NumberInputPublic as WithFieldVariantInternal<typeof NumberInputPublic>\nconst Select = SelectPublic as WithFieldVariantInternal<typeof SelectPublic>\nconst Combobox = ComboboxPublic as WithFieldVariantInternal<typeof ComboboxPublic>\nconst DatePicker = DatePickerPublic as WithFieldVariantInternal<typeof DatePickerPublic>\nconst TimePicker = TimePickerPublic as WithFieldVariantInternal<typeof TimePickerPublic>\nconst PeoplePicker = PeoplePickerPublic as WithFieldVariantInternal<typeof PeoplePickerPublic>\nconst LinkInput = LinkInputPublic as WithFieldVariantInternal<typeof LinkInputPublic>\nconst Checkbox = CheckboxPublic as WithFieldVariantInternal<typeof CheckboxPublic>\n\n// ── Types ────────────────────────────────────────────────────────────────────\n\nexport type CellMode = 'view' | 'edit'\nexport type CellSize = 'sm' | 'md' | 'lg'\n\nexport interface CellComponentProps {\n // any-allow: free-form column value(consumer-defined,跨 type 共用 signature)\n value: any\n // any-allow: free-form consumer meta bag(prefix / options / formatOptions / locale / linkLabel 等)\n meta: Record<string, any>\n mode: CellMode\n size: CellSize\n /** 該 cell 的 accessible name(= 欄標題)。naked Field 控件在 cell 內無 FieldLabel,\n * 漏此名 → editor 成無名控件(axe aria-input-field-name / select-name)。由 renderCellContent\n * 從 columnDef.header 解析後注入。對齊 AG Grid / MUI X「editor aria-label = column headerName」。 */\n ariaLabel?: string\n autoRowHeight: boolean\n /** 該 cell 是否可編。replaces 舊 `meta._editable` 私有 flag(Phase C M1 hack 移除)。 */\n isEditable?: boolean\n /** Cell 進 edit mode → 提交新值(blur / Enter / option select 都觸發)— 提交後**自動 exit edit**。\n * 適用 single-shot commit:string / number / select(single)/ person(single)/ date / time / boolean / url。 */\n onCommit?: (next: unknown) => void\n /** Live commit — 提交新值但 **不 exit edit**(popover 持續開)。\n * 適用 multi-select 類:multiSelect / multiPerson — user 連續勾選,直到點外面才關。\n * 對齊 Notion / Linear / Airtable canonical:multi-pick popover 不在每次 toggle 後關閉。 */\n onCommitLive?: (next: unknown) => void\n /** Esc 取消編輯,不 commit。 */\n onCancel?: () => void\n /** URL cell 專用:hover 顯示的 Pencil 鈕 → 進 edit mode(read mode 保留 link click 語意)。 */\n onRequestEdit?: () => void\n /** Per-keystroke draft propagation(2026-05-10 Phase 7 D.3 portal Field virtualizer unmount preserve draft):\n * Edit mode 內部 input onChange/onValueChange 每 keystroke 呼叫 onDraft,讓 lifted draft state(in\n * data-table.tsx)持有 user 編輯中字。Cell DOM unmount(virtualizer scroll out)時 draft 在\n * parent state 不丟;mount-back 時 portal Field value 從 draft 取,user 字保留。\n * 非 portal mode(inline edit)不傳此 prop,各 Cell 走原 uncontrolled defaultValue 路徑。 */\n onDraft?: (next: unknown) => void\n}\n\n// ── Helpers ──────────────────────────────────────────────────────────────────\n\n/** 鍵盤 commit / cancel — string / number cell edit mode 共用 */\nfunction makeKeyHandler(\n onCommit?: (v: unknown) => void,\n onCancel?: () => void,\n parseValue?: (raw: string) => unknown,\n) {\n // 消費 edit-in-place 鍵盤結算 SSOT(field-edit-keys.ts):IME guard + Enter/Esc dispatch 統一\n // (2026-07-09 抽出;原本 InlineEdit 漏 IME guard = bug,現同源)。value 讀取為 input-specific,留本地。\n return makeEditSettleKeyHandler({\n onCommit: (e) => {\n const raw = (e.target as HTMLInputElement).value\n onCommit?.(parseValue ? parseValue(raw) : raw)\n },\n onCancel: () => onCancel?.(),\n })\n}\n\nconst sizeForInput = (size: CellSize): CellSize => size\n\n// 2026-07-16 round16:cell「disabled」態廢除(世界級 grid 無 disabled cell — MUI X / AG Grid /\n// Handsontable 皆只有 editable/readonly;meta.disabled 全庫 0 消費)。cell view 態一律 mode=\"view\",\n// 鎖定用 `editable:(row)=>false` 閘(= isCellEditable 模型)。原 displayOrDisabled helper 已移除。\n\n// ── Cell Components ──────────────────────────────────────────────────────────\n\nfunction StringCell({ value, meta, mode, size, autoRowHeight, onCommit, onCancel, onDraft, ariaLabel }: CellComponentProps) {\n // 2026-05-14 I9 fix(per codex+Layer A 共識):meta.maxLines opt-in line-clamp。\n // view autoRow 用 Tailwind arbitrary line-clamp 支援 N rows;edit textarea field-sizing\n // 已 auto-grow to content,natural match clamp。\n // 2026-05-16 Round 5 audit Dim 27 fix:narrow type 取代 `as any` cast。\n const maxLines: number | undefined = (meta as { maxLines?: number } | undefined)?.maxLines\n const clampClass = autoRowHeight ? lineClampClass(maxLines) : undefined\n // string type canonical(2026-05-05 v2 user 校正:input space ≥ display space):\n // - autoRowHeight: Textarea(view + edit)— view wrap text 撐高 row,edit textarea\n // 多行輸入、`!h-full` 填 cell。對齊 Notion long-text cell canonical。\n // - fixed: Input(view + edit)— 單行 truncate view,單行 input edit;Field naked intrinsic\n // 高 = cell 高 = h-field-md,文字位置 view↔edit 完全一致。對齊 AG Grid / Material X-Grid。\n // - autoRowHeight 是 table 框架決定(consumer 不需 per-column 設 meta.wrap)。\n // - 互動(Textarea):Esc cancel / Cmd|Ctrl+Enter commit / blur commit;Enter 保留換行\n // - 互動(Input):Esc cancel / Enter commit / blur commit\n const v = value != null ? String(value) : ''\n if (mode === 'view') {\n // size 必傳:DataTable cell 字級隨 size 變(sm/md text-body / lg text-body-lg),\n // 對齊 Field family size→font SSOT(field-wrapper.tsx:60-64)。漏傳 → fallback md → lg 表格\n // 字卡 14px 跟 Select/Date 等有傳 size 的 cell 不一致(2026-06-08 user 抓 frozen string 欄字偏小)。\n return autoRowHeight\n ? <Textarea variant=\"naked\" mode=\"view\" value={v} size={size} className={clampClass} aria-label={ariaLabel} />\n : <Input variant=\"naked\" mode=\"view\" value={v} size={size} aria-label={ariaLabel} />\n }\n if (autoRowHeight) {\n // 2026-05-14 I8 fix(per codex verdict + user 抓「edit cell shrink」):\n // 原 `wrapRows = value.length / 40` 字元估算不準(對應實際 column width 不同\n // → cell 進 edit shrink)。改 CSS `field-sizing: content`(Chrome 123+ / FF 122+ /\n // Safari 17+)讓 textarea 自動 grow to content,匹配 view wrap 真實高度。\n // Fallback rows 仍保留給舊 browser(rows attr 在 field-sizing 支援時被覆蓋)。\n const newlineRows = (v.match(/\\n/g) || []).length + 1\n const wrapRows = Math.ceil(v.length / 40)\n const estimateRows = Math.min(10, Math.max(1, newlineRows, wrapRows))\n return (\n <Textarea\n autoFocus\n variant=\"naked\"\n aria-label={ariaLabel}\n size={sizeForInput(size)}\n rows={estimateRows}\n defaultValue={v}\n // any-allow: CSS `field-sizing` 屬性 Chrome 123+/FF 122+/Safari 17+ 支援但 TypeScript lib.dom\n // 尚未加 type;narrow 到 CSSProperties 仍需 cast,保留 single-site any 較 type aug 簡潔。\n style={{ fieldSizing: 'content' } as React.CSSProperties}\n onChange={(e) => onDraft?.((e.target as HTMLTextAreaElement).value)}\n onBlur={(e) => onCommit?.((e.target as HTMLTextAreaElement).value)}\n // 多行:走 edit-in-place 鍵盤結算 SSOT(IME guard + Esc + Cmd/Ctrl+Enter commit;\n // plain Enter=換行)。commitOnEnter:false → 純 Enter 不攔。\n onKeyDown={makeEditSettleKeyHandler({\n onCommit: (e) => onCommit?.((e.target as HTMLTextAreaElement).value),\n onCancel: () => onCancel?.(),\n commitOnEnter: false,\n })}\n />\n )\n }\n return (\n <Input\n autoFocus\n variant=\"naked\"\n aria-label={ariaLabel}\n size={sizeForInput(size)}\n defaultValue={v}\n onChange={(e) => onDraft?.(e.target.value)}\n onBlur={(e) => onCommit?.(e.target.value)}\n onKeyDown={makeKeyHandler(onCommit, onCancel)}\n />\n )\n}\n\nfunction NumberCell({ value, meta, mode, size, onCommit, onCancel, onDraft, ariaLabel }: CellComponentProps) {\n // currency 透過 columnType-aware prefix:type='currency' → 預設 '$'(可 override)\n const isCurrency = meta?.type === 'currency'\n const prefix = isCurrency ? (meta?.prefix ?? '$') : meta?.prefix\n // React #310 fix:useState 必在 view early-return 前無條件呼叫。同一 memo'd cell instance\n // 在 view↔edit 切換時被重用(render site 無 key={mode},data-table.tsx:1352),hook 數量不可變,\n // 否則 Rules of Hooks violation → React #310 crash。對齊 combobox/select hoist pattern。\n const initial = typeof value === 'number' ? value : null\n const [localValue, setLocalValue] = React.useState<number | null>(initial)\n if (mode === 'view') {\n return (\n <NumberInput\n variant=\"naked\"\n mode=\"view\"\n aria-label={ariaLabel}\n value={value as number | null}\n // size 必傳(同 StringCell)— currency/number cell 字級隨 DataTable size 變,對齊 Field SSOT。\n size={size}\n prefix={prefix}\n suffix={meta?.suffix}\n precision={meta?.precision}\n locale={meta?.locale}\n />\n )\n }\n // Edit mode value pre-fill canonical(2026-05-05):NumberInput edit 強制 controlled\n // (`value={value ?? ''}`)— 若 NumberCell 以 `defaultValue` 傳入,NumberInput value=undefined → ''\n // empty。對齊 cell-as-input「edit mode 自動帶入 view 值」(對齊 Notion / Airtable 共識),\n // 改用 local state controlled。User typing → setLocalValue;blur/Enter → onCommit(localValue)。\n // (initial + useState 已 hoist 到 view-return 前 — 見上方 React #310 fix。)\n return (\n <NumberInput\n autoFocus\n variant=\"naked\"\n aria-label={ariaLabel}\n size={sizeForInput(size)}\n value={localValue}\n onChange={(v) => { setLocalValue(v); onDraft?.(v) }}\n prefix={prefix}\n suffix={meta?.suffix}\n precision={meta?.precision}\n onBlur={() => onCommit?.(localValue)}\n // 單行:走 edit-in-place 鍵盤結算 SSOT(IME guard + Esc + Enter commit)。\n // commit localValue(controlled state,非 e.target.value)。\n onKeyDown={makeEditSettleKeyHandler({\n onCommit: () => onCommit?.(localValue),\n onCancel: () => onCancel?.(),\n })}\n />\n )\n}\n\n// Cell-as-input dismiss canonical(2026-05-05):defaultOpen=true 開始 → user click 外 popover 關\n// → 元件 fire onOpenChange(false) → cell call onCancel exit edit。否則 cell 卡 edit mode 不可 re-trigger\n// (對齊 Airtable / Notion canonical:click 外即關)。\nconst dismissOnClose = (onCancel?: () => void) => (open: boolean) => { if (!open) onCancel?.() }\n\n// Mode-keyed remount canonical(2026-05-05):view↔edit 切換時,因 React reconciliation 同 type 同\n// position 會重用 instance,導致 `useState(defaultOpen)` 只在首次 mount 跑(那時 mode='view'\n// defaultOpen 沒給→預設 false)。後續 mode='edit' 即使傳 defaultOpen=true 也無效。\n// Fix:`key={mode}` 強制 React unmount + remount,每次切 mode 都重跑 useState init。\n// 對齊 Notion / Airtable cell-as-input「view 跟 edit 是不同 mount cycle」語義。\n\nfunction DateCell({ value, meta, mode, size, onCommit, onCancel }: CellComponentProps) {\n if (mode === 'view') {\n return (\n <DatePicker\n key=\"view\"\n variant=\"naked\"\n mode=\"view\"\n value={value as string | null}\n size={size}\n formatOptions={meta?.formatOptions}\n locale={meta?.locale}\n // 2026-07-08 user 拍板 A 案(推翻 2026-05-10/06-26 兩次拍板,per 6 家 benchmark 6/6 共識\n // Ant/MUI X/AG Grid/Atlaskit/Notion/Airtable:view 態零恆顯型別 icon;editable\n // affordance 統一 = hover outline(field.spec.md L4)。showDisplayEndIcon 不再傳\n //(prop 保留為 spreadsheet-flavored 消費端 opt-in 逃生門,見 field.spec.md L6)。\n />\n )\n }\n return (\n <DatePicker\n key=\"edit\"\n autoFocus\n variant=\"naked\"\n size={sizeForInput(size)}\n value={typeof value === 'string' ? value : null}\n showTime={meta?.includeTime === true}\n onChange={(v) => onCommit?.(v)}\n defaultOpen\n onOpenChange={dismissOnClose(onCancel)}\n />\n )\n}\n\nfunction TimeCell({ value, meta, mode, size, onCommit, onCancel }: CellComponentProps) {\n if (mode === 'view') {\n return (\n <TimePicker\n key=\"view\"\n variant=\"naked\"\n mode=\"view\"\n value={value as string | null}\n size={size}\n formatOptions={meta?.formatOptions}\n locale={meta?.locale}\n // showDisplayEndIcon 不傳 — 2026-07-08 A 案:view 態零恆顯 icon(同 DateCell 註)\n />\n )\n }\n return (\n <TimePicker\n key=\"edit\"\n variant=\"naked\"\n size={sizeForInput(size)}\n value={typeof value === 'string' ? value : null}\n showSeconds={meta?.showSeconds === true}\n minuteStep={meta?.minuteStep}\n secondStep={meta?.secondStep}\n onChange={(v) => onCommit?.(v)}\n defaultOpen\n onOpenChange={dismissOnClose(onCancel)}\n />\n )\n}\n\nfunction SelectCell({ value, meta, mode, size, onCommit, onCancel }: CellComponentProps) {\n // View canonical(2026-05-05):cell IS variant,default plain text(no Tag pill 疊在 cell border 內)。\n // Consumer 可在 column meta.display='tag' opt-in 內容導向的 Tag 視覺(category 含色彩標籤等)。\n // 對齊 JTable / AG Grid「renderer/editor 視覺一致」canonical。\n const displayMode = (meta?.display as 'plain' | 'tag' | undefined) ?? 'plain'\n if (mode === 'view') {\n return (\n <Select\n key=\"view\"\n variant=\"naked\"\n mode=\"view\"\n value={value as string | null}\n options={meta?.options ?? []}\n size={size}\n display={displayMode}\n // showDisplayEndIcon 不傳 — 2026-07-08 A 案:view 態零恆顯 icon(同 DateCell 註)\n selectedItemRenderer={meta?.selectedItemRenderer} // 2026-07-08 WM 戰役:status 類彩色 cell 顯示通道\n />\n )\n }\n return (\n <Select\n key=\"edit\"\n autoFocus\n variant=\"naked\"\n size={sizeForInput(size)}\n selectedItemRenderer={meta?.selectedItemRenderer}\n options={meta?.options ?? []}\n value={value as string | null | undefined}\n onChange={(v) => onCommit?.(v)}\n // B7(2026-05-05):cell 編輯時支援 inline search,沿用 Select.searchable 機制(對齊 cell-as-input\n // 「沿用既有輸入框互動」原則)。Default false,consumer 在 meta.searchable 開啟。\n searchable={meta?.searchable === true}\n display={displayMode}\n defaultOpen\n onOpenChange={dismissOnClose(onCancel)}\n />\n )\n}\n\nfunction MultiSelectCell({ value, meta, mode, size, autoRowHeight, onCommitLive, onCancel }: CellComponentProps) {\n const wrap = autoRowHeight && meta?.wrap === true\n if (mode === 'view') {\n return (\n <Combobox\n key=\"view\"\n variant=\"naked\"\n mode=\"view\"\n value={(value as string[] | null) ?? []}\n options={meta?.options ?? []}\n wrap={wrap}\n size={size}\n // showDisplayEndIcon 不傳 — 2026-07-08 A 案:view 態零恆顯 icon(同 DateCell 註)\n />\n )\n }\n // Multi 用 onCommitLive(commit 但不 exit edit)— 每勾一項即時生效,popover 持續開\n // 直到點外面;onOpenChange(false) → onCancel exit edit。對齊 Notion / Linear / Airtable canonical。\n return (\n <Combobox\n key=\"edit\"\n variant=\"naked\"\n size={sizeForInput(size)}\n options={meta?.options ?? []}\n value={Array.isArray(value) ? (value as string[]) : []}\n onChange={(v) => onCommitLive?.(v)}\n defaultOpen\n onOpenChange={dismissOnClose(onCancel)}\n />\n )\n}\n\nfunction PersonCell({ value, mode, size, onCommit, onCancel, meta }: CellComponentProps) {\n if (mode === 'view') {\n // 2026-07-08 A 案:view 態零恆顯 icon(同 DateCell 註)\n return <PeoplePicker key=\"view\" variant=\"naked\" mode=\"view\" value={value as PersonValue | null} size={size} />\n }\n return (\n <PeoplePicker\n key=\"edit\"\n variant=\"naked\"\n size={sizeForInput(size)}\n value={value as PersonValue | null}\n people={meta?.people ?? []}\n // PeoplePicker onChange 永遠 emit array(API contract);single mode commit 取首位\n onChange={(next) => onCommit?.(next[0] ?? null)}\n defaultOpen\n onOpenChange={dismissOnClose(onCancel)}\n />\n )\n}\n\nfunction MultiPersonCell({ value, mode, size, onCommitLive, onCancel, meta }: CellComponentProps) {\n if (mode === 'view') {\n // 2026-07-08 A 案:view 態零恆顯 icon(同 DateCell 註)\n return <PeoplePicker key=\"view\" variant=\"naked\" mode=\"view\" value={(value as PersonValue[]) ?? []} size={size} />\n }\n // Multi 用 onCommitLive(commit 但不 exit edit)— 每勾一人即時生效,popover 持續開\n // 直到點外面;onOpenChange(false) → onCancel exit edit。對齊 multiSelect canonical。\n return (\n <PeoplePicker\n key=\"edit\"\n variant=\"naked\"\n size={sizeForInput(size)}\n value={Array.isArray(value) ? (value as PersonValue[]) : []}\n people={meta?.people ?? []}\n onChange={(next) => onCommitLive?.(next)}\n defaultOpen\n onOpenChange={dismissOnClose(onCancel)}\n />\n )\n}\n\nfunction BooleanCell({ value, mode, meta, size, isEditable, onCommit }: CellComponentProps) {\n // boolean 不分 read/edit mode — view 渲 mode='view' 純展示;editable 時直接 toggle Checkbox。\n // 不可編(!isEditable)→ 走 view branch,Checkbox mode=\"view\" 純展示不接 onCheckedChange。\n if (mode === 'view' && !isEditable) {\n // size 傳入 → boolean 值 icon(Check/X)@lg 縮放對齊其他 cell(對齊 editable 分支同 size 邏輯)\n return <Checkbox variant=\"naked\" size={size === 'lg' ? 'lg' : 'md'} mode=\"view\" checked={value === true} />\n }\n return (\n <Checkbox\n size={size === 'lg' ? 'lg' : 'md'}\n checked={value === true}\n onCheckedChange={(checked) => onCommit?.(checked === true)}\n aria-label={meta?.ariaLabel ?? '切換'}\n />\n )\n}\n\n/**\n * UrlCell(2026-07-14 docblock 對齊實作):\n * view branch = `<LinkInput mode=\"view\">`(URL parse / hostname\n * 顯示一致性 SSOT);editable 互動:hover 時右側出 Pencil 鈕 → 進 edit(保留 link click 語意)。\n * edit branch = plain `<Input variant=\"naked\">`(LinkInput edit 的 controlled value 衝突\n * revert,詳下方 edit branch 註解);URL 驗證 deferred 到 onCommit(consumer 端 validate)。\n */\nfunction UrlCell({ value, meta, mode, size, isEditable, onRequestEdit, onCommit, onCancel }: CellComponentProps) {\n if (mode === 'view') {\n // showDisplayEndIcon ← D path Phase 2(2026-05-08):Field naked wrapper 包 anchor,與 Input edit 同 chrome。\n // LinkInput 此 prop = wrapper-only(無 icon,field.spec.md L6 例外)→ A 案(2026-07-08)不撤;\n // 但修 I1:原無條件 true 違反「= isEditable」knob 等式(field-controls.spec.md cell 例外),改等式。\n const display = (\n <LinkInput variant=\"naked\" mode=\"view\" value={value as string | null} label={meta?.linkLabel} size={size} showDisplayEndIcon={isEditable === true} />\n )\n // 不可編 URL 不顯 Pencil affordance(純 view 顯示連結,無編輯入口)\n if (!isEditable) return display\n // editable read mode:hover Pencil 鈕(對齊 spec 第十二段「url:read = 連結 + Pencil」)\n return (\n <span className=\"group/cell relative flex items-center w-full\"> {/* @naked-row-mode-allow: URL hover-Pencil 是 inline action 不是 value content,items-center 鎖 Pencil 對齊行高第一行(autoRow 跟 fixed 皆同視覺正確) */}\n <span className=\"flex-1 min-w-0\">{display}</span>\n <Button\n variant=\"tertiary\"\n size=\"xs\"\n iconOnly\n startIcon={Pencil}\n aria-label=\"編輯連結\"\n className={cn('ml-1 opacity-0 group-hover/cell:opacity-100 transition-opacity')}\n onClick={(e) => {\n e.stopPropagation()\n onRequestEdit?.()\n }}\n />\n </span>\n )\n }\n // edit mode value pre-fill canonical(2026-05-05):LinkInput edit `value` prop 強制 controlled\n // (line 113 `useState(value ?? '')`)+ `showLink = !editing && hasValidValue` 預設顯 link 不顯 input\n // → cell-as-input editing 場景需要 input 直接 focus 編輯。改用 plain `<Input>`(uncontrolled\n // `defaultValue` 正確 pre-fill,Input.tsx `value={value}` 是 undefined → uncontrolled 走 defaultValue)。\n // URL 驗證等 deferred 到 commit phase(consumer 可在 onCommit 時 validate)。\n return (\n <Input\n autoFocus\n variant=\"naked\"\n size={sizeForInput(size)}\n defaultValue={value != null ? String(value) : ''}\n onBlur={(e) => onCommit?.(e.target.value)}\n onKeyDown={makeKeyHandler(onCommit, onCancel)}\n />\n )\n}\n\n// ── Registry ────────────────────────────────────────────────────────────────\n//\n// type → cell component。新增 columnType 必同步註冊一條(否則 fallback 到 string)。\n\nexport const cellRegistry: Record<ColumnType, ComponentType<CellComponentProps>> = {\n string: StringCell,\n number: NumberCell,\n currency: NumberCell, // 共用 NumberCell — currency-ness 走 meta.type 判 prefix='$'\n date: DateCell,\n time: TimeCell,\n select: SelectCell,\n multiSelect: MultiSelectCell,\n person: PersonCell,\n multiPerson: MultiPersonCell,\n boolean: BooleanCell,\n url: UrlCell,\n}\n\n/** Resolve cell component by type;default = StringCell(consumer 沒設 type 的 fallback)。\n * 2026-05-12 Stream C Cluster B fix:wrap with FieldSurfaceProvider `surface='table-cell'`\n * 讓所有 Cell 內的 Field family controls 透過 `useFieldSurface()` 取得「我在 cell 裡」context,\n * 取代散落的 `variant === 'naked'` cell-detection heuristic + per-prop hardcoded padding。\n *\n * **2026-05-13 (a) perf fix(user 拍板 + codex V1 verdict + Layer A grep root cause)**:\n * 原 factory pattern 每次 call 在 function body 內宣告新 `CellWithSurface` FC closure → 每 scroll\n * × 每 visible cell 都 return 新 FC reference → React 認 component type 變,**整 subtree mount/\n * unmount cascade**(Field + ItemPrefix/Suffix + Avatar / Tag / PersonDisplay)。\n * Fix:每 ColumnType **module-level 預建** wrapped FC + `React.memo`,resolve 走 cached map,\n * identity stable across scroll → memo 真生效 + subtree 不 mount/unmount。\n * Cite world-class:AG Grid「cell renderer per-type stable reference」/ MUI X DataGrid「memoized\n * subcomponents」/ Glide Data Grid「DOM virtualization 加解掛 = bottleneck」。 */\nconst cellWithSurfaceCache = new Map<ColumnType | '_default_', ComponentType<CellComponentProps>>()\n\nfunction buildCellWithSurface(Inner: ComponentType<CellComponentProps>, key: string): ComponentType<CellComponentProps> {\n const CellWithSurface = React.memo(function CellWithSurface(props: CellComponentProps) {\n return (\n <FieldSurfaceProvider surface=\"table-cell\">\n {/* 2026-06-08:把 table-density size 經獨立 surface-size context 注給 child Field controls,\n 漏傳 size 的 cell 也自動繼承(根治「新 cell 漏傳 size」class);size primitive 不破壞 memo identity。*/}\n <FieldSurfaceSizeProvider size={props.size}>\n {/* 2026-07-08 user 拍板:cell 可編輯訊號經獨立 boolean context 注給 child Field controls,\n 讓 useFieldEmptyDisplay 分流「可編輯 cell 空 view → 空白」vs「不可編輯 cell → '-'」。\n boolean primitive 不破壞 memo identity(同 size context)。 */}\n <FieldSurfaceEditableProvider isEditable={props.isEditable ?? false}>\n <Inner {...props} />\n </FieldSurfaceEditableProvider>\n </FieldSurfaceSizeProvider>\n </FieldSurfaceProvider>\n )\n })\n ;(CellWithSurface as { displayName?: string }).displayName = `CellWithSurface(${key})`\n return CellWithSurface as ComponentType<CellComponentProps>\n}\n\n// Pre-build per-type cached wrapped components(module-level,one-time init)\nfor (const type of Object.keys(cellRegistry) as ColumnType[]) {\n cellWithSurfaceCache.set(type, buildCellWithSurface(cellRegistry[type], type))\n}\ncellWithSurfaceCache.set('_default_', buildCellWithSurface(StringCell, 'StringCell-fallback'))\n\nexport function resolveCellComponent(type?: ColumnType): ComponentType<CellComponentProps> {\n return cellWithSurfaceCache.get(type ?? '_default_') ?? cellWithSurfaceCache.get('_default_')!\n}\n"],"names":["InputPublic","TextareaPublic","NumberInputPublic","SelectPublic","ComboboxPublic","DatePickerPublic","TimePickerPublic","PeoplePickerPublic","LinkInputPublic","CheckboxPublic","CellWithSurface"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"cell-registry.js","sources":["../../../src/components/DataTable/cell-registry.tsx"],"sourcesContent":["// @benchmark-unverified-blanket: file-level retraction per M22 (d) — claims herein not individually URL-cited; treat as unverified visual/usage rumor unless retrofit per-claim. Hook escape preserved.\n// code-quality-allow: file-size — Cell Registry 含 10 cell-type components(string/number/date/time/select/multiSelect/person/multiPerson/boolean/url)+ shared helpers,split-into-files 會破壞 type-keyed registry SSOT canonical\n// DataTable Cell Registry — type-keyed SSOT for cell rendering(Phase C 2026-05-05)\n//\n// 對齊 M17 SSOT consolidation + audit recommendation:\n// 原 `renderTypedValue` switch + `EditableCellContent` switch 兩條平行 type-switch 已 collapse\n// 為**一張 type → cell component** registry。每個 cell component 同時處理 view / edit mode,\n// 靠底層 Field control 的 `mode` prop 切換。\n//\n// 設計原則:\n// - 每個 cell component 接同一組 props(`CellComponentProps`)\n// - 用 `variant=\"naked\"` — DataTable cell-as-input substrate(Field chrome variant;bare 2026-07-09 退役)\n// - 消費 full Field 家族 primitive(無 stub)\n// - 不再用 `meta._editable` 私有 flag — `isEditable` 直接顯式入參(消除 M1 hack)\n//\n// World-class 對照(@benchmark-unverified):AG Grid cellRendererSelector / Material X-Grid\n// `valueGetter + renderCell` / Notion property type registry。\n\nimport * as React from 'react'\nimport type { ComponentType } from 'react'\nimport { Pencil } from 'lucide-react'\nimport { cn, lineClampClass } from '@/lib/utils'\nimport type { ColumnType } from './column-types'\nimport { Input as InputPublic } from '@/design-system/components/Input/input'\nimport { Textarea as TextareaPublic } from '@/design-system/components/Textarea/textarea'\nimport { NumberInput as NumberInputPublic } from '@/design-system/components/NumberInput/number-input'\nimport { Select as SelectPublic } from '@/design-system/components/Select/select'\nimport { Combobox as ComboboxPublic } from '@/design-system/components/Combobox/combobox'\nimport { DatePicker as DatePickerPublic } from '@/design-system/components/DatePicker/date-picker'\nimport { TimePicker as TimePickerPublic } from '@/design-system/components/TimePicker/time-picker'\nimport { PeoplePicker as PeoplePickerPublic } from '@/design-system/components/PeoplePicker/people-picker'\nimport { LinkInput as LinkInputPublic } from '@/design-system/components/LinkInput/link-input'\nimport { Checkbox as CheckboxPublic } from '@/design-system/components/Checkbox/checkbox'\nimport { Button } from '@/design-system/components/Button/button'\nimport type { PersonValue } from '@/design-system/components/PeoplePicker/person-display'\nimport { FieldSurfaceProvider, FieldSurfaceSizeProvider, FieldSurfaceEditableProvider } from '@/design-system/components/Field/field-context'\nimport { makeEditSettleKeyHandler } from '@/design-system/components/Field/field-edit-keys'\nimport type { WithFieldVariantInternal } from '@/design-system/components/Field/field-types'\n\n// ── @internal naked variant 通道(2026-07-14 API 策展 E,user 拍板「全部收窄」)──────────────\n// `naked` 已從公開 FieldVariant 拆出(field-types.ts `FieldVariantInternal`);本檔是唯一合法\n// naked 消費者(field-controls.spec.md「軸二 variant」明文)。以 `WithFieldVariantInternal`\n// 型別層 widen 各 Field control 的 `variant` prop — 純型別、零 runtime;元件內部 cva / resolver\n// 分支本就吃 FieldVariantInternal,widen 不引入 unsound 行為。\nconst Input = InputPublic as WithFieldVariantInternal<typeof InputPublic>\nconst Textarea = TextareaPublic as WithFieldVariantInternal<typeof TextareaPublic>\nconst NumberInput = NumberInputPublic as WithFieldVariantInternal<typeof NumberInputPublic>\nconst Select = SelectPublic as WithFieldVariantInternal<typeof SelectPublic>\nconst Combobox = ComboboxPublic as WithFieldVariantInternal<typeof ComboboxPublic>\nconst DatePicker = DatePickerPublic as WithFieldVariantInternal<typeof DatePickerPublic>\nconst TimePicker = TimePickerPublic as WithFieldVariantInternal<typeof TimePickerPublic>\nconst PeoplePicker = PeoplePickerPublic as WithFieldVariantInternal<typeof PeoplePickerPublic>\nconst LinkInput = LinkInputPublic as WithFieldVariantInternal<typeof LinkInputPublic>\nconst Checkbox = CheckboxPublic as WithFieldVariantInternal<typeof CheckboxPublic>\n\n// ── Types ────────────────────────────────────────────────────────────────────\n\nexport type CellMode = 'view' | 'edit'\nexport type CellSize = 'sm' | 'md' | 'lg'\n\nexport interface CellComponentProps {\n // any-allow: free-form column value(consumer-defined,跨 type 共用 signature)\n value: any\n // any-allow: free-form consumer meta bag(prefix / options / formatOptions / locale / linkLabel 等)\n meta: Record<string, any>\n mode: CellMode\n size: CellSize\n /** 該 cell 的 accessible name(= 欄標題)。naked Field 控件在 cell 內無 FieldLabel,\n * 漏此名 → editor 成無名控件(axe aria-input-field-name / select-name)。由 renderCellContent\n * 從 columnDef.header 解析後注入。對齊 AG Grid / MUI X「editor aria-label = column headerName」。 */\n ariaLabel?: string\n autoRowHeight: boolean\n /** 該 cell 是否可編。replaces 舊 `meta._editable` 私有 flag(Phase C M1 hack 移除)。 */\n isEditable?: boolean\n /** Cell 進 edit mode → 提交新值(blur / Enter / option select 都觸發)— 提交後**自動 exit edit**。\n * 適用 single-shot commit:string / number / select(single)/ person(single)/ date / time / boolean / url。 */\n onCommit?: (next: unknown) => void\n /** Live commit — 提交新值但 **不 exit edit**(popover 持續開)。\n * 適用 multi-select 類:multiSelect / multiPerson — user 連續勾選,直到點外面才關。\n * 對齊 Notion / Linear / Airtable canonical:multi-pick popover 不在每次 toggle 後關閉。 */\n onCommitLive?: (next: unknown) => void\n /** Esc 取消編輯,不 commit。 */\n onCancel?: () => void\n /** URL cell 專用:hover 顯示的 Pencil 鈕 → 進 edit mode(read mode 保留 link click 語意)。 */\n onRequestEdit?: () => void\n /** Per-keystroke draft propagation(2026-05-10 Phase 7 D.3 portal Field virtualizer unmount preserve draft):\n * Edit mode 內部 input onChange/onValueChange 每 keystroke 呼叫 onDraft,讓 lifted draft state(in\n * data-table.tsx)持有 user 編輯中字。Cell DOM unmount(virtualizer scroll out)時 draft 在\n * parent state 不丟;mount-back 時 portal Field value 從 draft 取,user 字保留。\n * 非 portal mode(inline edit)不傳此 prop,各 Cell 走原 uncontrolled defaultValue 路徑。 */\n onDraft?: (next: unknown) => void\n}\n\n// ── Helpers ──────────────────────────────────────────────────────────────────\n\n/** 鍵盤 commit / cancel — string / number cell edit mode 共用 */\nfunction makeKeyHandler(\n onCommit?: (v: unknown) => void,\n onCancel?: () => void,\n parseValue?: (raw: string) => unknown,\n) {\n // 消費 edit-in-place 鍵盤結算 SSOT(field-edit-keys.ts):IME guard + Enter/Esc dispatch 統一\n // (2026-07-09 抽出;原本 InlineEdit 漏 IME guard = bug,現同源)。value 讀取為 input-specific,留本地。\n return makeEditSettleKeyHandler({\n onCommit: (e) => {\n const raw = (e.target as HTMLInputElement).value\n onCommit?.(parseValue ? parseValue(raw) : raw)\n },\n onCancel: () => onCancel?.(),\n })\n}\n\nconst sizeForInput = (size: CellSize): CellSize => size\n\n// 2026-07-16 round16:cell「disabled」態廢除(世界級 grid 無 disabled cell — MUI X / AG Grid /\n// Handsontable 皆只有 editable/readonly;meta.disabled 全庫 0 消費)。cell view 態一律 mode=\"view\",\n// 鎖定用 `editable:(row)=>false` 閘(= isCellEditable 模型)。原 displayOrDisabled helper 已移除。\n\n// ── Cell Components ──────────────────────────────────────────────────────────\n\nfunction StringCell({ value, meta, mode, size, autoRowHeight, onCommit, onCancel, onDraft, ariaLabel }: CellComponentProps) {\n // 2026-05-14 I9 fix(per codex+Layer A 共識):meta.maxLines opt-in line-clamp。\n // view autoRow 用 Tailwind arbitrary line-clamp 支援 N rows;edit textarea field-sizing\n // 已 auto-grow to content,natural match clamp。\n // 2026-05-16 Round 5 audit Dim 27 fix:narrow type 取代 `as any` cast。\n const maxLines: number | undefined = (meta as { maxLines?: number } | undefined)?.maxLines\n const clampClass = autoRowHeight ? lineClampClass(maxLines) : undefined\n // string type canonical(2026-05-05 v2 user 校正:input space ≥ display space):\n // - autoRowHeight: Textarea(view + edit)— view wrap text 撐高 row,edit textarea\n // 多行輸入、`!h-full` 填 cell。對齊 Notion long-text cell canonical。\n // - fixed: Input(view + edit)— 單行 truncate view,單行 input edit;Field naked intrinsic\n // 高 = cell 高 = h-field-md,文字位置 view↔edit 完全一致。對齊 AG Grid / Material X-Grid。\n // - autoRowHeight 是 table 框架決定(consumer 不需 per-column 設 meta.wrap)。\n // - 互動(Textarea):Esc cancel / Cmd|Ctrl+Enter commit / blur commit;Enter 保留換行\n // - 互動(Input):Esc cancel / Enter commit / blur commit\n const v = value != null ? String(value) : ''\n if (mode === 'view') {\n // size 必傳:DataTable cell 字級隨 size 變(sm/md text-body / lg text-body-lg),\n // 對齊 Field family size→font SSOT(field-wrapper.tsx:60-64)。漏傳 → fallback md → lg 表格\n // 字卡 14px 跟 Select/Date 等有傳 size 的 cell 不一致(2026-06-08 user 抓 frozen string 欄字偏小)。\n return autoRowHeight\n ? <Textarea variant=\"naked\" mode=\"view\" value={v} size={size} className={clampClass} aria-label={ariaLabel} />\n : <Input variant=\"naked\" mode=\"view\" value={v} size={size} aria-label={ariaLabel} />\n }\n if (autoRowHeight) {\n // 2026-05-14 I8 fix(per codex verdict + user 抓「edit cell shrink」):\n // 原 `wrapRows = value.length / 40` 字元估算不準(對應實際 column width 不同\n // → cell 進 edit shrink)。改 CSS `field-sizing: content`(Chrome 123+ / FF 122+ /\n // Safari 17+)讓 textarea 自動 grow to content,匹配 view wrap 真實高度。\n // Fallback rows 仍保留給舊 browser(rows attr 在 field-sizing 支援時被覆蓋)。\n return (\n <Textarea\n autoFocus\n variant=\"naked\"\n aria-label={ariaLabel}\n size={sizeForInput(size)}\n // 2026-07-28:原本 field-sizing + rows 估算是本檔的呼叫端膠水,只有 cell 有、InlineEdit 沒有\n // → 兩者 edit 高度漂移。已提升為 Textarea `autoSize` 能力,兩個語境共用同一份實作。\n autoSize\n defaultValue={v}\n onChange={(e) => onDraft?.((e.target as HTMLTextAreaElement).value)}\n onBlur={(e) => onCommit?.((e.target as HTMLTextAreaElement).value)}\n // 多行:走 edit-in-place 鍵盤結算 SSOT(IME guard + Esc + Cmd/Ctrl+Enter commit;\n // plain Enter=換行)。commitOnEnter:false → 純 Enter 不攔。\n onKeyDown={makeEditSettleKeyHandler({\n onCommit: (e) => onCommit?.((e.target as HTMLTextAreaElement).value),\n onCancel: () => onCancel?.(),\n commitOnEnter: false,\n })}\n />\n )\n }\n return (\n <Input\n autoFocus\n variant=\"naked\"\n aria-label={ariaLabel}\n size={sizeForInput(size)}\n defaultValue={v}\n onChange={(e) => onDraft?.(e.target.value)}\n onBlur={(e) => onCommit?.(e.target.value)}\n onKeyDown={makeKeyHandler(onCommit, onCancel)}\n />\n )\n}\n\nfunction NumberCell({ value, meta, mode, size, onCommit, onCancel, onDraft, ariaLabel }: CellComponentProps) {\n // currency 透過 columnType-aware prefix:type='currency' → 預設 '$'(可 override)\n const isCurrency = meta?.type === 'currency'\n const prefix = isCurrency ? (meta?.prefix ?? '$') : meta?.prefix\n // React #310 fix:useState 必在 view early-return 前無條件呼叫。同一 memo'd cell instance\n // 在 view↔edit 切換時被重用(render site 無 key={mode},data-table.tsx:1352),hook 數量不可變,\n // 否則 Rules of Hooks violation → React #310 crash。對齊 combobox/select hoist pattern。\n const initial = typeof value === 'number' ? value : null\n const [localValue, setLocalValue] = React.useState<number | null>(initial)\n if (mode === 'view') {\n return (\n <NumberInput\n variant=\"naked\"\n mode=\"view\"\n aria-label={ariaLabel}\n value={value as number | null}\n // size 必傳(同 StringCell)— currency/number cell 字級隨 DataTable size 變,對齊 Field SSOT。\n size={size}\n prefix={prefix}\n suffix={meta?.suffix}\n precision={meta?.precision}\n locale={meta?.locale}\n />\n )\n }\n // Edit mode value pre-fill canonical(2026-05-05):NumberInput edit 強制 controlled\n // (`value={value ?? ''}`)— 若 NumberCell 以 `defaultValue` 傳入,NumberInput value=undefined → ''\n // empty。對齊 cell-as-input「edit mode 自動帶入 view 值」(對齊 Notion / Airtable 共識),\n // 改用 local state controlled。User typing → setLocalValue;blur/Enter → onCommit(localValue)。\n // (initial + useState 已 hoist 到 view-return 前 — 見上方 React #310 fix。)\n return (\n <NumberInput\n autoFocus\n variant=\"naked\"\n aria-label={ariaLabel}\n size={sizeForInput(size)}\n value={localValue}\n onChange={(v) => { setLocalValue(v); onDraft?.(v) }}\n prefix={prefix}\n suffix={meta?.suffix}\n precision={meta?.precision}\n onBlur={() => onCommit?.(localValue)}\n // 單行:走 edit-in-place 鍵盤結算 SSOT(IME guard + Esc + Enter commit)。\n // commit localValue(controlled state,非 e.target.value)。\n onKeyDown={makeEditSettleKeyHandler({\n onCommit: () => onCommit?.(localValue),\n onCancel: () => onCancel?.(),\n })}\n />\n )\n}\n\n// Cell-as-input dismiss canonical(2026-05-05):defaultOpen=true 開始 → user click 外 popover 關\n// → 元件 fire onOpenChange(false) → cell call onCancel exit edit。否則 cell 卡 edit mode 不可 re-trigger\n// (對齊 Airtable / Notion canonical:click 外即關)。\nconst dismissOnClose = (onCancel?: () => void) => (open: boolean) => { if (!open) onCancel?.() }\n\n// Mode-keyed remount canonical(2026-05-05):view↔edit 切換時,因 React reconciliation 同 type 同\n// position 會重用 instance,導致 `useState(defaultOpen)` 只在首次 mount 跑(那時 mode='view'\n// defaultOpen 沒給→預設 false)。後續 mode='edit' 即使傳 defaultOpen=true 也無效。\n// Fix:`key={mode}` 強制 React unmount + remount,每次切 mode 都重跑 useState init。\n// 對齊 Notion / Airtable cell-as-input「view 跟 edit 是不同 mount cycle」語義。\n\nfunction DateCell({ value, meta, mode, size, onCommit, onCancel }: CellComponentProps) {\n if (mode === 'view') {\n return (\n <DatePicker\n key=\"view\"\n variant=\"naked\"\n mode=\"view\"\n value={value as string | null}\n size={size}\n formatOptions={meta?.formatOptions}\n locale={meta?.locale}\n // 2026-07-08 user 拍板 A 案(推翻 2026-05-10/06-26 兩次拍板,per 6 家 benchmark 6/6 共識\n // Ant/MUI X/AG Grid/Atlaskit/Notion/Airtable:view 態零恆顯型別 icon;editable\n // affordance 統一 = hover outline(field.spec.md L4)。showDisplayEndIcon 不再傳\n //(prop 保留為 spreadsheet-flavored 消費端 opt-in 逃生門,見 field.spec.md L6)。\n />\n )\n }\n return (\n <DatePicker\n key=\"edit\"\n autoFocus\n variant=\"naked\"\n size={sizeForInput(size)}\n value={typeof value === 'string' ? value : null}\n showTime={meta?.includeTime === true}\n onChange={(v) => onCommit?.(v)}\n defaultOpen\n onOpenChange={dismissOnClose(onCancel)}\n />\n )\n}\n\nfunction TimeCell({ value, meta, mode, size, onCommit, onCancel }: CellComponentProps) {\n if (mode === 'view') {\n return (\n <TimePicker\n key=\"view\"\n variant=\"naked\"\n mode=\"view\"\n value={value as string | null}\n size={size}\n formatOptions={meta?.formatOptions}\n locale={meta?.locale}\n // showDisplayEndIcon 不傳 — 2026-07-08 A 案:view 態零恆顯 icon(同 DateCell 註)\n />\n )\n }\n return (\n <TimePicker\n key=\"edit\"\n variant=\"naked\"\n size={sizeForInput(size)}\n value={typeof value === 'string' ? value : null}\n showSeconds={meta?.showSeconds === true}\n minuteStep={meta?.minuteStep}\n secondStep={meta?.secondStep}\n onChange={(v) => onCommit?.(v)}\n defaultOpen\n onOpenChange={dismissOnClose(onCancel)}\n />\n )\n}\n\nfunction SelectCell({ value, meta, mode, size, onCommit, onCancel }: CellComponentProps) {\n // View canonical(2026-05-05):cell IS variant,default plain text(no Tag pill 疊在 cell border 內)。\n // Consumer 可在 column meta.display='tag' opt-in 內容導向的 Tag 視覺(category 含色彩標籤等)。\n // 對齊 JTable / AG Grid「renderer/editor 視覺一致」canonical。\n const displayMode = (meta?.display as 'plain' | 'tag' | undefined) ?? 'plain'\n if (mode === 'view') {\n return (\n <Select\n key=\"view\"\n variant=\"naked\"\n mode=\"view\"\n value={value as string | null}\n options={meta?.options ?? []}\n size={size}\n display={displayMode}\n // showDisplayEndIcon 不傳 — 2026-07-08 A 案:view 態零恆顯 icon(同 DateCell 註)\n selectedItemRenderer={meta?.selectedItemRenderer} // 2026-07-08 WM 戰役:status 類彩色 cell 顯示通道\n />\n )\n }\n return (\n <Select\n key=\"edit\"\n autoFocus\n variant=\"naked\"\n size={sizeForInput(size)}\n selectedItemRenderer={meta?.selectedItemRenderer}\n options={meta?.options ?? []}\n value={value as string | null | undefined}\n onChange={(v) => onCommit?.(v)}\n // B7(2026-05-05):cell 編輯時支援 inline search,沿用 Select.searchable 機制(對齊 cell-as-input\n // 「沿用既有輸入框互動」原則)。Default false,consumer 在 meta.searchable 開啟。\n searchable={meta?.searchable === true}\n display={displayMode}\n defaultOpen\n onOpenChange={dismissOnClose(onCancel)}\n />\n )\n}\n\nfunction MultiSelectCell({ value, meta, mode, size, autoRowHeight, onCommitLive, onCancel }: CellComponentProps) {\n const wrap = autoRowHeight && meta?.wrap === true\n if (mode === 'view') {\n return (\n <Combobox\n key=\"view\"\n variant=\"naked\"\n mode=\"view\"\n value={(value as string[] | null) ?? []}\n options={meta?.options ?? []}\n wrap={wrap}\n size={size}\n // showDisplayEndIcon 不傳 — 2026-07-08 A 案:view 態零恆顯 icon(同 DateCell 註)\n />\n )\n }\n // Multi 用 onCommitLive(commit 但不 exit edit)— 每勾一項即時生效,popover 持續開\n // 直到點外面;onOpenChange(false) → onCancel exit edit。對齊 Notion / Linear / Airtable canonical。\n return (\n <Combobox\n key=\"edit\"\n variant=\"naked\"\n size={sizeForInput(size)}\n options={meta?.options ?? []}\n value={Array.isArray(value) ? (value as string[]) : []}\n onChange={(v) => onCommitLive?.(v)}\n defaultOpen\n onOpenChange={dismissOnClose(onCancel)}\n />\n )\n}\n\nfunction PersonCell({ value, mode, size, onCommit, onCancel, meta }: CellComponentProps) {\n if (mode === 'view') {\n // 2026-07-08 A 案:view 態零恆顯 icon(同 DateCell 註)\n return <PeoplePicker key=\"view\" variant=\"naked\" mode=\"view\" value={value as PersonValue | null} size={size} />\n }\n return (\n <PeoplePicker\n key=\"edit\"\n variant=\"naked\"\n size={sizeForInput(size)}\n value={value as PersonValue | null}\n people={meta?.people ?? []}\n // PeoplePicker onChange 永遠 emit array(API contract);single mode commit 取首位\n onChange={(next) => onCommit?.(next[0] ?? null)}\n defaultOpen\n onOpenChange={dismissOnClose(onCancel)}\n />\n )\n}\n\nfunction MultiPersonCell({ value, mode, size, onCommitLive, onCancel, meta }: CellComponentProps) {\n if (mode === 'view') {\n // 2026-07-08 A 案:view 態零恆顯 icon(同 DateCell 註)\n return <PeoplePicker key=\"view\" variant=\"naked\" mode=\"view\" value={(value as PersonValue[]) ?? []} size={size} />\n }\n // Multi 用 onCommitLive(commit 但不 exit edit)— 每勾一人即時生效,popover 持續開\n // 直到點外面;onOpenChange(false) → onCancel exit edit。對齊 multiSelect canonical。\n return (\n <PeoplePicker\n key=\"edit\"\n variant=\"naked\"\n size={sizeForInput(size)}\n value={Array.isArray(value) ? (value as PersonValue[]) : []}\n people={meta?.people ?? []}\n onChange={(next) => onCommitLive?.(next)}\n defaultOpen\n onOpenChange={dismissOnClose(onCancel)}\n />\n )\n}\n\nfunction BooleanCell({ value, mode, meta, size, isEditable, onCommit }: CellComponentProps) {\n // boolean 不分 read/edit mode — view 渲 mode='view' 純展示;editable 時直接 toggle Checkbox。\n // 不可編(!isEditable)→ 走 view branch,Checkbox mode=\"view\" 純展示不接 onCheckedChange。\n if (mode === 'view' && !isEditable) {\n // size 傳入 → boolean 值 icon(Check/X)@lg 縮放對齊其他 cell(對齊 editable 分支同 size 邏輯)\n return <Checkbox variant=\"naked\" size={size === 'lg' ? 'lg' : 'md'} mode=\"view\" checked={value === true} />\n }\n return (\n <Checkbox\n size={size === 'lg' ? 'lg' : 'md'}\n checked={value === true}\n onCheckedChange={(checked) => onCommit?.(checked === true)}\n aria-label={meta?.ariaLabel ?? '切換'}\n />\n )\n}\n\n/**\n * UrlCell(2026-07-14 docblock 對齊實作):\n * view branch = `<LinkInput mode=\"view\">`(URL parse / hostname\n * 顯示一致性 SSOT);editable 互動:hover 時右側出 Pencil 鈕 → 進 edit(保留 link click 語意)。\n * edit branch = plain `<Input variant=\"naked\">`(LinkInput edit 的 controlled value 衝突\n * revert,詳下方 edit branch 註解);URL 驗證 deferred 到 onCommit(consumer 端 validate)。\n */\nfunction UrlCell({ value, meta, mode, size, isEditable, onRequestEdit, onCommit, onCancel }: CellComponentProps) {\n if (mode === 'view') {\n // showDisplayEndIcon ← D path Phase 2(2026-05-08):Field naked wrapper 包 anchor,與 Input edit 同 chrome。\n // LinkInput 此 prop = wrapper-only(無 icon,field.spec.md L6 例外)→ A 案(2026-07-08)不撤;\n // 但修 I1:原無條件 true 違反「= isEditable」knob 等式(field-controls.spec.md cell 例外),改等式。\n const display = (\n <LinkInput variant=\"naked\" mode=\"view\" value={value as string | null} label={meta?.linkLabel} size={size} showDisplayEndIcon={isEditable === true} />\n )\n // 不可編 URL 不顯 Pencil affordance(純 view 顯示連結,無編輯入口)\n if (!isEditable) return display\n // editable read mode:hover Pencil 鈕(對齊 spec 第十二段「url:read = 連結 + Pencil」)\n return (\n <span className=\"group/cell relative flex items-center w-full\"> {/* @naked-row-mode-allow: URL hover-Pencil 是 inline action 不是 value content,items-center 鎖 Pencil 對齊行高第一行(autoRow 跟 fixed 皆同視覺正確) */}\n <span className=\"flex-1 min-w-0\">{display}</span>\n <Button\n variant=\"tertiary\"\n size=\"xs\"\n iconOnly\n startIcon={Pencil}\n aria-label=\"編輯連結\"\n className={cn('ml-1 opacity-0 group-hover/cell:opacity-100 transition-opacity')}\n onClick={(e) => {\n e.stopPropagation()\n onRequestEdit?.()\n }}\n />\n </span>\n )\n }\n // edit mode value pre-fill canonical(2026-05-05):LinkInput edit `value` prop 強制 controlled\n // (line 113 `useState(value ?? '')`)+ `showLink = !editing && hasValidValue` 預設顯 link 不顯 input\n // → cell-as-input editing 場景需要 input 直接 focus 編輯。改用 plain `<Input>`(uncontrolled\n // `defaultValue` 正確 pre-fill,Input.tsx `value={value}` 是 undefined → uncontrolled 走 defaultValue)。\n // URL 驗證等 deferred 到 commit phase(consumer 可在 onCommit 時 validate)。\n return (\n <Input\n autoFocus\n variant=\"naked\"\n size={sizeForInput(size)}\n defaultValue={value != null ? String(value) : ''}\n onBlur={(e) => onCommit?.(e.target.value)}\n onKeyDown={makeKeyHandler(onCommit, onCancel)}\n />\n )\n}\n\n// ── Registry ────────────────────────────────────────────────────────────────\n//\n// type → cell component。新增 columnType 必同步註冊一條(否則 fallback 到 string)。\n\nexport const cellRegistry: Record<ColumnType, ComponentType<CellComponentProps>> = {\n string: StringCell,\n number: NumberCell,\n currency: NumberCell, // 共用 NumberCell — currency-ness 走 meta.type 判 prefix='$'\n date: DateCell,\n time: TimeCell,\n select: SelectCell,\n multiSelect: MultiSelectCell,\n person: PersonCell,\n multiPerson: MultiPersonCell,\n boolean: BooleanCell,\n url: UrlCell,\n}\n\n/** Resolve cell component by type;default = StringCell(consumer 沒設 type 的 fallback)。\n * 2026-05-12 Stream C Cluster B fix:wrap with FieldSurfaceProvider `surface='table-cell'`\n * 讓所有 Cell 內的 Field family controls 透過 `useFieldSurface()` 取得「我在 cell 裡」context,\n * 取代散落的 `variant === 'naked'` cell-detection heuristic + per-prop hardcoded padding。\n *\n * **2026-05-13 (a) perf fix(user 拍板 + codex V1 verdict + Layer A grep root cause)**:\n * 原 factory pattern 每次 call 在 function body 內宣告新 `CellWithSurface` FC closure → 每 scroll\n * × 每 visible cell 都 return 新 FC reference → React 認 component type 變,**整 subtree mount/\n * unmount cascade**(Field + ItemPrefix/Suffix + Avatar / Tag / PersonDisplay)。\n * Fix:每 ColumnType **module-level 預建** wrapped FC + `React.memo`,resolve 走 cached map,\n * identity stable across scroll → memo 真生效 + subtree 不 mount/unmount。\n * Cite world-class:AG Grid「cell renderer per-type stable reference」/ MUI X DataGrid「memoized\n * subcomponents」/ Glide Data Grid「DOM virtualization 加解掛 = bottleneck」。 */\nconst cellWithSurfaceCache = new Map<ColumnType | '_default_', ComponentType<CellComponentProps>>()\n\nfunction buildCellWithSurface(Inner: ComponentType<CellComponentProps>, key: string): ComponentType<CellComponentProps> {\n const CellWithSurface = React.memo(function CellWithSurface(props: CellComponentProps) {\n return (\n <FieldSurfaceProvider surface=\"table-cell\">\n {/* 2026-06-08:把 table-density size 經獨立 surface-size context 注給 child Field controls,\n 漏傳 size 的 cell 也自動繼承(根治「新 cell 漏傳 size」class);size primitive 不破壞 memo identity。*/}\n <FieldSurfaceSizeProvider size={props.size}>\n {/* 2026-07-08 user 拍板:cell 可編輯訊號經獨立 boolean context 注給 child Field controls,\n 讓 useFieldEmptyDisplay 分流「可編輯 cell 空 view → 空白」vs「不可編輯 cell → '-'」。\n boolean primitive 不破壞 memo identity(同 size context)。 */}\n <FieldSurfaceEditableProvider isEditable={props.isEditable ?? false}>\n <Inner {...props} />\n </FieldSurfaceEditableProvider>\n </FieldSurfaceSizeProvider>\n </FieldSurfaceProvider>\n )\n })\n ;(CellWithSurface as { displayName?: string }).displayName = `CellWithSurface(${key})`\n return CellWithSurface as ComponentType<CellComponentProps>\n}\n\n// Pre-build per-type cached wrapped components(module-level,one-time init)\nfor (const type of Object.keys(cellRegistry) as ColumnType[]) {\n cellWithSurfaceCache.set(type, buildCellWithSurface(cellRegistry[type], type))\n}\ncellWithSurfaceCache.set('_default_', buildCellWithSurface(StringCell, 'StringCell-fallback'))\n\nexport function resolveCellComponent(type?: ColumnType): ComponentType<CellComponentProps> {\n return cellWithSurfaceCache.get(type ?? '_default_') ?? cellWithSurfaceCache.get('_default_')!\n}\n"],"names":["InputPublic","TextareaPublic","NumberInputPublic","SelectPublic","ComboboxPublic","DatePickerPublic","TimePickerPublic","PeoplePickerPublic","LinkInputPublic","CheckboxPublic","CellWithSurface"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"data-table.d.ts","sourceRoot":"","sources":["../../../src/components/DataTable/data-table.tsx"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"data-table.d.ts","sourceRoot":"","sources":["../../../src/components/DataTable/data-table.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1600,8 +1600,9 @@ function DataTableInner({
|
|
|
1600
1600
|
ref: centerBodyRef,
|
|
1601
1601
|
"data-datatable-hscroll": true,
|
|
1602
1602
|
"data-datatable-panel": "center",
|
|
1603
|
-
|
|
1604
|
-
|
|
1603
|
+
role: isEmpty ? void 0 : "rowgroup",
|
|
1604
|
+
tabIndex: enabled || spreadsheetMode || isEmpty ? void 0 : 0,
|
|
1605
|
+
"aria-label": enabled || spreadsheetMode || isEmpty ? void 0 : "表格內容,可捲動",
|
|
1605
1606
|
className: "flex-1 min-w-0 overflow-x-auto overflow-y-auto focus-visible:outline-2 focus-visible:outline-offset-[-2px] focus-visible:outline-ring",
|
|
1606
1607
|
style: isFillHeight && bodyMaxHeight != null ? { maxHeight: bodyMaxHeight } : hasHeightConstraint ? { maxHeight: height } : void 0,
|
|
1607
1608
|
onScroll: onCenterBodyScroll,
|