@qijenchen/design-system 0.1.0-beta.88 → 0.1.0-beta.89
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/Breadcrumb/breadcrumb.d.ts.map +1 -1
- package/dist/components/Breadcrumb/breadcrumb.js +4 -47
- package/dist/components/Breadcrumb/breadcrumb.js.map +1 -1
- package/dist/components/DataTable/data-table.d.ts.map +1 -1
- package/dist/components/DataTable/data-table.js +3 -40
- package/dist/components/DataTable/data-table.js.map +1 -1
- package/dist/components/Tag/tag.d.ts.map +1 -1
- package/dist/components/Tag/tag.js +11 -15
- package/dist/components/Tag/tag.js.map +1 -1
- package/dist/hooks/use-truncated.d.ts +27 -0
- package/dist/hooks/use-truncated.d.ts.map +1 -0
- package/dist/hooks/use-truncated.js +57 -0
- package/dist/hooks/use-truncated.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/patterns/element-anatomy/index.d.ts +1 -0
- package/dist/patterns/element-anatomy/index.d.ts.map +1 -1
- package/dist/patterns/element-anatomy/index.js +2 -0
- package/dist/patterns/element-anatomy/index.js.map +1 -1
- package/dist/patterns/element-anatomy/item-anatomy.js +1 -1
- package/dist/patterns/element-anatomy/truncated-text.d.ts +27 -0
- package/dist/patterns/element-anatomy/truncated-text.d.ts.map +1 -0
- package/dist/patterns/element-anatomy/truncated-text.js +16 -0
- package/dist/patterns/element-anatomy/truncated-text.js.map +1 -0
- package/llms-full.txt +1 -1
- package/llms.txt +1 -1
- package/package.json +1 -1
- package/src/components/Breadcrumb/breadcrumb.tsx +8 -70
- package/src/components/DataTable/data-table.tsx +9 -47
- package/src/components/Tag/tag.tsx +16 -16
- package/src/hooks/use-truncated.ts +110 -0
- package/src/index.ts +3 -0
- package/src/patterns/element-anatomy/index.ts +1 -0
- package/src/patterns/element-anatomy/truncated-text.spec.md +57 -0
- package/src/patterns/element-anatomy/truncated-text.tsx +61 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tag.d.ts","sourceRoot":"","sources":["../../../src/components/Tag/tag.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAEjE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;
|
|
1
|
+
{"version":3,"file":"tag.d.ts","sourceRoot":"","sources":["../../../src/components/Tag/tag.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAEjE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAyB9C,QAAA,MAAM,WAAW;;;8EAuBhB,CAAA;AAWD,MAAM,WAAW,QACf,SAAQ,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC,EACpE,YAAY,CAAC,OAAO,WAAW,CAAC;IAClC,qDAAqD;IACrD,IAAI,CAAC,EAAE,UAAU,CAAA;IACjB,sCAAsC;IACtC,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACxB,oDAAoD;IACpD,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;IACrB,iLAAiL;IACjL,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,0IAA0I;IAC1I,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,2GAA2G;IAC3G,KAAK,CAAC,EAAE,OAAO,CAAA;IACf;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB;AAuID,QAAA,MAAM,GAAG,iFAAuD,CAAA;AAKhE,eAAO,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4CV,CAAA;AAEV,OAAO,EAAE,GAAG,EAAE,WAAW,EAAE,CAAA"}
|
|
@@ -4,6 +4,7 @@ import { cva } from "class-variance-authority";
|
|
|
4
4
|
import { X } from "lucide-react";
|
|
5
5
|
import { cn } from "../../lib/utils.js";
|
|
6
6
|
import { Tooltip, TooltipTrigger, TooltipContent } from "../Tooltip/tooltip.js";
|
|
7
|
+
import { useTruncated } from "../../hooks/use-truncated.js";
|
|
7
8
|
import { ItemInlineActionButton } from "../../patterns/element-anatomy/item-anatomy.js";
|
|
8
9
|
import { CAT_SUBTLE, CAT_SOLID, CAT_INTERACT } from "../../tokens/categorical-color.js";
|
|
9
10
|
let _measureCtx = null;
|
|
@@ -63,15 +64,11 @@ function TagDismiss({ onRemove, label, solid, color }) {
|
|
|
63
64
|
}
|
|
64
65
|
function TagInner({ className, color, size, icon: Icon, avatar, onRemove, removeAriaLabel, dismissLabel, solid, unbounded = false, children, style, ...props }, forwardedRef) {
|
|
65
66
|
const solidClass = solid ? SOLID_CLASSES[color ?? "neutral"] : void 0;
|
|
66
|
-
const ownRef =
|
|
67
|
-
|
|
68
|
-
React.useLayoutEffect(() => {
|
|
69
|
-
const el = ownRef.current;
|
|
70
|
-
if (!el) return;
|
|
71
|
-
const ctx = getMeasureCtx();
|
|
72
|
-
const check = () => {
|
|
67
|
+
const { ref: ownRef, isTruncated } = useTruncated({
|
|
68
|
+
measure: (el) => {
|
|
73
69
|
const textSpan = el.querySelector("[data-tag-text]");
|
|
74
|
-
|
|
70
|
+
const ctx = getMeasureCtx();
|
|
71
|
+
if (!textSpan || !ctx) return void 0;
|
|
75
72
|
const text = textSpan.textContent || "";
|
|
76
73
|
const cs = getComputedStyle(textSpan);
|
|
77
74
|
ctx.font = `${cs.fontWeight} ${cs.fontSize} ${cs.fontFamily}`;
|
|
@@ -79,13 +76,12 @@ function TagInner({ className, color, size, icon: Icon, avatar, onRemove, remove
|
|
|
79
76
|
const padL = parseFloat(cs.paddingLeft) || 0;
|
|
80
77
|
const padR = parseFloat(cs.paddingRight) || 0;
|
|
81
78
|
const needed = textWidth + padL + padR;
|
|
82
|
-
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
}, [children]);
|
|
79
|
+
return needed > textSpan.clientWidth + 1;
|
|
80
|
+
},
|
|
81
|
+
deps: [children],
|
|
82
|
+
timing: "layoutEffect",
|
|
83
|
+
recheckAfterPaint: false
|
|
84
|
+
});
|
|
89
85
|
const label = typeof children === "string" ? children : "";
|
|
90
86
|
if (process.env.NODE_ENV !== "production" && Icon && avatar) {
|
|
91
87
|
console.warn(
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tag.js","sources":["../../../src/components/Tag/tag.tsx"],"sourcesContent":["import * as React from \"react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\nimport { X } from \"lucide-react\"\nimport type { LucideIcon } from \"lucide-react\"\n\nimport { cn } from \"@/lib/utils\"\nimport { Tooltip, TooltipTrigger, TooltipContent } from \"@/design-system/components/Tooltip/tooltip\"\nimport { ItemInlineActionButton } from \"@/design-system/patterns/element-anatomy/item-anatomy\"\nimport { CAT_SUBTLE, CAT_SOLID, CAT_INTERACT } from \"@/design-system/tokens/categorical-color\"\n\n// ── Tag(inline label)─────────────────────────────────────────────────────\n// 用於分類標籤、狀態標記、多選已選值。\n//\n// 三種尺寸(子元件補齊原則——消費端直接透傳 size,不做 mapping):\n// sm — 20px 高, 12px 字, 4px tag-px, font-medium(配 field sm)\n// md — 24px 高, 14px 字, 4px tag-px, font-normal(配 field md)— 預設\n// lg — 24px = md alias(配 field lg,子元件補齊原則)\n//\n// 截斷:max-w-40(160px),超出時文字 truncate + 自動 tooltip。\n// 用 Canvas measureText 偵測截斷(scrollWidth 在 flex 內不可靠)。\n\nlet _measureCtx: CanvasRenderingContext2D | null = null\nfunction getMeasureCtx() {\n if (!_measureCtx) _measureCtx = document.createElement('canvas').getContext('2d')\n return _measureCtx\n}\n\nconst tagVariants = cva(\n \"inline-flex items-center rounded-md border border-transparent transition-colors cursor-text\",\n {\n variants: {\n // color:categorical 色相(裝飾性分類,非語意狀態)。**消費 categorical-color SSOT**——\n // key X 一律對 `--color-X-*`(1:1,零 offset)。neutral 非色相(無 hue),用 secondary 底自處理。\n // 2026-06-04 修:原 `red` 誤接 `--color-deep-orange-*`(red=品牌紅 hue-25 ≠ deep-orange hue-38\n // ≠ 語意 --error〔= deep-orange〕);改消費 SSOT 後 red→`--color-red-*`,並補齊全 12 色相。\n color: {\n neutral: \"bg-secondary text-foreground\",\n ...CAT_SUBTLE,\n },\n size: {\n sm: \"h-5 px-1 text-caption font-medium\",\n md: \"h-6 px-1 text-body font-normal\",\n lg: \"h-6 px-1 text-body font-normal\",\n },\n },\n defaultVariants: {\n color: \"neutral\",\n size: \"md\",\n },\n }\n)\n\n// ── Solid variant 色彩(step-6 底 + on-emphasis 配對文字,消費 categorical-color SSOT)──\n// 白字 --on-emphasis(夠深的 hue)/ 深字 --on-emphasis-dark(亮 hue:yellow/amber/orange/lime);green 白字例外。\n// **消費 categorical-color SSOT**(CAT_SOLID,1:1 色相)。neutral 非色相,用 neutral-9\n// + --inverse-fg(light=白字, dark=深字,自動反轉)自處理。\nconst SOLID_CLASSES: Record<string, string> = {\n neutral: 'bg-[var(--color-neutral-9)] text-inverse-fg',\n ...CAT_SOLID,\n}\n\nexport interface TagProps\n extends Omit<React.HTMLAttributes<HTMLDivElement>, 'prefix' | 'color'>,\n VariantProps<typeof tagVariants> {\n /** 左側 icon(LucideIcon),由 Tag 統一 16px。與 avatar 互斥。 */\n icon?: LucideIcon\n /** 左側 avatar(ReactNode),與 icon 互斥。 */\n avatar?: React.ReactNode\n /** 可移除——Tag 自動渲染 remove 按鈕並控制尺寸與互動樣式(從集合移除 item) */\n onRemove?: () => void\n /** remove 按鈕的 aria-label 目標名(a11y)。children 為非字串 ReactNode 時建議傳,否則 SR 讀不出移除哪個 tag。預設取 string children。對齊 FileUpload `removeAriaLabel`(同「移除集合項目」場景 + DS `<動作>AriaLabel` 命名慣例)。 */\n removeAriaLabel?: string\n /** @deprecated 2026-07-17 改名為 `removeAriaLabel`(對齊 FileUpload + onRemove callback 語意;dismiss 保留給 Alert/Notice/Toast「通知被忽略」)。舊名過渡一版後移除。 */\n dismissLabel?: string\n /** 深底模式(step-6 背景 + on-emphasis 配對前景;亮色 hue yellow/amber/orange/lime 用深字 --on-emphasis-dark,green 白字例外) */\n solid?: boolean\n /**\n * 2026-05-15 Q3 真 SSOT fix(per user verbatim「同空間兩判斷點」+「不要冰山一角」):\n * Tag 寬度由 parent constrain,不套預設 max-w-40(160px)。用於 cell-as-input narrow cell\n * (< 160px)時 Tag fit cell 寬度 + truncate ellipsis,而非 160px 後被 cell `overflow-hidden`\n * 硬切。對齊「同 cell width → 同 overflow 判斷」SSOT。Default false 保 backward compat\n * (wrap layout / pill rail 等仍受 160px 保護)。\n */\n unbounded?: boolean\n}\n\n// ── Solid dismiss hover/active bg ──\n// **消費 categorical-color SSOT**(CAT_INTERACT,semantic --{hue}-hover/active token),\n// 跟 --primary-hover/active 同模式:solid 色彩 shade change(hover 較亮 step、active 較暗 step),\n// 在 semantic 層做 dark mode swap 確保方向跨 mode 一致。\n// neutral 特例:bg 是 neutral-9 隨 mode 反轉,用 --inverse-neutral-* 鏡射,自處理。\nconst SOLID_DISMISS_HOVER: Record<string, { hover: string; active: string }> = {\n neutral: { hover: 'var(--inverse-neutral-hover)', active: 'var(--inverse-neutral-active)' },\n ...CAT_INTERACT,\n}\n\n// ── Dismiss(internal)────────────────────────────────────────────────────\n// 走 `ItemInlineActionButton`(item-anatomy SSOT)+ `hoverBgClassName` override prop\n// (2026-05-01 整合,消除原 Tag 自刻 `<button>` 繞 DS infra 的 tech debt)。\n//\n// 視覺對齊:`size=\"md\"` → icon 16 / hover-bg 18,跟 Tag 既有手刻幾何完全相等。\n// Solid variant(blue/green/red 等)透過 `hoverBgClassName` 套色相 override token;\n// Subtle variant 落用 ItemInlineActionButton 預設 neutral-hover。\n// 圖標色繼承 Tag 文字色 → `text-current` 三態覆寫。\n\nfunction TagDismiss({ onRemove, label, solid, color }: { onRemove: () => void; label: string; solid?: boolean; color?: string }) {\n const solidColors = solid && color ? SOLID_DISMISS_HOVER[color] : undefined\n\n return (\n <ItemInlineActionButton\n icon={X}\n size=\"md\"\n onClick={(e) => { e.stopPropagation(); onRemove() }}\n aria-label={label ? `移除 ${label}` : '移除'}\n style={solidColors ? ({ '--dismiss-hover': solidColors.hover, '--dismiss-active': solidColors.active } as React.CSSProperties) : undefined}\n hoverBgClassName={\n solidColors\n ? 'group-hover/action:bg-[var(--dismiss-hover)] group-active/action:bg-[var(--dismiss-active)]'\n : undefined\n }\n // Override default fg-muted → 繼承 Tag 文字色(label 同色)\n className=\"text-current hover:text-current active:text-current\"\n />\n )\n}\n\nfunction TagInner(\n { className, color, size, icon: Icon, avatar, onRemove, removeAriaLabel, dismissLabel, solid, unbounded = false, children, style, ...props }: TagProps,\n forwardedRef: React.ForwardedRef<HTMLDivElement>,\n) {\n const solidClass = solid ? SOLID_CLASSES[color ?? 'neutral'] : undefined\n const ownRef = React.useRef<HTMLDivElement | null>(null)\n const [isTruncated, setIsTruncated] = React.useState(false)\n\n React.useLayoutEffect(() => {\n const el = ownRef.current\n if (!el) return\n const ctx = getMeasureCtx()\n const check = () => {\n const textSpan = el.querySelector('[data-tag-text]')\n if (!textSpan || !ctx) return\n const text = textSpan.textContent || ''\n const cs = getComputedStyle(textSpan)\n ctx.font = `${cs.fontWeight} ${cs.fontSize} ${cs.fontFamily}`\n const textWidth = ctx.measureText(text).width\n const padL = parseFloat(cs.paddingLeft) || 0\n const padR = parseFloat(cs.paddingRight) || 0\n const needed = textWidth + padL + padR\n setIsTruncated(needed > (textSpan as HTMLElement).clientWidth + 1)\n }\n check()\n const obs = new ResizeObserver(check)\n obs.observe(el)\n return () => obs.disconnect()\n }, [children])\n\n const label = typeof children === 'string' ? children : ''\n\n // ── Dev-mode warning:icon 與 avatar 互斥 ──\n // 兩者同為 prefix slot(tag.spec.md Props 表「與 avatar 互斥」),同時傳會並列渲染破壞 Tag\n // 內部結構;原僅 jsdoc/spec 約束會靜默通過 → 2026-07-05 對齊 Button overlayBadge dev-warn\n // 先例(button.tsx「Dev-mode warning」段)補齊家族一致 runtime 防線。\n if (process.env.NODE_ENV !== 'production' && Icon && avatar) {\n // eslint-disable-next-line no-console\n console.warn(\n '[DS Tag] `icon` 與 `avatar` 互斥(同為 prefix slot),同時傳會並列渲染破壞 Tag 內部結構,請只擇一。SSOT:tag.spec.md Props 表 + tag.principles.stories.tsx IconRule。'\n )\n }\n\n const tag = (\n <div\n ref={(el) => {\n ownRef.current = el\n if (typeof forwardedRef === 'function') forwardedRef(el)\n else if (forwardedRef) (forwardedRef as React.MutableRefObject<HTMLDivElement | null>).current = el\n }}\n data-tag-root=\"\"\n // 截斷時條件性可 focus(2026-07-06 user 拍板「確認世界級有這樣做就做」——APG Tooltip\n // pattern 原文:tooltip 在元素「收到鍵盤焦點」或 hover 時顯示,trigger 可 focus 是\n // W3C 官方 pattern 前提;Radix Tooltip focus-open 自動生效 → 鍵盤 Tab 到即見全文。\n // 未截斷不入 tab 序(維持 tag.spec「靜態 Tag 不取得 focus」預設,不汙染 tab order)。\n tabIndex={isTruncated ? 0 : undefined}\n className={cn(\n tagVariants({ color, size }),\n solidClass,\n 'w-fit min-w-0 overflow-hidden',\n isTruncated && 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1',\n className,\n )}\n // 2026-05-18 Round 5 fix(per Codex M31 Round 5 verdict + user 拍板「那就開始做」):\n // 用 CSS var `--combobox-tag-area-inline-size`(由 Combobox useOverflowCount JS-injected)取代\n // `min(100%, 10rem)` cyclic percentage。CSS Sizing 3 §5.2.1:percentage 在 indefinite containing\n // block 退化為 initial value → Round 4 的 100% 沒 enforce。改 explicit px 值(JS measured)避此 trap。\n // unbounded=true:cap = inject 寬(回 cell-as-input narrow cell 原 behavior)\n // default:cap = min(inject 寬, 160px)— 兩 cap 取小。fallback(無 var,Form context 等)= 100% / 10rem。\n style={{\n maxWidth: unbounded\n ? 'var(--combobox-tag-area-inline-size, 100%)'\n : 'min(var(--combobox-tag-area-inline-size, 10rem), 10rem)',\n ...style,\n }}\n {...props}\n >\n {Icon && <Icon size={16} aria-hidden />}\n {avatar && <span className=\"shrink-0 w-4 h-4 rounded-full overflow-hidden inline-grid place-content-center [&>*]:w-full [&>*]:h-full\">{avatar}</span>}\n <span data-tag-text=\"\" className=\"px-1 truncate min-w-0\">{children}</span>\n {onRemove && <TagDismiss onRemove={onRemove} label={removeAriaLabel ?? dismissLabel ?? label} solid={solid} color={color ?? 'neutral'} />}\n </div>\n )\n\n if (!isTruncated) return tag\n\n return (\n <Tooltip>\n <TooltipTrigger asChild>{tag}</TooltipTrigger>\n <TooltipContent>{children}</TooltipContent>\n </Tooltip>\n )\n}\n\nconst Tag = React.forwardRef<HTMLDivElement, TagProps>(TagInner)\nTag.displayName = 'Tag'\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 tagMeta = {\n component: 'Tag',\n family: 3,\n // categorical 色相(裝飾性分類,非語意狀態)。**1:1 對 `--color-{hue}-*` primitive,零 offset**。\n // 不對應語意 token——語意狀態(error/info/success/warning)走 Notice / Alert 等狀態元件,\n // 不是 Tag 色相。2026-06-04 修:移除原「red 對應 --error / blue 對應 --info ...」誤導框架\n // (red = 品牌紅 hue-25,跟語意 --error〔= deep-orange〕無關)。\n variants: {\n neutral: { purpose: '通用分類、草稿、無特定語義(secondary 底)' },\n blue: { purpose: 'categorical 色相(--color-blue-*)' },\n green: { purpose: 'categorical 色相(--color-green-*)' },\n 'deep-orange': { purpose: 'categorical 色相(--color-deep-orange-*,hue 38)' },\n yellow: { purpose: 'categorical 色相(--color-yellow-*,淺底深字)' },\n red: { purpose: 'categorical 色相(--color-red-*,品牌紅家族 hue 25;≠ 語意 --error)' },\n orange: { purpose: 'categorical 色相(--color-orange-*)' },\n amber: { purpose: 'categorical 色相(--color-amber-*,淺底深字)' },\n lime: { purpose: 'categorical 色相(--color-lime-*)' },\n turquoise: { purpose: 'categorical 色相(--color-turquoise-*)' },\n indigo: { purpose: 'categorical 色相(--color-indigo-*)' },\n purple: { purpose: 'categorical 色相(--color-purple-*)' },\n magenta: { purpose: 'categorical 色相(--color-magenta-*)' },\n },\n sizes: {\n // Tag 尺寸不引用 field-height token(spec「尺寸」段——Tag 與 Field 尺寸獨立;段名指法免行號漂移)。\n // height = Tag 自身高度(cva h-5/h-6/h-6 = 20/24/24,lg = md alias)。\n // iconSize 全尺寸統一 16(本檔 CAT icon render 硬寫 size={16})。\n sm: { height: 20, iconSize: 16, typography: 'caption' },\n md: { height: 24, iconSize: 16, typography: 'body' },\n lg: { height: 24, iconSize: 16, typography: 'body' },\n },\n // Tag 為純展示 indicator,無互動 state(spec「為何無 StateBehavior」段;段名指法免行號漂移)。\n // 唯一行為 dismiss 屬 Inline Action pattern,非 Tag 自有 state。\n states: ['default'],\n tokens: {\n // 2026-07-04 audit 註記:另有動態色相家族不逐一列 — CAT_SUBTLE 12 色相\n // bg-[var(--color-{hue}-1)] + step-7 深字、CAT_SOLID step-6 底 + --on-emphasis(-dark) 配字、\n // neutral solid bg-[var(--color-neutral-9)] — 全由 categorical-color.ts SSOT 衍生\n //(anatomy TOKEN_MAP 以 stripVar 機械衍生,零漂移)。\n bg: ['bg-neutral-active', 'bg-neutral-hover', 'bg-secondary', 'bg-transparent'],\n fg: ['text-foreground', 'text-inverse-fg'],\n ring: [],\n },\n defaultVariant: 'neutral',\n defaultSize: 'md',\n} as const\n\nexport { Tag, tagVariants }\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"tag.js","sources":["../../../src/components/Tag/tag.tsx"],"sourcesContent":["import * as React from \"react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\nimport { X } from \"lucide-react\"\nimport type { LucideIcon } from \"lucide-react\"\n\nimport { cn } from \"@/lib/utils\"\nimport { Tooltip, TooltipTrigger, TooltipContent } from \"@/design-system/components/Tooltip/tooltip\"\nimport { useTruncated } from \"@/design-system/hooks/use-truncated\"\nimport { ItemInlineActionButton } from \"@/design-system/patterns/element-anatomy/item-anatomy\"\nimport { CAT_SUBTLE, CAT_SOLID, CAT_INTERACT } from \"@/design-system/tokens/categorical-color\"\n\n// ── Tag(inline label)─────────────────────────────────────────────────────\n// 用於分類標籤、狀態標記、多選已選值。\n//\n// 三種尺寸(子元件補齊原則——消費端直接透傳 size,不做 mapping):\n// sm — 20px 高, 12px 字, 4px tag-px, font-medium(配 field sm)\n// md — 24px 高, 14px 字, 4px tag-px, font-normal(配 field md)— 預設\n// lg — 24px = md alias(配 field lg,子元件補齊原則)\n//\n// 截斷:max-w-40(160px),超出時文字 truncate + 自動 tooltip。\n// 用 Canvas measureText 偵測截斷(scrollWidth 在 flex 內不可靠)。\n\nlet _measureCtx: CanvasRenderingContext2D | null = null\nfunction getMeasureCtx() {\n if (!_measureCtx) _measureCtx = document.createElement('canvas').getContext('2d')\n return _measureCtx\n}\n\nconst tagVariants = cva(\n \"inline-flex items-center rounded-md border border-transparent transition-colors cursor-text\",\n {\n variants: {\n // color:categorical 色相(裝飾性分類,非語意狀態)。**消費 categorical-color SSOT**——\n // key X 一律對 `--color-X-*`(1:1,零 offset)。neutral 非色相(無 hue),用 secondary 底自處理。\n // 2026-06-04 修:原 `red` 誤接 `--color-deep-orange-*`(red=品牌紅 hue-25 ≠ deep-orange hue-38\n // ≠ 語意 --error〔= deep-orange〕);改消費 SSOT 後 red→`--color-red-*`,並補齊全 12 色相。\n color: {\n neutral: \"bg-secondary text-foreground\",\n ...CAT_SUBTLE,\n },\n size: {\n sm: \"h-5 px-1 text-caption font-medium\",\n md: \"h-6 px-1 text-body font-normal\",\n lg: \"h-6 px-1 text-body font-normal\",\n },\n },\n defaultVariants: {\n color: \"neutral\",\n size: \"md\",\n },\n }\n)\n\n// ── Solid variant 色彩(step-6 底 + on-emphasis 配對文字,消費 categorical-color SSOT)──\n// 白字 --on-emphasis(夠深的 hue)/ 深字 --on-emphasis-dark(亮 hue:yellow/amber/orange/lime);green 白字例外。\n// **消費 categorical-color SSOT**(CAT_SOLID,1:1 色相)。neutral 非色相,用 neutral-9\n// + --inverse-fg(light=白字, dark=深字,自動反轉)自處理。\nconst SOLID_CLASSES: Record<string, string> = {\n neutral: 'bg-[var(--color-neutral-9)] text-inverse-fg',\n ...CAT_SOLID,\n}\n\nexport interface TagProps\n extends Omit<React.HTMLAttributes<HTMLDivElement>, 'prefix' | 'color'>,\n VariantProps<typeof tagVariants> {\n /** 左側 icon(LucideIcon),由 Tag 統一 16px。與 avatar 互斥。 */\n icon?: LucideIcon\n /** 左側 avatar(ReactNode),與 icon 互斥。 */\n avatar?: React.ReactNode\n /** 可移除——Tag 自動渲染 remove 按鈕並控制尺寸與互動樣式(從集合移除 item) */\n onRemove?: () => void\n /** remove 按鈕的 aria-label 目標名(a11y)。children 為非字串 ReactNode 時建議傳,否則 SR 讀不出移除哪個 tag。預設取 string children。對齊 FileUpload `removeAriaLabel`(同「移除集合項目」場景 + DS `<動作>AriaLabel` 命名慣例)。 */\n removeAriaLabel?: string\n /** @deprecated 2026-07-17 改名為 `removeAriaLabel`(對齊 FileUpload + onRemove callback 語意;dismiss 保留給 Alert/Notice/Toast「通知被忽略」)。舊名過渡一版後移除。 */\n dismissLabel?: string\n /** 深底模式(step-6 背景 + on-emphasis 配對前景;亮色 hue yellow/amber/orange/lime 用深字 --on-emphasis-dark,green 白字例外) */\n solid?: boolean\n /**\n * 2026-05-15 Q3 真 SSOT fix(per user verbatim「同空間兩判斷點」+「不要冰山一角」):\n * Tag 寬度由 parent constrain,不套預設 max-w-40(160px)。用於 cell-as-input narrow cell\n * (< 160px)時 Tag fit cell 寬度 + truncate ellipsis,而非 160px 後被 cell `overflow-hidden`\n * 硬切。對齊「同 cell width → 同 overflow 判斷」SSOT。Default false 保 backward compat\n * (wrap layout / pill rail 等仍受 160px 保護)。\n */\n unbounded?: boolean\n}\n\n// ── Solid dismiss hover/active bg ──\n// **消費 categorical-color SSOT**(CAT_INTERACT,semantic --{hue}-hover/active token),\n// 跟 --primary-hover/active 同模式:solid 色彩 shade change(hover 較亮 step、active 較暗 step),\n// 在 semantic 層做 dark mode swap 確保方向跨 mode 一致。\n// neutral 特例:bg 是 neutral-9 隨 mode 反轉,用 --inverse-neutral-* 鏡射,自處理。\nconst SOLID_DISMISS_HOVER: Record<string, { hover: string; active: string }> = {\n neutral: { hover: 'var(--inverse-neutral-hover)', active: 'var(--inverse-neutral-active)' },\n ...CAT_INTERACT,\n}\n\n// ── Dismiss(internal)────────────────────────────────────────────────────\n// 走 `ItemInlineActionButton`(item-anatomy SSOT)+ `hoverBgClassName` override prop\n// (2026-05-01 整合,消除原 Tag 自刻 `<button>` 繞 DS infra 的 tech debt)。\n//\n// 視覺對齊:`size=\"md\"` → icon 16 / hover-bg 18,跟 Tag 既有手刻幾何完全相等。\n// Solid variant(blue/green/red 等)透過 `hoverBgClassName` 套色相 override token;\n// Subtle variant 落用 ItemInlineActionButton 預設 neutral-hover。\n// 圖標色繼承 Tag 文字色 → `text-current` 三態覆寫。\n\nfunction TagDismiss({ onRemove, label, solid, color }: { onRemove: () => void; label: string; solid?: boolean; color?: string }) {\n const solidColors = solid && color ? SOLID_DISMISS_HOVER[color] : undefined\n\n return (\n <ItemInlineActionButton\n icon={X}\n size=\"md\"\n onClick={(e) => { e.stopPropagation(); onRemove() }}\n aria-label={label ? `移除 ${label}` : '移除'}\n style={solidColors ? ({ '--dismiss-hover': solidColors.hover, '--dismiss-active': solidColors.active } as React.CSSProperties) : undefined}\n hoverBgClassName={\n solidColors\n ? 'group-hover/action:bg-[var(--dismiss-hover)] group-active/action:bg-[var(--dismiss-active)]'\n : undefined\n }\n // Override default fg-muted → 繼承 Tag 文字色(label 同色)\n className=\"text-current hover:text-current active:text-current\"\n />\n )\n}\n\nfunction TagInner(\n { className, color, size, icon: Icon, avatar, onRemove, removeAriaLabel, dismissLabel, solid, unbounded = false, children, style, ...props }: TagProps,\n forwardedRef: React.ForwardedRef<HTMLDivElement>,\n) {\n const solidClass = solid ? SOLID_CLASSES[color ?? 'neutral'] : undefined\n // 截斷偵測用 SSOT 引擎 `useTruncated`(patterns/element-anatomy 的 hook)。Tag 走**變異型**:\n // - measure = Canvas measureText(flex 內 scrollWidth 不可靠,line 20):observe root、量測內層\n // `[data-tag-text]` span(trigger≠量測元素);回 undefined = 無法量測時保留前一 state。\n // - timing='layoutEffect'(避免 paint flash)/ deps=[children](children 變重量)/ recheckAfterPaint=false\n // (Tag 原本即無 rAF/timeout 二次量)—— 三處變異全走 options,行為零漂移。\n const { ref: ownRef, isTruncated } = useTruncated<HTMLDivElement>({\n measure: (el) => {\n const textSpan = el.querySelector('[data-tag-text]')\n const ctx = getMeasureCtx()\n if (!textSpan || !ctx) return undefined\n const text = textSpan.textContent || ''\n const cs = getComputedStyle(textSpan)\n ctx.font = `${cs.fontWeight} ${cs.fontSize} ${cs.fontFamily}`\n const textWidth = ctx.measureText(text).width\n const padL = parseFloat(cs.paddingLeft) || 0\n const padR = parseFloat(cs.paddingRight) || 0\n const needed = textWidth + padL + padR\n return needed > (textSpan as HTMLElement).clientWidth + 1\n },\n deps: [children],\n timing: 'layoutEffect',\n recheckAfterPaint: false,\n })\n\n const label = typeof children === 'string' ? children : ''\n\n // ── Dev-mode warning:icon 與 avatar 互斥 ──\n // 兩者同為 prefix slot(tag.spec.md Props 表「與 avatar 互斥」),同時傳會並列渲染破壞 Tag\n // 內部結構;原僅 jsdoc/spec 約束會靜默通過 → 2026-07-05 對齊 Button overlayBadge dev-warn\n // 先例(button.tsx「Dev-mode warning」段)補齊家族一致 runtime 防線。\n if (process.env.NODE_ENV !== 'production' && Icon && avatar) {\n // eslint-disable-next-line no-console\n console.warn(\n '[DS Tag] `icon` 與 `avatar` 互斥(同為 prefix slot),同時傳會並列渲染破壞 Tag 內部結構,請只擇一。SSOT:tag.spec.md Props 表 + tag.principles.stories.tsx IconRule。'\n )\n }\n\n const tag = (\n <div\n ref={(el) => {\n ownRef.current = el\n if (typeof forwardedRef === 'function') forwardedRef(el)\n else if (forwardedRef) (forwardedRef as React.MutableRefObject<HTMLDivElement | null>).current = el\n }}\n data-tag-root=\"\"\n // 截斷時條件性可 focus(2026-07-06 user 拍板「確認世界級有這樣做就做」——APG Tooltip\n // pattern 原文:tooltip 在元素「收到鍵盤焦點」或 hover 時顯示,trigger 可 focus 是\n // W3C 官方 pattern 前提;Radix Tooltip focus-open 自動生效 → 鍵盤 Tab 到即見全文。\n // 未截斷不入 tab 序(維持 tag.spec「靜態 Tag 不取得 focus」預設,不汙染 tab order)。\n tabIndex={isTruncated ? 0 : undefined}\n className={cn(\n tagVariants({ color, size }),\n solidClass,\n 'w-fit min-w-0 overflow-hidden',\n isTruncated && 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1',\n className,\n )}\n // 2026-05-18 Round 5 fix(per Codex M31 Round 5 verdict + user 拍板「那就開始做」):\n // 用 CSS var `--combobox-tag-area-inline-size`(由 Combobox useOverflowCount JS-injected)取代\n // `min(100%, 10rem)` cyclic percentage。CSS Sizing 3 §5.2.1:percentage 在 indefinite containing\n // block 退化為 initial value → Round 4 的 100% 沒 enforce。改 explicit px 值(JS measured)避此 trap。\n // unbounded=true:cap = inject 寬(回 cell-as-input narrow cell 原 behavior)\n // default:cap = min(inject 寬, 160px)— 兩 cap 取小。fallback(無 var,Form context 等)= 100% / 10rem。\n style={{\n maxWidth: unbounded\n ? 'var(--combobox-tag-area-inline-size, 100%)'\n : 'min(var(--combobox-tag-area-inline-size, 10rem), 10rem)',\n ...style,\n }}\n {...props}\n >\n {Icon && <Icon size={16} aria-hidden />}\n {avatar && <span className=\"shrink-0 w-4 h-4 rounded-full overflow-hidden inline-grid place-content-center [&>*]:w-full [&>*]:h-full\">{avatar}</span>}\n <span data-tag-text=\"\" className=\"px-1 truncate min-w-0\">{children}</span>\n {onRemove && <TagDismiss onRemove={onRemove} label={removeAriaLabel ?? dismissLabel ?? label} solid={solid} color={color ?? 'neutral'} />}\n </div>\n )\n\n if (!isTruncated) return tag\n\n return (\n <Tooltip>\n <TooltipTrigger asChild>{tag}</TooltipTrigger>\n <TooltipContent>{children}</TooltipContent>\n </Tooltip>\n )\n}\n\nconst Tag = React.forwardRef<HTMLDivElement, TagProps>(TagInner)\nTag.displayName = 'Tag'\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 tagMeta = {\n component: 'Tag',\n family: 3,\n // categorical 色相(裝飾性分類,非語意狀態)。**1:1 對 `--color-{hue}-*` primitive,零 offset**。\n // 不對應語意 token——語意狀態(error/info/success/warning)走 Notice / Alert 等狀態元件,\n // 不是 Tag 色相。2026-06-04 修:移除原「red 對應 --error / blue 對應 --info ...」誤導框架\n // (red = 品牌紅 hue-25,跟語意 --error〔= deep-orange〕無關)。\n variants: {\n neutral: { purpose: '通用分類、草稿、無特定語義(secondary 底)' },\n blue: { purpose: 'categorical 色相(--color-blue-*)' },\n green: { purpose: 'categorical 色相(--color-green-*)' },\n 'deep-orange': { purpose: 'categorical 色相(--color-deep-orange-*,hue 38)' },\n yellow: { purpose: 'categorical 色相(--color-yellow-*,淺底深字)' },\n red: { purpose: 'categorical 色相(--color-red-*,品牌紅家族 hue 25;≠ 語意 --error)' },\n orange: { purpose: 'categorical 色相(--color-orange-*)' },\n amber: { purpose: 'categorical 色相(--color-amber-*,淺底深字)' },\n lime: { purpose: 'categorical 色相(--color-lime-*)' },\n turquoise: { purpose: 'categorical 色相(--color-turquoise-*)' },\n indigo: { purpose: 'categorical 色相(--color-indigo-*)' },\n purple: { purpose: 'categorical 色相(--color-purple-*)' },\n magenta: { purpose: 'categorical 色相(--color-magenta-*)' },\n },\n sizes: {\n // Tag 尺寸不引用 field-height token(spec「尺寸」段——Tag 與 Field 尺寸獨立;段名指法免行號漂移)。\n // height = Tag 自身高度(cva h-5/h-6/h-6 = 20/24/24,lg = md alias)。\n // iconSize 全尺寸統一 16(本檔 CAT icon render 硬寫 size={16})。\n sm: { height: 20, iconSize: 16, typography: 'caption' },\n md: { height: 24, iconSize: 16, typography: 'body' },\n lg: { height: 24, iconSize: 16, typography: 'body' },\n },\n // Tag 為純展示 indicator,無互動 state(spec「為何無 StateBehavior」段;段名指法免行號漂移)。\n // 唯一行為 dismiss 屬 Inline Action pattern,非 Tag 自有 state。\n states: ['default'],\n tokens: {\n // 2026-07-04 audit 註記:另有動態色相家族不逐一列 — CAT_SUBTLE 12 色相\n // bg-[var(--color-{hue}-1)] + step-7 深字、CAT_SOLID step-6 底 + --on-emphasis(-dark) 配字、\n // neutral solid bg-[var(--color-neutral-9)] — 全由 categorical-color.ts SSOT 衍生\n //(anatomy TOKEN_MAP 以 stripVar 機械衍生,零漂移)。\n bg: ['bg-neutral-active', 'bg-neutral-hover', 'bg-secondary', 'bg-transparent'],\n fg: ['text-foreground', 'text-inverse-fg'],\n ring: [],\n },\n defaultVariant: 'neutral',\n defaultSize: 'md',\n} as const\n\nexport { Tag, tagVariants }\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
export interface UseTruncatedOptions {
|
|
3
|
+
/**
|
|
4
|
+
* 偵測策略:回傳 `true` = 截斷、`false` = 未截斷、`undefined` = 本次無法量測(保留前一狀態)。
|
|
5
|
+
* 預設 = `el.scrollWidth > el.clientWidth`(觀察元素自身)。
|
|
6
|
+
* Tag 傳自訂 fn:observe root、內部 `querySelector('[data-tag-text]')` + Canvas measureText。
|
|
7
|
+
*/
|
|
8
|
+
measure?: (observedEl: HTMLElement) => boolean | undefined;
|
|
9
|
+
/** deps 變更時 cleanup + 重新量測 / 重新訂閱(Tag 傳 `[children]`)。預設 `[]`(mount-once)。 */
|
|
10
|
+
deps?: React.DependencyList;
|
|
11
|
+
/**
|
|
12
|
+
* 是否在首次 paint 後以 `requestAnimationFrame` + `setTimeout(100)` 再量一次,捕獲首幀 layout
|
|
13
|
+
* 未完成 / 字型 async load 的假陰性(Breadcrumb 已採此 robust 版)。預設 `true`。
|
|
14
|
+
*/
|
|
15
|
+
recheckAfterPaint?: boolean;
|
|
16
|
+
/** `'layoutEffect'` = `useLayoutEffect`(量測在 paint 前,避免 flash;Tag 用)/ `'effect'` = `useEffect`。預設 `'effect'`。 */
|
|
17
|
+
timing?: 'effect' | 'layoutEffect';
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* 偵測 ref 所指元素的文字是否被截斷,回傳 `{ ref, isTruncated }`。
|
|
21
|
+
* `isTruncated` 用來驅動 Tooltip「僅截斷時顯示」(對齊 `tooltip.principles.stories.tsx`「沒被截斷就不該顯示 tooltip」)。
|
|
22
|
+
*/
|
|
23
|
+
export declare function useTruncated<E extends HTMLElement = HTMLElement>(options?: UseTruncatedOptions): {
|
|
24
|
+
ref: React.MutableRefObject<E | null>;
|
|
25
|
+
isTruncated: boolean;
|
|
26
|
+
};
|
|
27
|
+
//# sourceMappingURL=use-truncated.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-truncated.d.ts","sourceRoot":"","sources":["../../src/hooks/use-truncated.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AA2C9B,MAAM,WAAW,mBAAmB;IAClC;;;;OAIG;IACH,OAAO,CAAC,EAAE,CAAC,UAAU,EAAE,WAAW,KAAK,OAAO,GAAG,SAAS,CAAA;IAC1D,8EAA8E;IAC9E,IAAI,CAAC,EAAE,KAAK,CAAC,cAAc,CAAA;IAC3B;;;OAGG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAA;IAC3B,gHAAgH;IAChH,MAAM,CAAC,EAAE,QAAQ,GAAG,cAAc,CAAA;CACnC;AAID;;;GAGG;AACH,wBAAgB,YAAY,CAAC,CAAC,SAAS,WAAW,GAAG,WAAW,EAC9D,OAAO,GAAE,mBAAwB,GAChC;IAAE,GAAG,EAAE,KAAK,CAAC,gBAAgB,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IAAC,WAAW,EAAE,OAAO,CAAA;CAAE,CAwCjE"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
let sharedRO = null;
|
|
3
|
+
const sharedROCallbacks = /* @__PURE__ */ new WeakMap();
|
|
4
|
+
function getSharedRO() {
|
|
5
|
+
if (sharedRO) return sharedRO;
|
|
6
|
+
sharedRO = new ResizeObserver((entries) => {
|
|
7
|
+
entries.forEach((e) => {
|
|
8
|
+
const cb = sharedROCallbacks.get(e.target);
|
|
9
|
+
if (cb) cb(e);
|
|
10
|
+
});
|
|
11
|
+
});
|
|
12
|
+
return sharedRO;
|
|
13
|
+
}
|
|
14
|
+
function observeShared(el, cb) {
|
|
15
|
+
const obs = getSharedRO();
|
|
16
|
+
sharedROCallbacks.set(el, cb);
|
|
17
|
+
obs.observe(el);
|
|
18
|
+
return () => {
|
|
19
|
+
sharedROCallbacks.delete(el);
|
|
20
|
+
obs.unobserve(el);
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
const defaultMeasure = (el) => el.scrollWidth > el.clientWidth;
|
|
24
|
+
function useTruncated(options = {}) {
|
|
25
|
+
const { measure = defaultMeasure, deps = [], recheckAfterPaint = true, timing = "effect" } = options;
|
|
26
|
+
const ref = React.useRef(null);
|
|
27
|
+
const [isTruncated, setIsTruncated] = React.useState(false);
|
|
28
|
+
const measureRef = React.useRef(measure);
|
|
29
|
+
measureRef.current = measure;
|
|
30
|
+
const useIsoEffect = timing === "layoutEffect" ? React.useLayoutEffect : React.useEffect;
|
|
31
|
+
useIsoEffect(() => {
|
|
32
|
+
const el = ref.current;
|
|
33
|
+
if (!el) return;
|
|
34
|
+
const check = () => {
|
|
35
|
+
const r = measureRef.current(el);
|
|
36
|
+
if (r !== void 0) setIsTruncated(r);
|
|
37
|
+
};
|
|
38
|
+
check();
|
|
39
|
+
let raf = 0;
|
|
40
|
+
let t;
|
|
41
|
+
if (recheckAfterPaint) {
|
|
42
|
+
raf = requestAnimationFrame(check);
|
|
43
|
+
t = setTimeout(check, 100);
|
|
44
|
+
}
|
|
45
|
+
const cleanup = observeShared(el, check);
|
|
46
|
+
return () => {
|
|
47
|
+
if (raf) cancelAnimationFrame(raf);
|
|
48
|
+
if (t) clearTimeout(t);
|
|
49
|
+
cleanup();
|
|
50
|
+
};
|
|
51
|
+
}, deps);
|
|
52
|
+
return { ref, isTruncated };
|
|
53
|
+
}
|
|
54
|
+
export {
|
|
55
|
+
useTruncated
|
|
56
|
+
};
|
|
57
|
+
//# sourceMappingURL=use-truncated.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-truncated.js","sources":["../../src/hooks/use-truncated.ts"],"sourcesContent":["import * as React from 'react'\n\n// ── useTruncated — 單行文字截斷偵測引擎(SSOT)─────────────────────────────────\n// 收斂 Breadcrumb TruncatedLabel / DataTable TruncateCell / Tag 三處**逐字重複**的\n// module-level shared ResizeObserver 引擎 + isTruncated 狀態機為唯一 owner(M17 SSOT)。\n//\n// 世界級對照(M8):MUI/MUI-X 官方無第一方 primitive,社群共識 = 「hook 量測 scrollWidth>clientWidth\n// + ref + 以 Tooltip `open` prop 條件控制」(issue #37211);此 hook 即該低階量測層,\n// 上層 `<TruncatedText>`(patterns/element-anatomy)對應 Ant `Typography.Text ellipsis` 高階元件。\n//\n// 三處變異點皆以 options 注入,**行為零漂移**:\n// - Breadcrumb / DataTable:預設 scrollWidth>clientWidth。\n// - Tag:trigger≠量測元素(observe root、量測內層 span)+ Canvas measureText(flex 內 scrollWidth\n// 不可靠)+ useLayoutEffect(避免 paint flash)+ deps=[children] → 全走 options。\n\ntype RoCallback = (entry: ResizeObserverEntry) => void\n\nlet sharedRO: ResizeObserver | null = null\nconst sharedROCallbacks = new WeakMap<Element, RoCallback>()\n\n// 全 DS 共用單一 ResizeObserver,dispatch 到 per-element callback(2026-04-22 DataTable D3 perf audit\n// 成果:10 col × 100 row = 1 RO 而非 1000)。element 卸載時 cleanup,singleton RO 本身不 disconnect。\nfunction getSharedRO(): ResizeObserver {\n if (sharedRO) return sharedRO\n sharedRO = new ResizeObserver((entries) => {\n entries.forEach((e) => {\n const cb = sharedROCallbacks.get(e.target)\n if (cb) cb(e)\n })\n })\n return sharedRO\n}\n\nfunction observeShared(el: Element, cb: RoCallback): () => void {\n const obs = getSharedRO()\n sharedROCallbacks.set(el, cb)\n obs.observe(el)\n return () => {\n sharedROCallbacks.delete(el)\n obs.unobserve(el)\n }\n}\n\nexport interface UseTruncatedOptions {\n /**\n * 偵測策略:回傳 `true` = 截斷、`false` = 未截斷、`undefined` = 本次無法量測(保留前一狀態)。\n * 預設 = `el.scrollWidth > el.clientWidth`(觀察元素自身)。\n * Tag 傳自訂 fn:observe root、內部 `querySelector('[data-tag-text]')` + Canvas measureText。\n */\n measure?: (observedEl: HTMLElement) => boolean | undefined\n /** deps 變更時 cleanup + 重新量測 / 重新訂閱(Tag 傳 `[children]`)。預設 `[]`(mount-once)。 */\n deps?: React.DependencyList\n /**\n * 是否在首次 paint 後以 `requestAnimationFrame` + `setTimeout(100)` 再量一次,捕獲首幀 layout\n * 未完成 / 字型 async load 的假陰性(Breadcrumb 已採此 robust 版)。預設 `true`。\n */\n recheckAfterPaint?: boolean\n /** `'layoutEffect'` = `useLayoutEffect`(量測在 paint 前,避免 flash;Tag 用)/ `'effect'` = `useEffect`。預設 `'effect'`。 */\n timing?: 'effect' | 'layoutEffect'\n}\n\nconst defaultMeasure = (el: HTMLElement): boolean => el.scrollWidth > el.clientWidth\n\n/**\n * 偵測 ref 所指元素的文字是否被截斷,回傳 `{ ref, isTruncated }`。\n * `isTruncated` 用來驅動 Tooltip「僅截斷時顯示」(對齊 `tooltip.principles.stories.tsx`「沒被截斷就不該顯示 tooltip」)。\n */\nexport function useTruncated<E extends HTMLElement = HTMLElement>(\n options: UseTruncatedOptions = {},\n): { ref: React.MutableRefObject<E | null>; isTruncated: boolean } {\n const { measure = defaultMeasure, deps = [], recheckAfterPaint = true, timing = 'effect' } = options\n // MutableRefObject(consumer 可經 callback ref 寫入 .current 以與 forwardedRef 合併,如 Tag)。\n const ref = React.useRef<E | null>(null)\n const [isTruncated, setIsTruncated] = React.useState(false)\n\n // measure 每 render 可能是新 closure(consumer inline);收進 ref 讓 effect 不因它重訂閱,\n // 但 RO 回呼仍讀到最新版。\n const measureRef = React.useRef(measure)\n measureRef.current = measure\n\n // timing 為 call-site 固定字面值(某 consumer 永遠同一值)→ 每個 component instance 每 render\n // 呼叫同一個 effect hook,符合 rules-of-hooks。\n const useIsoEffect = timing === 'layoutEffect' ? React.useLayoutEffect : React.useEffect\n\n useIsoEffect(() => {\n const el = ref.current\n if (!el) return\n const check = () => {\n const r = measureRef.current(el)\n if (r !== undefined) setIsTruncated(r)\n }\n check()\n let raf = 0\n let t: ReturnType<typeof setTimeout> | undefined\n if (recheckAfterPaint) {\n raf = requestAnimationFrame(check)\n t = setTimeout(check, 100)\n }\n const cleanup = observeShared(el, check)\n return () => {\n if (raf) cancelAnimationFrame(raf)\n if (t) clearTimeout(t)\n cleanup()\n }\n // deps 由 consumer 決定(Tag: [children];其餘: []);measure 走 ref 不需進 deps。\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, deps)\n\n return { ref, isTruncated }\n}\n"],"names":[],"mappings":";AAiBA,IAAI,WAAkC;AACtC,MAAM,wCAAwB,QAAA;AAI9B,SAAS,cAA8B;AACrC,MAAI,SAAU,QAAO;AACrB,aAAW,IAAI,eAAe,CAAC,YAAY;AACzC,YAAQ,QAAQ,CAAC,MAAM;AACrB,YAAM,KAAK,kBAAkB,IAAI,EAAE,MAAM;AACzC,UAAI,OAAO,CAAC;AAAA,IACd,CAAC;AAAA,EACH,CAAC;AACD,SAAO;AACT;AAEA,SAAS,cAAc,IAAa,IAA4B;AAC9D,QAAM,MAAM,YAAA;AACZ,oBAAkB,IAAI,IAAI,EAAE;AAC5B,MAAI,QAAQ,EAAE;AACd,SAAO,MAAM;AACX,sBAAkB,OAAO,EAAE;AAC3B,QAAI,UAAU,EAAE;AAAA,EAClB;AACF;AAoBA,MAAM,iBAAiB,CAAC,OAA6B,GAAG,cAAc,GAAG;AAMlE,SAAS,aACd,UAA+B,IACkC;AACjE,QAAM,EAAE,UAAU,gBAAgB,OAAO,CAAA,GAAI,oBAAoB,MAAM,SAAS,SAAA,IAAa;AAE7F,QAAM,MAAM,MAAM,OAAiB,IAAI;AACvC,QAAM,CAAC,aAAa,cAAc,IAAI,MAAM,SAAS,KAAK;AAI1D,QAAM,aAAa,MAAM,OAAO,OAAO;AACvC,aAAW,UAAU;AAIrB,QAAM,eAAe,WAAW,iBAAiB,MAAM,kBAAkB,MAAM;AAE/E,eAAa,MAAM;AACjB,UAAM,KAAK,IAAI;AACf,QAAI,CAAC,GAAI;AACT,UAAM,QAAQ,MAAM;AAClB,YAAM,IAAI,WAAW,QAAQ,EAAE;AAC/B,UAAI,MAAM,OAAW,gBAAe,CAAC;AAAA,IACvC;AACA,UAAA;AACA,QAAI,MAAM;AACV,QAAI;AACJ,QAAI,mBAAmB;AACrB,YAAM,sBAAsB,KAAK;AACjC,UAAI,WAAW,OAAO,GAAG;AAAA,IAC3B;AACA,UAAM,UAAU,cAAc,IAAI,KAAK;AACvC,WAAO,MAAM;AACX,UAAI,0BAA0B,GAAG;AACjC,UAAI,gBAAgB,CAAC;AACrB,cAAA;AAAA,IACF;AAAA,EAGF,GAAG,IAAI;AAEP,SAAO,EAAE,KAAK,YAAA;AAChB;"}
|
package/dist/index.d.ts
CHANGED
|
@@ -117,6 +117,7 @@ export * from './hooks/use-controllable';
|
|
|
117
117
|
export * from './hooks/use-is-narrow-viewport';
|
|
118
118
|
export * from './hooks/use-is-touch-device';
|
|
119
119
|
export * from './hooks/use-overflow-items';
|
|
120
|
+
export * from './hooks/use-truncated';
|
|
120
121
|
export * from './lib/drag-visual';
|
|
121
122
|
export * from './lib/multi-select-ordering';
|
|
122
123
|
export * from './lib/utils';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -70,6 +70,7 @@ import { useControllable } from "./hooks/use-controllable.js";
|
|
|
70
70
|
import { useIsNarrowViewport } from "./hooks/use-is-narrow-viewport.js";
|
|
71
71
|
import { useIsTouchDevice } from "./hooks/use-is-touch-device.js";
|
|
72
72
|
import { useOverflowIndices, useScrollEdges } from "./hooks/use-overflow-items.js";
|
|
73
|
+
import { useTruncated } from "./hooks/use-truncated.js";
|
|
73
74
|
import { dragActiveCursor, dragHandleCursorClass, dragSourceClass, dragSourceStyle, dropIndicatorColumn, dropIndicatorInside, dropIndicatorRow, isReorderNoop, reconstructFullRowGhost, snapToCursorModifier } from "./lib/drag-visual.js";
|
|
74
75
|
import { applySelectAll, clearSelection } from "./lib/multi-select-ordering.js";
|
|
75
76
|
import { cn, lineClampClass } from "./lib/utils.js";
|
|
@@ -330,6 +331,7 @@ export {
|
|
|
330
331
|
useOverflowIndices,
|
|
331
332
|
useRowSize,
|
|
332
333
|
useScrollEdges,
|
|
333
|
-
useSidebar
|
|
334
|
+
useSidebar,
|
|
335
|
+
useTruncated
|
|
334
336
|
};
|
|
335
337
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/patterns/element-anatomy/index.ts"],"names":[],"mappings":"AAIA,cAAc,gBAAgB,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/patterns/element-anatomy/index.ts"],"names":[],"mappings":"AAIA,cAAc,gBAAgB,CAAA;AAC9B,cAAc,kBAAkB,CAAA"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { AVATAR_SIZE, ICON_SIZE, INLINE_ACTION_HOVER_BG_SIZE, ItemAvatar, ItemContent, ItemIcon, ItemInlineAction, ItemInlineActionButton, ItemLabel, ItemPrefix, ItemSuffix, ROW_PADDING_BY_SIZE, RowSizeProvider, getUniformPrefixSlotStyle, itemPrefixAlignVariants, useRowSize } from "./item-anatomy.js";
|
|
2
|
+
import { TruncatedText } from "./truncated-text.js";
|
|
2
3
|
export {
|
|
3
4
|
AVATAR_SIZE,
|
|
4
5
|
ICON_SIZE,
|
|
@@ -13,6 +14,7 @@ export {
|
|
|
13
14
|
ItemSuffix,
|
|
14
15
|
ROW_PADDING_BY_SIZE,
|
|
15
16
|
RowSizeProvider,
|
|
17
|
+
TruncatedText,
|
|
16
18
|
getUniformPrefixSlotStyle,
|
|
17
19
|
itemPrefixAlignVariants,
|
|
18
20
|
useRowSize
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
2
|
import * as React from "react";
|
|
3
3
|
import { cva } from "class-variance-authority";
|
|
4
|
-
import {
|
|
4
|
+
import { lineClampClass, cn } from "../../lib/utils.js";
|
|
5
5
|
import { Avatar } from "../../components/Avatar/avatar.js";
|
|
6
6
|
import { Tooltip, TooltipTrigger, TooltipContent } from "../../components/Tooltip/tooltip.js";
|
|
7
7
|
const ICON_SIZE = {
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
/** @internal 隨 `TruncatedText`(DS-internal 組合 primitive)一併不進 root barrel front-door;subpath 仍可取。 */
|
|
3
|
+
export interface TruncatedTextProps {
|
|
4
|
+
children: React.ReactNode;
|
|
5
|
+
/** 附加到截斷 span 的 className(如 DataTable 的 text-align)。 */
|
|
6
|
+
className?: string;
|
|
7
|
+
/**
|
|
8
|
+
* Tooltip 顯示內容,預設 = `children`。當 `children` 為非字串 ReactNode(icon+text 等)、
|
|
9
|
+
* 但已知完整文字時傳入(Breadcrumb 的 `fullText`)。
|
|
10
|
+
*/
|
|
11
|
+
tooltip?: React.ReactNode;
|
|
12
|
+
/**
|
|
13
|
+
* span 的 display:`'inline'`(預設,保 baseline/垂直對齊,DataTable cell 用)/ `'block'`(Breadcrumb 用)。
|
|
14
|
+
* ⚠️ DataTable 刻意用 inline —— `block` 會改 baseline 使 Field/inline-flex cell 垂直對齊 collapse。
|
|
15
|
+
*/
|
|
16
|
+
display?: 'block' | 'inline';
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* @internal DS-internal 組合 primitive:由 Breadcrumb / DataTable 內部消費以統一 truncate-tooltip 呈現。
|
|
20
|
+
* end-user app 若需「單行截斷 + tooltip」直接消費 public `useTruncated` hook 自組(trigger/a11y 自控),
|
|
21
|
+
* 或經 per-component subpath 取用本 component。不進 root barrel front-door。
|
|
22
|
+
*/
|
|
23
|
+
export declare function TruncatedText({ children, className, tooltip, display }: TruncatedTextProps): import("react/jsx-runtime").JSX.Element;
|
|
24
|
+
export declare namespace TruncatedText {
|
|
25
|
+
var displayName: string;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=truncated-text.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"truncated-text.d.ts","sourceRoot":"","sources":["../../../src/patterns/element-anatomy/truncated-text.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAyB9B,oGAAoG;AACpG,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,wDAAwD;IACxD,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;OAGG;IACH,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAA;CAC7B;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE,OAAkB,EAAE,EAAE,kBAAkB,2CAYrG;yBAZe,aAAa"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from "../../lib/utils.js";
|
|
3
|
+
import { Tooltip, TooltipTrigger, TooltipContent } from "../../components/Tooltip/tooltip.js";
|
|
4
|
+
import { useTruncated } from "../../hooks/use-truncated.js";
|
|
5
|
+
function TruncatedText({ children, className, tooltip, display = "inline" }) {
|
|
6
|
+
const { ref, isTruncated } = useTruncated();
|
|
7
|
+
return /* @__PURE__ */ jsxs(Tooltip, { open: isTruncated ? void 0 : false, children: [
|
|
8
|
+
/* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx("span", { ref, className: cn("truncate min-w-0", display === "block" && "block", className), children }) }),
|
|
9
|
+
/* @__PURE__ */ jsx(TooltipContent, { children: tooltip ?? children })
|
|
10
|
+
] });
|
|
11
|
+
}
|
|
12
|
+
TruncatedText.displayName = "TruncatedText";
|
|
13
|
+
export {
|
|
14
|
+
TruncatedText
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=truncated-text.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"truncated-text.js","sources":["../../../src/patterns/element-anatomy/truncated-text.tsx"],"sourcesContent":["import * as React from 'react'\n\nimport { cn } from '@/lib/utils'\nimport { Tooltip, TooltipTrigger, TooltipContent } from '@/design-system/components/Tooltip/tooltip'\nimport { useTruncated } from '@/design-system/hooks/use-truncated'\n\n// ── 消費的 SSOT ──\n// - hooks/use-truncated(useTruncated):截斷偵測引擎 + isTruncated 狀態(本 primitive 的量測核心)\n// - components/Tooltip(Tooltip/TooltipTrigger/TooltipContent):截斷才顯示完整文字的補救 overlay\n// - lib/utils(cn):className 合併\n// - spec: patterns/element-anatomy/truncated-text.spec.md(本 primitive「何時用/為什麼」)\n// - governing: components/Tooltip/tooltip.principles.stories.tsx「沒被截斷就不該顯示 tooltip」→ 由 open 控制機械保證\n\n// ── TruncatedText — 單行截斷 + 截斷才顯示 tooltip 的組合式 primitive ──────────────\n// 消費 `useTruncated`(量測引擎 SSOT)+ 封裝「永遠 wrap Tooltip、以 `open` 控制可見」的正解結構。\n// 收斂 Breadcrumb `TruncatedLabel` 與 DataTable `TruncateCell` 兩處同構的 truncate-span+tooltip presentation。\n// Tag 因 trigger≠量測元素(整個 tag root vs 內層 text span)+ Canvas measure + 自訂 a11y,正當地\n// 只消費 `useTruncated` hook、不走本 component(見 tag.tsx)。\n//\n// 「永遠 wrap + `open={isTruncated?undefined:false}`」而非「未截斷回裸 span、截斷才 wrap」:\n// 後者切換 JSX 樹會讓 span unmount/remount → ref 換到新 DOM、useEffect[] 不重跑 → 觀察的 DOM 與\n// 實際 DOM 對不上(Breadcrumb 2026-05-11 抓的 bug)。always-wrap 保 DOM 節點生命週期穩定;\n// `open={false}` 時 TooltipTrigger asChild 只把 handler/data-state 合併到同一 span(無多餘 DOM、\n// tooltip 靜默),與裸 span 視覺行為等價。\n\n/** @internal 隨 `TruncatedText`(DS-internal 組合 primitive)一併不進 root barrel front-door;subpath 仍可取。 */\nexport interface TruncatedTextProps {\n children: React.ReactNode\n /** 附加到截斷 span 的 className(如 DataTable 的 text-align)。 */\n className?: string\n /**\n * Tooltip 顯示內容,預設 = `children`。當 `children` 為非字串 ReactNode(icon+text 等)、\n * 但已知完整文字時傳入(Breadcrumb 的 `fullText`)。\n */\n tooltip?: React.ReactNode\n /**\n * span 的 display:`'inline'`(預設,保 baseline/垂直對齊,DataTable cell 用)/ `'block'`(Breadcrumb 用)。\n * ⚠️ DataTable 刻意用 inline —— `block` 會改 baseline 使 Field/inline-flex cell 垂直對齊 collapse。\n */\n display?: 'block' | 'inline'\n}\n\n/**\n * @internal DS-internal 組合 primitive:由 Breadcrumb / DataTable 內部消費以統一 truncate-tooltip 呈現。\n * end-user app 若需「單行截斷 + tooltip」直接消費 public `useTruncated` hook 自組(trigger/a11y 自控),\n * 或經 per-component subpath 取用本 component。不進 root barrel front-door。\n */\nexport function TruncatedText({ children, className, tooltip, display = 'inline' }: TruncatedTextProps) {\n const { ref, isTruncated } = useTruncated<HTMLSpanElement>()\n return (\n <Tooltip open={isTruncated ? undefined : false}>\n <TooltipTrigger asChild>\n <span ref={ref} className={cn('truncate min-w-0', display === 'block' && 'block', className)}>\n {children}\n </span>\n </TooltipTrigger>\n <TooltipContent>{tooltip ?? children}</TooltipContent>\n </Tooltip>\n )\n}\nTruncatedText.displayName = 'TruncatedText'\n"],"names":[],"mappings":";;;;AA+CO,SAAS,cAAc,EAAE,UAAU,WAAW,SAAS,UAAU,YAAgC;AACtG,QAAM,EAAE,KAAK,YAAA,IAAgB,aAAA;AAC7B,SACE,qBAAC,SAAA,EAAQ,MAAM,cAAc,SAAY,OACvC,UAAA;AAAA,IAAA,oBAAC,gBAAA,EAAe,SAAO,MACrB,UAAA,oBAAC,UAAK,KAAU,WAAW,GAAG,oBAAoB,YAAY,WAAW,SAAS,SAAS,GACxF,UACH,GACF;AAAA,IACA,oBAAC,gBAAA,EAAgB,UAAA,WAAW,SAAA,CAAS;AAAA,EAAA,GACvC;AAEJ;AACA,cAAc,cAAc;"}
|
package/llms-full.txt
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @qijenchen/design-system — 完整設計參考(llms-full)
|
|
2
2
|
|
|
3
|
-
> 全 component / pattern 的 variants / sizes / 禁止事項。build-time 從 spec.md frontmatter 生成,禁手改。v0.1.0-beta.
|
|
3
|
+
> 全 component / pattern 的 variants / sizes / 禁止事項。build-time 從 spec.md frontmatter 生成,禁手改。v0.1.0-beta.89。
|
|
4
4
|
|
|
5
5
|
# Components
|
|
6
6
|
|
package/llms.txt
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# @qijenchen/design-system
|
|
2
2
|
|
|
3
3
|
> World-class React design system(Radix/shadcn + Tailwind v4 + 自訂 design token)。
|
|
4
|
-
> 57 components + 4 public patterns + design tokens。v0.1.0-beta.
|
|
4
|
+
> 57 components + 4 public patterns + design tokens。v0.1.0-beta.89。
|
|
5
5
|
|
|
6
6
|
本檔由 source(spec.md frontmatter + Storybook index)build-time 自動生成,**禁手改**(CI --check drift gate 守)。
|
|
7
7
|
每元件 / pattern 的完整 variants / sizes / 禁止事項 全文見 [llms-full.txt](./llms-full.txt)。
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@qijenchen/design-system",
|
|
3
|
-
"version": "0.1.0-beta.
|
|
3
|
+
"version": "0.1.0-beta.89",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "World-class design system — components, patterns, tokens, hooks (single source of truth for team distribution).",
|
|
6
6
|
"type": "module",
|
|
@@ -5,7 +5,7 @@ import { Slot } from '@radix-ui/react-slot'
|
|
|
5
5
|
import { ChevronRight, MoreHorizontal, type LucideIcon } from 'lucide-react'
|
|
6
6
|
import { cn } from '@/lib/utils'
|
|
7
7
|
import { ItemInlineActionButton } from '@/design-system/patterns/element-anatomy/item-anatomy'
|
|
8
|
-
import {
|
|
8
|
+
import { TruncatedText } from '@/design-system/patterns/element-anatomy/truncated-text'
|
|
9
9
|
import {
|
|
10
10
|
DropdownMenu,
|
|
11
11
|
DropdownMenuTrigger,
|
|
@@ -13,71 +13,9 @@ import {
|
|
|
13
13
|
DropdownMenuItem,
|
|
14
14
|
} from '@/design-system/components/DropdownMenu/dropdown-menu'
|
|
15
15
|
|
|
16
|
-
// ── TruncatedLabel
|
|
17
|
-
//
|
|
18
|
-
//
|
|
19
|
-
// 設計註記(非待辦):本 component / DataTable TruncateCell / Tag inner 三處同 truncate-tooltip idiom,
|
|
20
|
-
// 已達 Rule-of-3;是否抽 `patterns/element-anatomy/truncated-text.tsx` 共用 primitive 屬 SSOT-affecting
|
|
21
|
-
// 結構決策(新 pattern),留 user 拍板後再做,不在此自行抽取(避免無授權新增 pattern primitive)。
|
|
22
|
-
|
|
23
|
-
type RoCallback = (entry: ResizeObserverEntry) => void
|
|
24
|
-
let sharedRO: ResizeObserver | null = null
|
|
25
|
-
const sharedROCallbacks = new WeakMap<Element, RoCallback>()
|
|
26
|
-
function getSharedRO(): ResizeObserver {
|
|
27
|
-
if (sharedRO) return sharedRO
|
|
28
|
-
sharedRO = new ResizeObserver((entries) => {
|
|
29
|
-
entries.forEach((e) => {
|
|
30
|
-
const cb = sharedROCallbacks.get(e.target)
|
|
31
|
-
if (cb) cb(e)
|
|
32
|
-
})
|
|
33
|
-
})
|
|
34
|
-
return sharedRO
|
|
35
|
-
}
|
|
36
|
-
function observeShared(el: Element, cb: RoCallback): () => void {
|
|
37
|
-
const obs = getSharedRO()
|
|
38
|
-
sharedROCallbacks.set(el, cb)
|
|
39
|
-
obs.observe(el)
|
|
40
|
-
return () => { sharedROCallbacks.delete(el); obs.unobserve(el) }
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
function TruncatedLabel({ children, fullText }: { children: React.ReactNode; fullText?: string }) {
|
|
44
|
-
const ref = React.useRef<HTMLSpanElement>(null)
|
|
45
|
-
const [isTruncated, setIsTruncated] = React.useState(false)
|
|
46
|
-
React.useEffect(() => {
|
|
47
|
-
const el = ref.current
|
|
48
|
-
if (!el) return
|
|
49
|
-
const check = () => setIsTruncated(el.scrollWidth > el.clientWidth)
|
|
50
|
-
check()
|
|
51
|
-
// 2026-05-11 fix:首幀 layout 未完成 / 字型 async load → scrollWidth=clientWidth 假陰性。
|
|
52
|
-
// RAF + 短延遲再驗一次,捕獲字型 / 容器尺寸後變(對齊 TruncateCell / Tag SSOT pattern)。
|
|
53
|
-
const raf = requestAnimationFrame(check)
|
|
54
|
-
const t = setTimeout(check, 100)
|
|
55
|
-
const cleanup = observeShared(el, check)
|
|
56
|
-
return () => {
|
|
57
|
-
cancelAnimationFrame(raf)
|
|
58
|
-
clearTimeout(t)
|
|
59
|
-
cleanup()
|
|
60
|
-
}
|
|
61
|
-
}, [])
|
|
62
|
-
// Tooltip canonical:per `tooltip.principles.stories.tsx:190`「Tooltip 是資訊補救 — 文字被
|
|
63
|
-
// truncate 時才顯示完整內容。沒被截斷就不該顯示 tooltip」
|
|
64
|
-
//
|
|
65
|
-
// 2026-05-11 fix(playwright tooltip-on-truncate 卡 hover 沒 tooltip):
|
|
66
|
-
// 原本 isTruncated=false 直接 return 裸 span / true 才 wrap Tooltip → JSX 樹結構改變
|
|
67
|
-
// → React 把 span unmount + remount(因為 wrapper component 變),ref 換到新 span,
|
|
68
|
-
// useEffect [] 不重跑(同 component instance)→ 觀察的 DOM 跟實際 DOM 對不上。
|
|
69
|
-
// Fix:**永遠 wrap Tooltip**(同 DOM 節點生命週期);`open` 由 isTruncated 控制 —
|
|
70
|
-
// 沒被 truncate 就 force `open={false}`,有 truncate 就 `undefined`(uncontrolled,
|
|
71
|
-
// hover 走 Radix default behavior)。對齊 canonical「沒被截斷就不該 tooltip」。
|
|
72
|
-
return (
|
|
73
|
-
<Tooltip open={isTruncated ? undefined : false}>
|
|
74
|
-
<TooltipTrigger asChild>
|
|
75
|
-
<span ref={ref} className="truncate min-w-0 block">{children}</span>
|
|
76
|
-
</TooltipTrigger>
|
|
77
|
-
<TooltipContent>{fullText ?? children}</TooltipContent>
|
|
78
|
-
</Tooltip>
|
|
79
|
-
)
|
|
80
|
-
}
|
|
16
|
+
// ── TruncatedLabel ── 2026-07-19:truncate+tooltip 引擎 + presentation 已抽成 SSOT primitive
|
|
17
|
+
// `patterns/element-anatomy/truncated-text`(`<TruncatedText>` 消費 `useTruncated` hook)。本檔改為
|
|
18
|
+
// 消費 `<TruncatedText display="block" tooltip={fullText}>`,原 file-local shared RO + TruncatedLabel 已移除。
|
|
81
19
|
|
|
82
20
|
/**
|
|
83
21
|
* Breadcrumb — 顯示當前頁面在階層中的位置
|
|
@@ -213,10 +151,10 @@ const BreadcrumbList = React.forwardRef<HTMLOListElement, BreadcrumbListProps>(
|
|
|
213
151
|
<BreadcrumbItem key={`${role}-${typeof spec.label === 'string' ? spec.label : idx}`} role={role}>
|
|
214
152
|
{role === 'current'
|
|
215
153
|
? <BreadcrumbPage startIcon={spec.startIcon}>
|
|
216
|
-
<
|
|
154
|
+
<TruncatedText display="block" tooltip={typeof spec.label === 'string' ? spec.label : undefined}>{spec.label}</TruncatedText>
|
|
217
155
|
</BreadcrumbPage>
|
|
218
156
|
: <BreadcrumbLink href={spec.href} asChild={spec.asChild} startIcon={spec.startIcon}>
|
|
219
|
-
<
|
|
157
|
+
<TruncatedText display="block" tooltip={typeof spec.label === 'string' ? spec.label : undefined}>{spec.label}</TruncatedText>
|
|
220
158
|
</BreadcrumbLink>
|
|
221
159
|
}
|
|
222
160
|
</BreadcrumbItem>
|
|
@@ -462,7 +400,7 @@ const BreadcrumbLink = React.forwardRef<HTMLAnchorElement, BreadcrumbLinkProps>(
|
|
|
462
400
|
// on truncate」per spec.md / Polaris breadcrumb)。Non-string children(consumer 自訂 icon+text
|
|
463
401
|
// 結構)→ pass-through 不 force-wrap(consumer own truncate)。
|
|
464
402
|
const wrappedChildren = typeof children === 'string'
|
|
465
|
-
? <
|
|
403
|
+
? <TruncatedText display="block" tooltip={children}>{children}</TruncatedText>
|
|
466
404
|
: children
|
|
467
405
|
const sharedClassName = cn(
|
|
468
406
|
'inline-flex items-center gap-2',
|
|
@@ -510,7 +448,7 @@ const BreadcrumbPage = React.forwardRef<HTMLSpanElement, BreadcrumbPageProps>(
|
|
|
510
448
|
const { size } = React.useContext(BreadcrumbContext)
|
|
511
449
|
// 2026-05-12 fix(同 BreadcrumbLink):純文字 children → auto-wrap TruncatedLabel。
|
|
512
450
|
const wrappedChildren = typeof children === 'string'
|
|
513
|
-
? <
|
|
451
|
+
? <TruncatedText display="block" tooltip={children}>{children}</TruncatedText>
|
|
514
452
|
: children
|
|
515
453
|
return (
|
|
516
454
|
<span
|