@comitor/ui 3.0.1 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/dist/components/composite/confirm-dialog.js +56 -35
  2. package/dist/components/composite/confirm-dialog.js.map +1 -1
  3. package/dist/components/composite/search-filter-bar-constants.d.ts +3 -0
  4. package/dist/components/composite/search-filter-bar-constants.js.map +1 -1
  5. package/dist/components/composite/table-pagination-constants.d.ts +3 -1
  6. package/dist/components/composite/table-pagination-constants.js.map +1 -1
  7. package/dist/components/composite/table-pagination.js +10 -2
  8. package/dist/components/composite/table-pagination.js.map +1 -1
  9. package/dist/components/composite/text-utils.d.ts +4 -23
  10. package/dist/components/composite/text-utils.js +1 -11
  11. package/dist/components/composite/text-utils.js.map +1 -1
  12. package/dist/components/ui/banner.d.ts +8 -0
  13. package/dist/components/ui/banner.js +149 -35
  14. package/dist/components/ui/banner.js.map +1 -1
  15. package/dist/components/ui/mask-input-constants.d.ts +34 -2
  16. package/dist/components/ui/mask-input-constants.js +56 -5
  17. package/dist/components/ui/mask-input-constants.js.map +1 -1
  18. package/dist/components/ui/mask-input.d.ts +6 -5
  19. package/dist/components/ui/mask-input.js +5 -1
  20. package/dist/components/ui/mask-input.js.map +1 -1
  21. package/dist/components/ui/mention.d.ts +14 -2
  22. package/dist/components/ui/mention.js +33 -6
  23. package/dist/components/ui/mention.js.map +1 -1
  24. package/dist/components/ui/phone-input.d.ts +18 -8
  25. package/dist/components/ui/phone-input.js +120 -33
  26. package/dist/components/ui/phone-input.js.map +1 -1
  27. package/dist/components/ui/scroll-spy.js +46 -31
  28. package/dist/components/ui/scroll-spy.js.map +1 -1
  29. package/dist/components/ui/stepper.js +26 -3
  30. package/dist/components/ui/stepper.js.map +1 -1
  31. package/dist/components/ui/time-picker.d.ts +24 -4
  32. package/dist/components/ui/time-picker.js +425 -162
  33. package/dist/components/ui/time-picker.js.map +1 -1
  34. package/dist/components/ui/timeline.js +45 -9
  35. package/dist/components/ui/timeline.js.map +1 -1
  36. package/dist/data-grid/data-grid-cell-variants.js +4 -4
  37. package/dist/data-grid/data-grid-cell-variants.js.map +1 -1
  38. package/dist/data-grid/data-grid-cell-wrapper.d.ts +1 -1
  39. package/dist/data-grid/data-grid-cell-wrapper.js +6 -0
  40. package/dist/data-grid/data-grid-cell-wrapper.js.map +1 -1
  41. package/dist/data-grid/data-grid-row.js +1 -1
  42. package/dist/data-grid/data-grid-row.js.map +1 -1
  43. package/dist/data-grid/data-grid-select-column.js +6 -2
  44. package/dist/data-grid/data-grid-select-column.js.map +1 -1
  45. package/dist/data-grid/data-grid-skeleton.d.ts +5 -0
  46. package/dist/data-grid/data-grid-skeleton.js +1 -4
  47. package/dist/data-grid/data-grid-skeleton.js.map +1 -1
  48. package/dist/data-grid/data-grid.d.ts +1 -1
  49. package/dist/data-grid/data-grid.js +3 -2
  50. package/dist/data-grid/data-grid.js.map +1 -1
  51. package/dist/data-grid/filters.js +3 -2
  52. package/dist/data-grid/filters.js.map +1 -1
  53. package/dist/data-grid/types.d.ts +7 -0
  54. package/dist/data-grid/use-data-grid.d.ts +3 -2
  55. package/dist/data-grid/use-data-grid.js +70 -24
  56. package/dist/data-grid/use-data-grid.js.map +1 -1
  57. package/dist/data-grid/utils.d.ts +7 -0
  58. package/dist/data-grid/utils.js +3 -1
  59. package/dist/data-grid/utils.js.map +1 -1
  60. package/dist/i18n/namespaces/search-filter-bar.js +8 -6
  61. package/dist/i18n/namespaces/search-filter-bar.js.map +1 -1
  62. package/dist/i18n/namespaces/table-pagination.js +6 -4
  63. package/dist/i18n/namespaces/table-pagination.js.map +1 -1
  64. package/dist/index.d.ts +2 -1
  65. package/dist/lib/collect-item-elements.d.ts +47 -0
  66. package/dist/lib/collect-item-elements.js +22 -0
  67. package/dist/lib/collect-item-elements.js.map +1 -0
  68. package/dist/lib/text-search.d.ts +32 -0
  69. package/dist/lib/text-search.js +17 -0
  70. package/dist/lib/text-search.js.map +1 -0
  71. package/dist/shell/app-shell.d.ts +1 -0
  72. package/dist/shell/display-axis-provider.d.ts +1 -1
  73. package/dist/shell/index.d.ts +2 -1
  74. package/dist/shell/shell-context.d.ts +1 -0
  75. package/dist/shell/utils.d.ts +2 -1
  76. package/package.json +1 -1
@@ -5,6 +5,7 @@ import { Slot } from "@radix-ui/react-slot";
5
5
  import { cva } from "class-variance-authority";
6
6
  import * as React from "react";
7
7
  import { cn } from "../../lib/cn.js";
8
+ import { collectItemElements } from "../../lib/collect-item-elements.js";
8
9
  import { useComposedRefs } from "../../lib/compose-refs.js";
9
10
  import { useIsomorphicLayoutEffect } from "../../lib/use-isomorphic-layout-effect.js";
10
11
  import { useLazyRef } from "../../lib/use-lazy-ref.js";
@@ -30,13 +31,26 @@ function getSortedEntries(entries) {
30
31
  return 0;
31
32
  });
32
33
  }
33
- function useStore(selector) {
34
+ function getItemsFromChildren(children) {
35
+ const indexes = /* @__PURE__ */ new WeakMap();
36
+ const items = collectItemElements(children, { item: TimelineItem }) ?? [];
37
+ for (const [index, { props }] of items.entries()) {
38
+ if (indexes.has(props)) return { indexes: /* @__PURE__ */ new WeakMap(), count: 0 };
39
+ indexes.set(props, index);
40
+ }
41
+ return { indexes, count: items.length };
42
+ }
43
+ function useStore(selector, initialSelector) {
34
44
  const store = React.useContext(StoreContext);
35
45
  if (!store) {
36
46
  throw new Error(`\`useStore\` ph\u1EA3i \u0111\u01B0\u1EE3c g\u1ECDi b\xEAn trong \`${ROOT_NAME}\``);
37
47
  }
38
- const getSnapshot = React.useCallback(() => selector(store), [store, selector]);
39
- return React.useSyncExternalStore(store.subscribe, getSnapshot, getSnapshot);
48
+ const getSnapshot = React.useCallback(
49
+ () => store.hasRegistered() ? selector(store) : initialSelector(store),
50
+ [store, selector, initialSelector]
51
+ );
52
+ const getServerSnapshot = React.useCallback(() => initialSelector(store), [store, initialSelector]);
53
+ return React.useSyncExternalStore(store.subscribe, getSnapshot, getServerSnapshot);
40
54
  }
41
55
  const StoreContext = React.createContext(null);
42
56
  function useStoreContext(consumerName) {
@@ -107,6 +121,8 @@ function Timeline(props) {
107
121
  const stateRef = useLazyRef(() => ({
108
122
  items: /* @__PURE__ */ new Map()
109
123
  }));
124
+ const initialItemsRef = useLazyRef(() => getItemsFromChildren(props.children));
125
+ const registeredRef = React.useRef(false);
110
126
  const store = React.useMemo(() => {
111
127
  return {
112
128
  subscribe: (cb) => {
@@ -141,9 +157,22 @@ function Timeline(props) {
141
157
  const entries = Array.from(stateRef.current.items.entries());
142
158
  const sortedEntries = getSortedEntries(entries);
143
159
  return sortedEntries.findIndex(([key]) => key === id);
160
+ },
161
+ hasRegistered: () => registeredRef.current,
162
+ getInitialItemIndex: (itemProps) => initialItemsRef.current.indexes.get(itemProps) ?? -1,
163
+ // Cùng luật với `getNextItemStatus`, trên vị trí đọc từ cây.
164
+ getInitialNextItemStatus: (initialIndex, activeIndex2) => {
165
+ if (initialIndex === -1 || initialIndex === initialItemsRef.current.count - 1) {
166
+ return void 0;
167
+ }
168
+ return getItemStatus(initialIndex + 1, activeIndex2);
144
169
  }
145
170
  };
146
- }, [listenersRef, stateRef]);
171
+ }, [listenersRef, stateRef, initialItemsRef]);
172
+ useIsomorphicLayoutEffect(() => {
173
+ registeredRef.current = true;
174
+ store.notify();
175
+ }, [store]);
147
176
  const contextValue = React.useMemo(
148
177
  () => ({
149
178
  dir,
@@ -233,7 +262,11 @@ function TimelineItem(props) {
233
262
  const itemId = id ?? instanceId;
234
263
  const itemRef = React.useRef(null);
235
264
  const composedRef = useComposedRefs(ref, itemRef);
236
- const itemIndex = useStore((state) => state.getItemIndex(itemId));
265
+ const initialIndex = store.getInitialItemIndex(props);
266
+ const itemIndex = useStore(
267
+ (state) => state.getItemIndex(itemId),
268
+ () => initialIndex
269
+ );
237
270
  const status = React.useMemo(() => {
238
271
  return getItemStatus(itemIndex, activeIndex);
239
272
  }, [activeIndex, itemIndex]);
@@ -245,8 +278,8 @@ function TimelineItem(props) {
245
278
  }, [itemId, store]);
246
279
  const isAlternateRight = variant === "alternate" && itemIndex % 2 === 1;
247
280
  const itemContextValue = React.useMemo(
248
- () => ({ id: itemId, status, isAlternateRight }),
249
- [itemId, status, isAlternateRight]
281
+ () => ({ id: itemId, status, isAlternateRight, initialIndex }),
282
+ [itemId, status, isAlternateRight, initialIndex]
250
283
  );
251
284
  const ItemPrimitive = asChild ? Slot : "div";
252
285
  return /* @__PURE__ */ jsx(TimelineItemContext.Provider, { value: itemContextValue, children: /* @__PURE__ */ jsx(
@@ -477,8 +510,11 @@ const timelineConnectorVariants = cva("absolute z-0", {
477
510
  function TimelineConnector(props) {
478
511
  const { asChild, forceMount, className, ...connectorProps } = props;
479
512
  const { orientation, variant, activeIndex } = useTimelineContext(CONNECTOR_NAME);
480
- const { id, status, isAlternateRight } = useTimelineItemContext(CONNECTOR_NAME);
481
- const nextItemStatus = useStore((state) => state.getNextItemStatus(id, activeIndex));
513
+ const { id, status, isAlternateRight, initialIndex } = useTimelineItemContext(CONNECTOR_NAME);
514
+ const nextItemStatus = useStore(
515
+ (state) => state.getNextItemStatus(id, activeIndex),
516
+ (state) => state.getInitialNextItemStatus(initialIndex, activeIndex)
517
+ );
482
518
  const isLastItem = nextItemStatus === void 0;
483
519
  if (!forceMount && isLastItem) return null;
484
520
  const isConnectorCompleted = nextItemStatus === "completed" || nextItemStatus === "active";
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/ui/timeline.tsx"],"sourcesContent":["\"use client\";\n\n/*\n * Port từ Dice UI (https://diceui.com/docs/components/timeline) — MIT, © 2024 Sadman Sakib.\n * Giữ nguyên cấu trúc thượng nguồn để còn đối chiếu ngược được; mọi chỗ đổi đều có chú thích.\n */\n\nimport { useDirection } from \"@radix-ui/react-direction\";\nimport { Slot } from \"@radix-ui/react-slot\";\nimport { cva } from \"class-variance-authority\";\nimport * as React from \"react\";\nimport { cn } from \"../../lib/cn.js\";\nimport { useComposedRefs } from \"../../lib/compose-refs.js\";\nimport { useIsomorphicLayoutEffect } from \"../../lib/use-isomorphic-layout-effect.js\";\nimport { useLazyRef } from \"../../lib/use-lazy-ref.js\";\n\ntype Direction = \"ltr\" | \"rtl\";\ntype Orientation = \"vertical\" | \"horizontal\";\ntype Variant = \"default\" | \"alternate\";\ntype Status = \"completed\" | \"active\" | \"pending\";\n\ninterface DivProps extends React.ComponentProps<\"div\"> {\n asChild?: boolean;\n}\n\ntype ItemElement = React.ComponentRef<typeof TimelineItem>;\n\nconst ROOT_NAME = \"Timeline\";\nconst ITEM_NAME = \"TimelineItem\";\nconst DOT_NAME = \"TimelineDot\";\nconst CONNECTOR_NAME = \"TimelineConnector\";\nconst CONTENT_NAME = \"TimelineContent\";\n\nfunction getItemStatus(itemIndex: number, activeIndex?: number): Status {\n /*\n * ⚠ Khác thượng nguồn: mục đăng ký chỉ số của mình trong layout effect, nên ở lượt render phía\n * server (và lượt đầu trước hydrate) MỌI mục đều mang chỉ số -1. Bản gốc so thẳng `-1 < activeIndex`\n * → mọi chấm cùng ra \"completed\" (tô gold) cho tới khi hydrate xong — một trạng thái SAI, không\n * chỉ là thiếu. Chưa biết vị trí thì coi là \"pending\": trung tính, và đúng với phần lớn mục.\n */\n if (activeIndex === undefined || itemIndex < 0) return \"pending\";\n if (itemIndex < activeIndex) return \"completed\";\n if (itemIndex === activeIndex) return \"active\";\n return \"pending\";\n}\n\nfunction getSortedEntries(entries: [string, React.RefObject<ItemElement | null>][]) {\n return entries.sort((a, b) => {\n const elementA = a[1].current;\n const elementB = b[1].current;\n if (!elementA || !elementB) return 0;\n const position = elementA.compareDocumentPosition(elementB);\n if (position & Node.DOCUMENT_POSITION_FOLLOWING) return -1;\n if (position & Node.DOCUMENT_POSITION_PRECEDING) return 1;\n return 0;\n });\n}\n\nfunction useStore<T>(selector: (store: Store) => T): T {\n const store = React.useContext(StoreContext);\n if (!store) {\n throw new Error(`\\`useStore\\` phải được gọi bên trong \\`${ROOT_NAME}\\``);\n }\n\n const getSnapshot = React.useCallback(() => selector(store), [store, selector]);\n\n return React.useSyncExternalStore(store.subscribe, getSnapshot, getSnapshot);\n}\n\ninterface StoreState {\n items: Map<string, React.RefObject<ItemElement | null>>;\n}\n\ninterface Store {\n subscribe: (callback: () => void) => () => void;\n getState: () => StoreState;\n notify: () => void;\n onItemRegister: (id: string, ref: React.RefObject<ItemElement | null>) => void;\n onItemUnregister: (id: string) => void;\n getNextItemStatus: (id: string, activeIndex?: number) => Status | undefined;\n getItemIndex: (id: string) => number;\n}\n\nconst StoreContext = React.createContext<Store | null>(null);\n\nfunction useStoreContext(consumerName: string) {\n const context = React.useContext(StoreContext);\n if (!context) {\n throw new Error(`\\`${consumerName}\\` phải nằm bên trong \\`${ROOT_NAME}\\``);\n }\n return context;\n}\n\ninterface TimelineContextValue {\n dir: Direction;\n orientation: Orientation;\n variant: Variant;\n activeIndex?: number;\n}\n\nconst TimelineContext = React.createContext<TimelineContextValue | null>(null);\n\nfunction useTimelineContext(consumerName: string) {\n const context = React.useContext(TimelineContext);\n if (!context) {\n throw new Error(`\\`${consumerName}\\` phải nằm bên trong \\`${ROOT_NAME}\\``);\n }\n return context;\n}\n\nconst timelineVariants = cva(\"relative flex [--timeline-connector-thickness:0.125rem] [--timeline-dot-size:0.875rem]\", {\n variants: {\n orientation: {\n vertical: \"flex-col\",\n horizontal: \"flex-row items-start\"\n },\n variant: {\n default: \"\",\n alternate: \"\"\n }\n },\n compoundVariants: [\n {\n orientation: \"vertical\",\n variant: \"default\",\n class: \"gap-6\"\n },\n {\n orientation: \"horizontal\",\n variant: \"default\",\n class: \"gap-8\"\n },\n {\n orientation: \"vertical\",\n variant: \"alternate\",\n class: \"relative w-full gap-3\"\n },\n {\n orientation: \"horizontal\",\n variant: \"alternate\",\n class: \"items-center gap-4\"\n }\n ],\n defaultVariants: {\n orientation: \"vertical\",\n variant: \"default\"\n }\n});\n\ninterface TimelineProps extends DivProps {\n dir?: Direction;\n orientation?: Orientation;\n variant?: Variant;\n activeIndex?: number;\n}\n\nfunction Timeline(props: TimelineProps) {\n const {\n orientation = \"vertical\",\n variant = \"default\",\n dir: dirProp,\n activeIndex,\n asChild,\n className,\n ...rootProps\n } = props;\n\n const dir = useDirection(dirProp);\n\n const listenersRef = useLazyRef(() => new Set<() => void>());\n const stateRef = useLazyRef<StoreState>(() => ({\n items: new Map()\n }));\n\n const store = React.useMemo<Store>(() => {\n return {\n subscribe: (cb) => {\n listenersRef.current.add(cb);\n return () => listenersRef.current.delete(cb);\n },\n getState: () => stateRef.current,\n notify: () => {\n for (const cb of listenersRef.current) {\n cb();\n }\n },\n onItemRegister: (id: string, ref: React.RefObject<ItemElement | null>) => {\n stateRef.current.items.set(id, ref);\n store.notify();\n },\n onItemUnregister: (id: string) => {\n stateRef.current.items.delete(id);\n store.notify();\n },\n getNextItemStatus: (id: string, activeIndex?: number) => {\n const entries = Array.from(stateRef.current.items.entries());\n const sortedEntries = getSortedEntries(entries);\n\n const currentIndex = sortedEntries.findIndex(([key]) => key === id);\n if (currentIndex === -1 || currentIndex === sortedEntries.length - 1) {\n return undefined;\n }\n\n const nextItemIndex = currentIndex + 1;\n return getItemStatus(nextItemIndex, activeIndex);\n },\n getItemIndex: (id: string) => {\n const entries = Array.from(stateRef.current.items.entries());\n const sortedEntries = getSortedEntries(entries);\n return sortedEntries.findIndex(([key]) => key === id);\n }\n };\n }, [listenersRef, stateRef]);\n\n const contextValue = React.useMemo<TimelineContextValue>(\n () => ({\n dir,\n orientation,\n variant,\n activeIndex\n }),\n [dir, orientation, variant, activeIndex]\n );\n\n const RootPrimitive = asChild ? Slot : \"div\";\n\n return (\n <StoreContext.Provider value={store}>\n <TimelineContext.Provider value={contextValue}>\n {/*\n * ⚠ Khác thượng nguồn: bỏ `aria-orientation` khỏi thẻ gốc. `role=\"list\"` không nhận thuộc\n * tính đó theo ARIA 1.2 (axe báo `aria-allowed-attr`); hướng vẫn có ở `data-orientation`.\n */}\n <RootPrimitive\n role=\"list\"\n data-slot=\"timeline\"\n data-orientation={orientation}\n data-variant={variant}\n dir={dir}\n {...rootProps}\n className={cn(timelineVariants({ orientation, variant, className }))}\n />\n </TimelineContext.Provider>\n </StoreContext.Provider>\n );\n}\n\ninterface TimelineItemContextValue {\n id: string;\n status: Status;\n isAlternateRight: boolean;\n}\n\nconst TimelineItemContext = React.createContext<TimelineItemContextValue | null>(null);\n\nfunction useTimelineItemContext(consumerName: string) {\n const context = React.useContext(TimelineItemContext);\n if (!context) {\n throw new Error(`\\`${consumerName}\\` phải nằm bên trong \\`${ITEM_NAME}\\``);\n }\n return context;\n}\n\nconst timelineItemVariants = cva(\"relative flex\", {\n variants: {\n orientation: {\n vertical: \"\",\n horizontal: \"\"\n },\n variant: {\n default: \"\",\n alternate: \"\"\n },\n isAlternateRight: {\n true: \"\",\n false: \"\"\n }\n },\n compoundVariants: [\n {\n orientation: \"vertical\",\n variant: \"default\",\n class: \"gap-3 pb-8 last:pb-0\"\n },\n {\n orientation: \"horizontal\",\n variant: \"default\",\n class: \"flex-col gap-3\"\n },\n {\n orientation: \"vertical\",\n variant: \"alternate\",\n isAlternateRight: false,\n class: \"w-1/2 gap-3 pr-6 pb-12 last:pb-0\"\n },\n {\n orientation: \"vertical\",\n variant: \"alternate\",\n isAlternateRight: true,\n class: \"ml-auto w-1/2 flex-row-reverse gap-3 pb-12 pl-6 last:pb-0\"\n },\n {\n orientation: \"horizontal\",\n variant: \"alternate\",\n class: \"grid min-w-0 grid-rows-[1fr_auto_1fr] gap-3\"\n }\n ],\n defaultVariants: {\n orientation: \"vertical\",\n variant: \"default\",\n isAlternateRight: false\n }\n});\n\nfunction TimelineItem(props: DivProps) {\n const { asChild, className, id, ref, ...itemProps } = props;\n\n const { dir, orientation, variant, activeIndex } = useTimelineContext(ITEM_NAME);\n const store = useStoreContext(ITEM_NAME);\n\n const instanceId = React.useId();\n const itemId = id ?? instanceId;\n const itemRef = React.useRef<ItemElement | null>(null);\n const composedRef = useComposedRefs(ref, itemRef);\n\n const itemIndex = useStore((state) => state.getItemIndex(itemId));\n\n const status = React.useMemo<Status>(() => {\n return getItemStatus(itemIndex, activeIndex);\n }, [activeIndex, itemIndex]);\n\n // ⚠ Khác thượng nguồn: phụ thuộc là `itemId` (thứ thật sự được dùng) thay cho `id` — cùng\n // nghĩa, vì `itemId = id ?? instanceId` và `instanceId` không đổi suốt vòng đời.\n useIsomorphicLayoutEffect(() => {\n store.onItemRegister(itemId, itemRef);\n return () => {\n store.onItemUnregister(itemId);\n };\n }, [itemId, store]);\n\n const isAlternateRight = variant === \"alternate\" && itemIndex % 2 === 1;\n\n const itemContextValue = React.useMemo<TimelineItemContextValue>(\n () => ({ id: itemId, status, isAlternateRight }),\n [itemId, status, isAlternateRight]\n );\n\n const ItemPrimitive = asChild ? Slot : \"div\";\n\n return (\n <TimelineItemContext.Provider value={itemContextValue}>\n <ItemPrimitive\n role=\"listitem\"\n aria-current={status === \"active\" ? \"step\" : undefined}\n data-slot=\"timeline-item\"\n data-status={status}\n data-orientation={orientation}\n data-alternate-right={isAlternateRight ? \"\" : undefined}\n id={itemId}\n dir={dir}\n {...itemProps}\n ref={composedRef}\n className={cn(\n timelineItemVariants({\n orientation,\n variant,\n isAlternateRight,\n className\n })\n )}\n />\n </TimelineItemContext.Provider>\n );\n}\n\nconst timelineContentVariants = cva(\"flex-1\", {\n variants: {\n orientation: {\n vertical: \"\",\n horizontal: \"\"\n },\n variant: {\n default: \"\",\n alternate: \"\"\n },\n isAlternateRight: {\n true: \"\",\n false: \"\"\n }\n },\n compoundVariants: [\n {\n variant: \"alternate\",\n orientation: \"vertical\",\n isAlternateRight: false,\n class: \"text-right\"\n },\n {\n variant: \"alternate\",\n orientation: \"horizontal\",\n isAlternateRight: false,\n class: \"row-start-3 pt-2\"\n },\n {\n variant: \"alternate\",\n orientation: \"horizontal\",\n isAlternateRight: true,\n class: \"row-start-1 pb-2\"\n }\n ],\n defaultVariants: {\n orientation: \"vertical\",\n variant: \"default\",\n isAlternateRight: false\n }\n});\n\nfunction TimelineContent(props: DivProps) {\n const { asChild, className, ...contentProps } = props;\n\n const { variant, orientation } = useTimelineContext(CONTENT_NAME);\n const { status, isAlternateRight } = useTimelineItemContext(CONTENT_NAME);\n\n const ContentPrimitive = asChild ? Slot : \"div\";\n\n return (\n <ContentPrimitive\n data-slot=\"timeline-content\"\n data-status={status}\n {...contentProps}\n className={cn(\n timelineContentVariants({\n orientation,\n variant,\n isAlternateRight,\n className\n })\n )}\n />\n );\n}\n\n/*\n * ⚠ Khác thượng nguồn — màu chấm đi qua token VAI TRÒ (docs/hop-dong-mau.md §1):\n * chấm là thành phần PHI VĂN BẢN mang nghĩa (đánh dấu từng mốc và trạng thái của nó) → viền chịu\n * 3:1 với nền trang.\n * - đã xong / đang diễn ra: `border-primary-ink` thay `border-primary` (token TÔ NỀN, ~1,86:1 với\n * nền trang; bậc ink đạt 6,51:1 light · 12,67:1 dark ở bảng tương phản cao).\n * - chờ: `border-muted-foreground` thay `border-border` (bậc TRANG TRÍ 1,16:1, và cổng bắt viền trang\n * trí khi phần tử có bo góc + cỡ cố định). Cùng lựa chọn với tone `neutral` của `StatusPill`\n * (`STATUS_TONES.neutral.borderColor`): 5,23:1 light · 5,70:1 dark.\n */\nconst timelineDotVariants = cva(\n \"relative z-10 flex size-[var(--timeline-dot-size)] shrink-0 items-center justify-center rounded-full border-2 bg-background\",\n {\n variants: {\n status: {\n completed: \"border-primary-ink\",\n active: \"border-primary-ink\",\n pending: \"border-muted-foreground\"\n },\n orientation: {\n vertical: \"\",\n horizontal: \"\"\n },\n variant: {\n default: \"\",\n alternate: \"\"\n },\n isAlternateRight: {\n true: \"\",\n false: \"\"\n }\n },\n compoundVariants: [\n {\n variant: \"alternate\",\n orientation: \"vertical\",\n isAlternateRight: false,\n class: \"absolute -right-[calc(var(--timeline-dot-size)/2-var(--timeline-connector-thickness)/2)] bg-background\"\n },\n {\n variant: \"alternate\",\n orientation: \"vertical\",\n isAlternateRight: true,\n class: \"absolute -left-[calc(var(--timeline-dot-size)/2-var(--timeline-connector-thickness)/2)] bg-background\"\n },\n {\n variant: \"alternate\",\n orientation: \"horizontal\",\n class: \"row-start-2 bg-background\"\n },\n {\n variant: \"alternate\",\n status: \"completed\",\n class: \"bg-background\"\n },\n {\n variant: \"alternate\",\n status: \"active\",\n class: \"bg-background\"\n }\n ],\n defaultVariants: {\n status: \"pending\",\n orientation: \"vertical\",\n variant: \"default\",\n isAlternateRight: false\n }\n }\n);\n\nfunction TimelineDot(props: DivProps) {\n const { asChild, className, ...dotProps } = props;\n\n const { orientation, variant } = useTimelineContext(DOT_NAME);\n const { status, isAlternateRight } = useTimelineItemContext(DOT_NAME);\n\n const DotPrimitive = asChild ? Slot : \"div\";\n\n return (\n <DotPrimitive\n data-slot=\"timeline-dot\"\n data-status={status}\n data-orientation={orientation}\n {...dotProps}\n className={cn(\n timelineDotVariants({\n status,\n orientation,\n variant,\n isAlternateRight,\n className\n })\n )}\n />\n );\n}\n\n/*\n * ⚠ Khác thượng nguồn: đoạn nối ĐÃ XONG mang nghĩa tiến độ → `bg-primary-ink` thay `bg-primary`\n * (token tô nền, ~1,86:1 với nền trang). Đoạn chưa tới giữ `bg-border` — đường kẻ trang trí.\n */\nconst timelineConnectorVariants = cva(\"absolute z-0\", {\n variants: {\n isCompleted: {\n true: \"bg-primary-ink\",\n false: \"bg-border\"\n },\n orientation: {\n vertical: \"\",\n horizontal: \"\"\n },\n variant: {\n default: \"\",\n alternate: \"\"\n },\n isAlternateRight: {\n true: \"\",\n false: \"\"\n }\n },\n compoundVariants: [\n {\n orientation: \"vertical\",\n variant: \"default\",\n class:\n \"start-[calc(var(--timeline-dot-size)/2-var(--timeline-connector-thickness)/2)] top-3 h-[calc(100%+0.5rem)] w-[var(--timeline-connector-thickness)]\"\n },\n {\n orientation: \"horizontal\",\n variant: \"default\",\n class:\n \"start-3 top-[calc(var(--timeline-dot-size)/2-var(--timeline-connector-thickness)/2)] h-[var(--timeline-connector-thickness)] w-[calc(100%+0.5rem)]\"\n },\n {\n orientation: \"vertical\",\n variant: \"alternate\",\n isAlternateRight: false,\n class: \"top-2 -right-[calc(var(--timeline-connector-thickness)/2)] h-full w-[var(--timeline-connector-thickness)]\"\n },\n {\n orientation: \"vertical\",\n variant: \"alternate\",\n isAlternateRight: true,\n class: \"top-2 -left-[calc(var(--timeline-connector-thickness)/2)] h-full w-[var(--timeline-connector-thickness)]\"\n },\n {\n orientation: \"horizontal\",\n variant: \"alternate\",\n class:\n \"top-[calc(var(--timeline-dot-size)/2-var(--timeline-connector-thickness)/2)] left-3 row-start-2 h-[var(--timeline-connector-thickness)] w-[calc(100%+0.5rem)]\"\n }\n ],\n defaultVariants: {\n isCompleted: false,\n orientation: \"vertical\",\n variant: \"default\",\n isAlternateRight: false\n }\n});\n\ninterface TimelineConnectorProps extends DivProps {\n forceMount?: boolean;\n}\n\nfunction TimelineConnector(props: TimelineConnectorProps) {\n const { asChild, forceMount, className, ...connectorProps } = props;\n\n const { orientation, variant, activeIndex } = useTimelineContext(CONNECTOR_NAME);\n const { id, status, isAlternateRight } = useTimelineItemContext(CONNECTOR_NAME);\n\n const nextItemStatus = useStore((state) => state.getNextItemStatus(id, activeIndex));\n\n const isLastItem = nextItemStatus === undefined;\n\n if (!forceMount && isLastItem) return null;\n\n const isConnectorCompleted = nextItemStatus === \"completed\" || nextItemStatus === \"active\";\n\n const ConnectorPrimitive = asChild ? Slot : \"div\";\n\n return (\n <ConnectorPrimitive\n aria-hidden=\"true\"\n data-slot=\"timeline-connector\"\n data-completed={isConnectorCompleted ? \"\" : undefined}\n data-status={status}\n data-orientation={orientation}\n {...connectorProps}\n className={cn(\n timelineConnectorVariants({\n isCompleted: isConnectorCompleted,\n orientation,\n variant,\n isAlternateRight,\n className\n })\n )}\n />\n );\n}\n\nfunction TimelineHeader(props: DivProps) {\n const { asChild, className, ...headerProps } = props;\n\n const HeaderPrimitive = asChild ? Slot : \"div\";\n\n return (\n <HeaderPrimitive data-slot=\"timeline-header\" {...headerProps} className={cn(\"flex flex-col gap-1\", className)} />\n );\n}\n\nfunction TimelineTitle(props: DivProps) {\n const { asChild, className, ...titleProps } = props;\n\n const TitlePrimitive = asChild ? Slot : \"div\";\n\n return (\n <TitlePrimitive\n data-slot=\"timeline-title\"\n {...titleProps}\n className={cn(\"leading-none font-semibold\", className)}\n />\n );\n}\n\nfunction TimelineDescription(props: DivProps) {\n const { asChild, className, ...descriptionProps } = props;\n\n const DescriptionPrimitive = asChild ? Slot : \"div\";\n\n return (\n <DescriptionPrimitive\n data-slot=\"timeline-description\"\n {...descriptionProps}\n className={cn(\"text-sm text-muted-foreground\", className)}\n />\n );\n}\n\ninterface TimelineTimeProps extends React.ComponentProps<\"time\"> {\n asChild?: boolean;\n}\n\n/** Mốc thời gian — gói KHÔNG tự định dạng ngày: app truyền chuỗi đã định dạng + `dateTime` máy đọc. */\nfunction TimelineTime(props: TimelineTimeProps) {\n const { asChild, className, ...timeProps } = props;\n\n const TimePrimitive = asChild ? Slot : \"time\";\n\n return (\n <TimePrimitive\n data-slot=\"timeline-time\"\n {...timeProps}\n className={cn(\"text-xs text-muted-foreground\", className)}\n />\n );\n}\n\nexport {\n Timeline,\n TimelineConnector,\n type TimelineConnectorProps,\n TimelineContent,\n TimelineDescription,\n TimelineDot,\n TimelineHeader,\n TimelineItem,\n type TimelineProps,\n TimelineTime,\n type TimelineTimeProps,\n TimelineTitle\n};\n"],"mappings":";AAyOQ;AAlOR,SAAS,oBAAoB;AAC7B,SAAS,YAAY;AACrB,SAAS,WAAW;AACpB,YAAY,WAAW;AACvB,SAAS,UAAU;AACnB,SAAS,uBAAuB;AAChC,SAAS,iCAAiC;AAC1C,SAAS,kBAAkB;AAa3B,MAAM,YAAY;AAClB,MAAM,YAAY;AAClB,MAAM,WAAW;AACjB,MAAM,iBAAiB;AACvB,MAAM,eAAe;AAErB,SAAS,cAAc,WAAmB,aAA8B;AAOtE,MAAI,gBAAgB,UAAa,YAAY,EAAG,QAAO;AACvD,MAAI,YAAY,YAAa,QAAO;AACpC,MAAI,cAAc,YAAa,QAAO;AACtC,SAAO;AACT;AAEA,SAAS,iBAAiB,SAA0D;AAClF,SAAO,QAAQ,KAAK,CAAC,GAAG,MAAM;AAC5B,UAAM,WAAW,EAAE,CAAC,EAAE;AACtB,UAAM,WAAW,EAAE,CAAC,EAAE;AACtB,QAAI,CAAC,YAAY,CAAC,SAAU,QAAO;AACnC,UAAM,WAAW,SAAS,wBAAwB,QAAQ;AAC1D,QAAI,WAAW,KAAK,4BAA6B,QAAO;AACxD,QAAI,WAAW,KAAK,4BAA6B,QAAO;AACxD,WAAO;AAAA,EACT,CAAC;AACH;AAEA,SAAS,SAAY,UAAkC;AACrD,QAAM,QAAQ,MAAM,WAAW,YAAY;AAC3C,MAAI,CAAC,OAAO;AACV,UAAM,IAAI,MAAM,sEAA0C,SAAS,IAAI;AAAA,EACzE;AAEA,QAAM,cAAc,MAAM,YAAY,MAAM,SAAS,KAAK,GAAG,CAAC,OAAO,QAAQ,CAAC;AAE9E,SAAO,MAAM,qBAAqB,MAAM,WAAW,aAAa,WAAW;AAC7E;AAgBA,MAAM,eAAe,MAAM,cAA4B,IAAI;AAE3D,SAAS,gBAAgB,cAAsB;AAC7C,QAAM,UAAU,MAAM,WAAW,YAAY;AAC7C,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,KAAK,YAAY,wCAA2B,SAAS,IAAI;AAAA,EAC3E;AACA,SAAO;AACT;AASA,MAAM,kBAAkB,MAAM,cAA2C,IAAI;AAE7E,SAAS,mBAAmB,cAAsB;AAChD,QAAM,UAAU,MAAM,WAAW,eAAe;AAChD,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,KAAK,YAAY,wCAA2B,SAAS,IAAI;AAAA,EAC3E;AACA,SAAO;AACT;AAEA,MAAM,mBAAmB,IAAI,0FAA0F;AAAA,EACrH,UAAU;AAAA,IACR,aAAa;AAAA,MACX,UAAU;AAAA,MACV,YAAY;AAAA,IACd;AAAA,IACA,SAAS;AAAA,MACP,SAAS;AAAA,MACT,WAAW;AAAA,IACb;AAAA,EACF;AAAA,EACA,kBAAkB;AAAA,IAChB;AAAA,MACE,aAAa;AAAA,MACb,SAAS;AAAA,MACT,OAAO;AAAA,IACT;AAAA,IACA;AAAA,MACE,aAAa;AAAA,MACb,SAAS;AAAA,MACT,OAAO;AAAA,IACT;AAAA,IACA;AAAA,MACE,aAAa;AAAA,MACb,SAAS;AAAA,MACT,OAAO;AAAA,IACT;AAAA,IACA;AAAA,MACE,aAAa;AAAA,MACb,SAAS;AAAA,MACT,OAAO;AAAA,IACT;AAAA,EACF;AAAA,EACA,iBAAiB;AAAA,IACf,aAAa;AAAA,IACb,SAAS;AAAA,EACX;AACF,CAAC;AASD,SAAS,SAAS,OAAsB;AACtC,QAAM;AAAA,IACJ,cAAc;AAAA,IACd,UAAU;AAAA,IACV,KAAK;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAG;AAAA,EACL,IAAI;AAEJ,QAAM,MAAM,aAAa,OAAO;AAEhC,QAAM,eAAe,WAAW,MAAM,oBAAI,IAAgB,CAAC;AAC3D,QAAM,WAAW,WAAuB,OAAO;AAAA,IAC7C,OAAO,oBAAI,IAAI;AAAA,EACjB,EAAE;AAEF,QAAM,QAAQ,MAAM,QAAe,MAAM;AACvC,WAAO;AAAA,MACL,WAAW,CAAC,OAAO;AACjB,qBAAa,QAAQ,IAAI,EAAE;AAC3B,eAAO,MAAM,aAAa,QAAQ,OAAO,EAAE;AAAA,MAC7C;AAAA,MACA,UAAU,MAAM,SAAS;AAAA,MACzB,QAAQ,MAAM;AACZ,mBAAW,MAAM,aAAa,SAAS;AACrC,aAAG;AAAA,QACL;AAAA,MACF;AAAA,MACA,gBAAgB,CAAC,IAAY,QAA6C;AACxE,iBAAS,QAAQ,MAAM,IAAI,IAAI,GAAG;AAClC,cAAM,OAAO;AAAA,MACf;AAAA,MACA,kBAAkB,CAAC,OAAe;AAChC,iBAAS,QAAQ,MAAM,OAAO,EAAE;AAChC,cAAM,OAAO;AAAA,MACf;AAAA,MACA,mBAAmB,CAAC,IAAYA,iBAAyB;AACvD,cAAM,UAAU,MAAM,KAAK,SAAS,QAAQ,MAAM,QAAQ,CAAC;AAC3D,cAAM,gBAAgB,iBAAiB,OAAO;AAE9C,cAAM,eAAe,cAAc,UAAU,CAAC,CAAC,GAAG,MAAM,QAAQ,EAAE;AAClE,YAAI,iBAAiB,MAAM,iBAAiB,cAAc,SAAS,GAAG;AACpE,iBAAO;AAAA,QACT;AAEA,cAAM,gBAAgB,eAAe;AACrC,eAAO,cAAc,eAAeA,YAAW;AAAA,MACjD;AAAA,MACA,cAAc,CAAC,OAAe;AAC5B,cAAM,UAAU,MAAM,KAAK,SAAS,QAAQ,MAAM,QAAQ,CAAC;AAC3D,cAAM,gBAAgB,iBAAiB,OAAO;AAC9C,eAAO,cAAc,UAAU,CAAC,CAAC,GAAG,MAAM,QAAQ,EAAE;AAAA,MACtD;AAAA,IACF;AAAA,EACF,GAAG,CAAC,cAAc,QAAQ,CAAC;AAE3B,QAAM,eAAe,MAAM;AAAA,IACzB,OAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,CAAC,KAAK,aAAa,SAAS,WAAW;AAAA,EACzC;AAEA,QAAM,gBAAgB,UAAU,OAAO;AAEvC,SACE,oBAAC,aAAa,UAAb,EAAsB,OAAO,OAC5B,8BAAC,gBAAgB,UAAhB,EAAyB,OAAO,cAK/B;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,aAAU;AAAA,MACV,oBAAkB;AAAA,MAClB,gBAAc;AAAA,MACd;AAAA,MACC,GAAG;AAAA,MACJ,WAAW,GAAG,iBAAiB,EAAE,aAAa,SAAS,UAAU,CAAC,CAAC;AAAA;AAAA,EACrE,GACF,GACF;AAEJ;AAQA,MAAM,sBAAsB,MAAM,cAA+C,IAAI;AAErF,SAAS,uBAAuB,cAAsB;AACpD,QAAM,UAAU,MAAM,WAAW,mBAAmB;AACpD,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,KAAK,YAAY,wCAA2B,SAAS,IAAI;AAAA,EAC3E;AACA,SAAO;AACT;AAEA,MAAM,uBAAuB,IAAI,iBAAiB;AAAA,EAChD,UAAU;AAAA,IACR,aAAa;AAAA,MACX,UAAU;AAAA,MACV,YAAY;AAAA,IACd;AAAA,IACA,SAAS;AAAA,MACP,SAAS;AAAA,MACT,WAAW;AAAA,IACb;AAAA,IACA,kBAAkB;AAAA,MAChB,MAAM;AAAA,MACN,OAAO;AAAA,IACT;AAAA,EACF;AAAA,EACA,kBAAkB;AAAA,IAChB;AAAA,MACE,aAAa;AAAA,MACb,SAAS;AAAA,MACT,OAAO;AAAA,IACT;AAAA,IACA;AAAA,MACE,aAAa;AAAA,MACb,SAAS;AAAA,MACT,OAAO;AAAA,IACT;AAAA,IACA;AAAA,MACE,aAAa;AAAA,MACb,SAAS;AAAA,MACT,kBAAkB;AAAA,MAClB,OAAO;AAAA,IACT;AAAA,IACA;AAAA,MACE,aAAa;AAAA,MACb,SAAS;AAAA,MACT,kBAAkB;AAAA,MAClB,OAAO;AAAA,IACT;AAAA,IACA;AAAA,MACE,aAAa;AAAA,MACb,SAAS;AAAA,MACT,OAAO;AAAA,IACT;AAAA,EACF;AAAA,EACA,iBAAiB;AAAA,IACf,aAAa;AAAA,IACb,SAAS;AAAA,IACT,kBAAkB;AAAA,EACpB;AACF,CAAC;AAED,SAAS,aAAa,OAAiB;AACrC,QAAM,EAAE,SAAS,WAAW,IAAI,KAAK,GAAG,UAAU,IAAI;AAEtD,QAAM,EAAE,KAAK,aAAa,SAAS,YAAY,IAAI,mBAAmB,SAAS;AAC/E,QAAM,QAAQ,gBAAgB,SAAS;AAEvC,QAAM,aAAa,MAAM,MAAM;AAC/B,QAAM,SAAS,MAAM;AACrB,QAAM,UAAU,MAAM,OAA2B,IAAI;AACrD,QAAM,cAAc,gBAAgB,KAAK,OAAO;AAEhD,QAAM,YAAY,SAAS,CAAC,UAAU,MAAM,aAAa,MAAM,CAAC;AAEhE,QAAM,SAAS,MAAM,QAAgB,MAAM;AACzC,WAAO,cAAc,WAAW,WAAW;AAAA,EAC7C,GAAG,CAAC,aAAa,SAAS,CAAC;AAI3B,4BAA0B,MAAM;AAC9B,UAAM,eAAe,QAAQ,OAAO;AACpC,WAAO,MAAM;AACX,YAAM,iBAAiB,MAAM;AAAA,IAC/B;AAAA,EACF,GAAG,CAAC,QAAQ,KAAK,CAAC;AAElB,QAAM,mBAAmB,YAAY,eAAe,YAAY,MAAM;AAEtE,QAAM,mBAAmB,MAAM;AAAA,IAC7B,OAAO,EAAE,IAAI,QAAQ,QAAQ,iBAAiB;AAAA,IAC9C,CAAC,QAAQ,QAAQ,gBAAgB;AAAA,EACnC;AAEA,QAAM,gBAAgB,UAAU,OAAO;AAEvC,SACE,oBAAC,oBAAoB,UAApB,EAA6B,OAAO,kBACnC;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,gBAAc,WAAW,WAAW,SAAS;AAAA,MAC7C,aAAU;AAAA,MACV,eAAa;AAAA,MACb,oBAAkB;AAAA,MAClB,wBAAsB,mBAAmB,KAAK;AAAA,MAC9C,IAAI;AAAA,MACJ;AAAA,MACC,GAAG;AAAA,MACJ,KAAK;AAAA,MACL,WAAW;AAAA,QACT,qBAAqB;AAAA,UACnB;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF,CAAC;AAAA,MACH;AAAA;AAAA,EACF,GACF;AAEJ;AAEA,MAAM,0BAA0B,IAAI,UAAU;AAAA,EAC5C,UAAU;AAAA,IACR,aAAa;AAAA,MACX,UAAU;AAAA,MACV,YAAY;AAAA,IACd;AAAA,IACA,SAAS;AAAA,MACP,SAAS;AAAA,MACT,WAAW;AAAA,IACb;AAAA,IACA,kBAAkB;AAAA,MAChB,MAAM;AAAA,MACN,OAAO;AAAA,IACT;AAAA,EACF;AAAA,EACA,kBAAkB;AAAA,IAChB;AAAA,MACE,SAAS;AAAA,MACT,aAAa;AAAA,MACb,kBAAkB;AAAA,MAClB,OAAO;AAAA,IACT;AAAA,IACA;AAAA,MACE,SAAS;AAAA,MACT,aAAa;AAAA,MACb,kBAAkB;AAAA,MAClB,OAAO;AAAA,IACT;AAAA,IACA;AAAA,MACE,SAAS;AAAA,MACT,aAAa;AAAA,MACb,kBAAkB;AAAA,MAClB,OAAO;AAAA,IACT;AAAA,EACF;AAAA,EACA,iBAAiB;AAAA,IACf,aAAa;AAAA,IACb,SAAS;AAAA,IACT,kBAAkB;AAAA,EACpB;AACF,CAAC;AAED,SAAS,gBAAgB,OAAiB;AACxC,QAAM,EAAE,SAAS,WAAW,GAAG,aAAa,IAAI;AAEhD,QAAM,EAAE,SAAS,YAAY,IAAI,mBAAmB,YAAY;AAChE,QAAM,EAAE,QAAQ,iBAAiB,IAAI,uBAAuB,YAAY;AAExE,QAAM,mBAAmB,UAAU,OAAO;AAE1C,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,eAAa;AAAA,MACZ,GAAG;AAAA,MACJ,WAAW;AAAA,QACT,wBAAwB;AAAA,UACtB;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF,CAAC;AAAA,MACH;AAAA;AAAA,EACF;AAEJ;AAYA,MAAM,sBAAsB;AAAA,EAC1B;AAAA,EACA;AAAA,IACE,UAAU;AAAA,MACR,QAAQ;AAAA,QACN,WAAW;AAAA,QACX,QAAQ;AAAA,QACR,SAAS;AAAA,MACX;AAAA,MACA,aAAa;AAAA,QACX,UAAU;AAAA,QACV,YAAY;AAAA,MACd;AAAA,MACA,SAAS;AAAA,QACP,SAAS;AAAA,QACT,WAAW;AAAA,MACb;AAAA,MACA,kBAAkB;AAAA,QAChB,MAAM;AAAA,QACN,OAAO;AAAA,MACT;AAAA,IACF;AAAA,IACA,kBAAkB;AAAA,MAChB;AAAA,QACE,SAAS;AAAA,QACT,aAAa;AAAA,QACb,kBAAkB;AAAA,QAClB,OAAO;AAAA,MACT;AAAA,MACA;AAAA,QACE,SAAS;AAAA,QACT,aAAa;AAAA,QACb,kBAAkB;AAAA,QAClB,OAAO;AAAA,MACT;AAAA,MACA;AAAA,QACE,SAAS;AAAA,QACT,aAAa;AAAA,QACb,OAAO;AAAA,MACT;AAAA,MACA;AAAA,QACE,SAAS;AAAA,QACT,QAAQ;AAAA,QACR,OAAO;AAAA,MACT;AAAA,MACA;AAAA,QACE,SAAS;AAAA,QACT,QAAQ;AAAA,QACR,OAAO;AAAA,MACT;AAAA,IACF;AAAA,IACA,iBAAiB;AAAA,MACf,QAAQ;AAAA,MACR,aAAa;AAAA,MACb,SAAS;AAAA,MACT,kBAAkB;AAAA,IACpB;AAAA,EACF;AACF;AAEA,SAAS,YAAY,OAAiB;AACpC,QAAM,EAAE,SAAS,WAAW,GAAG,SAAS,IAAI;AAE5C,QAAM,EAAE,aAAa,QAAQ,IAAI,mBAAmB,QAAQ;AAC5D,QAAM,EAAE,QAAQ,iBAAiB,IAAI,uBAAuB,QAAQ;AAEpE,QAAM,eAAe,UAAU,OAAO;AAEtC,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,eAAa;AAAA,MACb,oBAAkB;AAAA,MACjB,GAAG;AAAA,MACJ,WAAW;AAAA,QACT,oBAAoB;AAAA,UAClB;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF,CAAC;AAAA,MACH;AAAA;AAAA,EACF;AAEJ;AAMA,MAAM,4BAA4B,IAAI,gBAAgB;AAAA,EACpD,UAAU;AAAA,IACR,aAAa;AAAA,MACX,MAAM;AAAA,MACN,OAAO;AAAA,IACT;AAAA,IACA,aAAa;AAAA,MACX,UAAU;AAAA,MACV,YAAY;AAAA,IACd;AAAA,IACA,SAAS;AAAA,MACP,SAAS;AAAA,MACT,WAAW;AAAA,IACb;AAAA,IACA,kBAAkB;AAAA,MAChB,MAAM;AAAA,MACN,OAAO;AAAA,IACT;AAAA,EACF;AAAA,EACA,kBAAkB;AAAA,IAChB;AAAA,MACE,aAAa;AAAA,MACb,SAAS;AAAA,MACT,OACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,aAAa;AAAA,MACb,SAAS;AAAA,MACT,OACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,aAAa;AAAA,MACb,SAAS;AAAA,MACT,kBAAkB;AAAA,MAClB,OAAO;AAAA,IACT;AAAA,IACA;AAAA,MACE,aAAa;AAAA,MACb,SAAS;AAAA,MACT,kBAAkB;AAAA,MAClB,OAAO;AAAA,IACT;AAAA,IACA;AAAA,MACE,aAAa;AAAA,MACb,SAAS;AAAA,MACT,OACE;AAAA,IACJ;AAAA,EACF;AAAA,EACA,iBAAiB;AAAA,IACf,aAAa;AAAA,IACb,aAAa;AAAA,IACb,SAAS;AAAA,IACT,kBAAkB;AAAA,EACpB;AACF,CAAC;AAMD,SAAS,kBAAkB,OAA+B;AACxD,QAAM,EAAE,SAAS,YAAY,WAAW,GAAG,eAAe,IAAI;AAE9D,QAAM,EAAE,aAAa,SAAS,YAAY,IAAI,mBAAmB,cAAc;AAC/E,QAAM,EAAE,IAAI,QAAQ,iBAAiB,IAAI,uBAAuB,cAAc;AAE9E,QAAM,iBAAiB,SAAS,CAAC,UAAU,MAAM,kBAAkB,IAAI,WAAW,CAAC;AAEnF,QAAM,aAAa,mBAAmB;AAEtC,MAAI,CAAC,cAAc,WAAY,QAAO;AAEtC,QAAM,uBAAuB,mBAAmB,eAAe,mBAAmB;AAElF,QAAM,qBAAqB,UAAU,OAAO;AAE5C,SACE;AAAA,IAAC;AAAA;AAAA,MACC,eAAY;AAAA,MACZ,aAAU;AAAA,MACV,kBAAgB,uBAAuB,KAAK;AAAA,MAC5C,eAAa;AAAA,MACb,oBAAkB;AAAA,MACjB,GAAG;AAAA,MACJ,WAAW;AAAA,QACT,0BAA0B;AAAA,UACxB,aAAa;AAAA,UACb;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF,CAAC;AAAA,MACH;AAAA;AAAA,EACF;AAEJ;AAEA,SAAS,eAAe,OAAiB;AACvC,QAAM,EAAE,SAAS,WAAW,GAAG,YAAY,IAAI;AAE/C,QAAM,kBAAkB,UAAU,OAAO;AAEzC,SACE,oBAAC,mBAAgB,aAAU,mBAAmB,GAAG,aAAa,WAAW,GAAG,uBAAuB,SAAS,GAAG;AAEnH;AAEA,SAAS,cAAc,OAAiB;AACtC,QAAM,EAAE,SAAS,WAAW,GAAG,WAAW,IAAI;AAE9C,QAAM,iBAAiB,UAAU,OAAO;AAExC,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACT,GAAG;AAAA,MACJ,WAAW,GAAG,8BAA8B,SAAS;AAAA;AAAA,EACvD;AAEJ;AAEA,SAAS,oBAAoB,OAAiB;AAC5C,QAAM,EAAE,SAAS,WAAW,GAAG,iBAAiB,IAAI;AAEpD,QAAM,uBAAuB,UAAU,OAAO;AAE9C,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACT,GAAG;AAAA,MACJ,WAAW,GAAG,iCAAiC,SAAS;AAAA;AAAA,EAC1D;AAEJ;AAOA,SAAS,aAAa,OAA0B;AAC9C,QAAM,EAAE,SAAS,WAAW,GAAG,UAAU,IAAI;AAE7C,QAAM,gBAAgB,UAAU,OAAO;AAEvC,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACT,GAAG;AAAA,MACJ,WAAW,GAAG,iCAAiC,SAAS;AAAA;AAAA,EAC1D;AAEJ;","names":["activeIndex"]}
1
+ {"version":3,"sources":["../../../src/components/ui/timeline.tsx"],"sourcesContent":["\"use client\";\n\n/*\n * Port từ Dice UI (https://diceui.com/docs/components/timeline) — MIT, © 2024 Sadman Sakib.\n * Giữ nguyên cấu trúc thượng nguồn để còn đối chiếu ngược được; mọi chỗ đổi đều có chú thích.\n */\n\nimport { useDirection } from \"@radix-ui/react-direction\";\nimport { Slot } from \"@radix-ui/react-slot\";\nimport { cva } from \"class-variance-authority\";\nimport * as React from \"react\";\nimport { cn } from \"../../lib/cn.js\";\nimport { collectItemElements } from \"../../lib/collect-item-elements.js\";\nimport { useComposedRefs } from \"../../lib/compose-refs.js\";\nimport { useIsomorphicLayoutEffect } from \"../../lib/use-isomorphic-layout-effect.js\";\nimport { useLazyRef } from \"../../lib/use-lazy-ref.js\";\n\ntype Direction = \"ltr\" | \"rtl\";\ntype Orientation = \"vertical\" | \"horizontal\";\ntype Variant = \"default\" | \"alternate\";\ntype Status = \"completed\" | \"active\" | \"pending\";\n\ninterface DivProps extends React.ComponentProps<\"div\"> {\n asChild?: boolean;\n}\n\ntype ItemElement = React.ComponentRef<typeof TimelineItem>;\n\nconst ROOT_NAME = \"Timeline\";\nconst ITEM_NAME = \"TimelineItem\";\nconst DOT_NAME = \"TimelineDot\";\nconst CONNECTOR_NAME = \"TimelineConnector\";\nconst CONTENT_NAME = \"TimelineContent\";\n\nfunction getItemStatus(itemIndex: number, activeIndex?: number): Status {\n /*\n * ⚠ Khác thượng nguồn: mục đăng ký chỉ số của mình trong layout effect, nên ở lượt render phía\n * server (và lượt đầu trước hydrate) MỌI mục đều mang chỉ số -1. Bản gốc so thẳng `-1 < activeIndex`\n * → mọi chấm cùng ra \"completed\" (tô gold) cho tới khi hydrate xong — một trạng thái SAI, không\n * chỉ là thiếu. Chưa biết vị trí thì coi là \"pending\": trung tính, và đúng với phần lớn mục.\n * Từ 3.1.0 các lượt đó đọc vị trí từ cây phần tử (`getItemsFromChildren`); -1 chỉ còn khi đọc\n * không được — mục nằm trong component của app — và nhánh này vẫn giữ nó ở \"pending\".\n */\n if (activeIndex === undefined || itemIndex < 0) return \"pending\";\n if (itemIndex < activeIndex) return \"completed\";\n if (itemIndex === activeIndex) return \"active\";\n return \"pending\";\n}\n\nfunction getSortedEntries(entries: [string, React.RefObject<ItemElement | null>][]) {\n return entries.sort((a, b) => {\n const elementA = a[1].current;\n const elementB = b[1].current;\n if (!elementA || !elementB) return 0;\n const position = elementA.compareDocumentPosition(elementB);\n if (position & Node.DOCUMENT_POSITION_FOLLOWING) return -1;\n if (position & Node.DOCUMENT_POSITION_PRECEDING) return 1;\n return 0;\n });\n}\n\n/*\n * ⚠ Khác thượng nguồn (3.1.0): vị trí các mục ĐỌC TỪ CÂY PHẦN TỬ của `Timeline`, theo thứ tự tài\n * liệu — `TimelineItem` viết trong gốc qua mảng, fragment, thẻ HTML (luật ở `collectItemElements`).\n * Mục không có `value`, nên vị trí khoá bằng CHÍNH object props của phần tử: React đưa đúng object\n * đó cho `TimelineItem` khi render nó — ở server cũng như ở trình duyệt. Mục do component của app\n * render thì không có trong bảng, nên không có vị trí (-1). `WeakMap` để không giữ props của lượt\n * đầu sống mãi.\n */\ninterface InitialItems {\n indexes: WeakMap<object, number>;\n count: number;\n}\n\nfunction getItemsFromChildren(children: React.ReactNode): InitialItems {\n const indexes = new WeakMap<object, number>();\n const items = collectItemElements(children, { item: TimelineItem }) ?? [];\n for (const [index, { props }] of items.entries()) {\n // Cùng MỘT phần tử đặt hai lần thì hai mục chung một object props — không phân biệt được.\n if (indexes.has(props)) return { indexes: new WeakMap(), count: 0 };\n indexes.set(props, index);\n }\n return { indexes, count: items.length };\n}\n\n/*\n * ⚠ Khác thượng nguồn (3.1.0): `initialSelector` là giá trị đọc từ cây phần tử (xem `Timeline`).\n * Nó là snapshot SERVER — React dùng ở server và ở lượt hydrate, nên hai bên ra cùng một HTML — và\n * là snapshot client cho tới layout effect đầu của gốc. Bản gốc dùng `selector` cho mọi lượt.\n */\nfunction useStore<T>(selector: (store: Store) => T, initialSelector: (store: Store) => T): T {\n const store = React.useContext(StoreContext);\n if (!store) {\n throw new Error(`\\`useStore\\` phải được gọi bên trong \\`${ROOT_NAME}\\``);\n }\n\n const getSnapshot = React.useCallback(\n () => (store.hasRegistered() ? selector(store) : initialSelector(store)),\n [store, selector, initialSelector]\n );\n const getServerSnapshot = React.useCallback(() => initialSelector(store), [store, initialSelector]);\n\n return React.useSyncExternalStore(store.subscribe, getSnapshot, getServerSnapshot);\n}\n\ninterface StoreState {\n items: Map<string, React.RefObject<ItemElement | null>>;\n}\n\ninterface Store {\n subscribe: (callback: () => void) => () => void;\n getState: () => StoreState;\n notify: () => void;\n onItemRegister: (id: string, ref: React.RefObject<ItemElement | null>) => void;\n onItemUnregister: (id: string) => void;\n getNextItemStatus: (id: string, activeIndex?: number) => Status | undefined;\n getItemIndex: (id: string) => number;\n hasRegistered: () => boolean;\n getInitialItemIndex: (itemProps: object) => number;\n getInitialNextItemStatus: (initialIndex: number, activeIndex?: number) => Status | undefined;\n}\n\nconst StoreContext = React.createContext<Store | null>(null);\n\nfunction useStoreContext(consumerName: string) {\n const context = React.useContext(StoreContext);\n if (!context) {\n throw new Error(`\\`${consumerName}\\` phải nằm bên trong \\`${ROOT_NAME}\\``);\n }\n return context;\n}\n\ninterface TimelineContextValue {\n dir: Direction;\n orientation: Orientation;\n variant: Variant;\n activeIndex?: number;\n}\n\nconst TimelineContext = React.createContext<TimelineContextValue | null>(null);\n\nfunction useTimelineContext(consumerName: string) {\n const context = React.useContext(TimelineContext);\n if (!context) {\n throw new Error(`\\`${consumerName}\\` phải nằm bên trong \\`${ROOT_NAME}\\``);\n }\n return context;\n}\n\nconst timelineVariants = cva(\"relative flex [--timeline-connector-thickness:0.125rem] [--timeline-dot-size:0.875rem]\", {\n variants: {\n orientation: {\n vertical: \"flex-col\",\n horizontal: \"flex-row items-start\"\n },\n variant: {\n default: \"\",\n alternate: \"\"\n }\n },\n compoundVariants: [\n {\n orientation: \"vertical\",\n variant: \"default\",\n class: \"gap-6\"\n },\n {\n orientation: \"horizontal\",\n variant: \"default\",\n class: \"gap-8\"\n },\n {\n orientation: \"vertical\",\n variant: \"alternate\",\n class: \"relative w-full gap-3\"\n },\n {\n orientation: \"horizontal\",\n variant: \"alternate\",\n class: \"items-center gap-4\"\n }\n ],\n defaultVariants: {\n orientation: \"vertical\",\n variant: \"default\"\n }\n});\n\ninterface TimelineProps extends DivProps {\n dir?: Direction;\n orientation?: Orientation;\n variant?: Variant;\n activeIndex?: number;\n}\n\nfunction Timeline(props: TimelineProps) {\n const {\n orientation = \"vertical\",\n variant = \"default\",\n dir: dirProp,\n activeIndex,\n asChild,\n className,\n ...rootProps\n } = props;\n\n const dir = useDirection(dirProp);\n\n const listenersRef = useLazyRef(() => new Set<() => void>());\n const stateRef = useLazyRef<StoreState>(() => ({\n items: new Map()\n }));\n /*\n * ⚠ Khác thượng nguồn (3.1.0): vị trí cho mọi lượt render TRƯỚC khi các mục đăng ký. Bản gốc chỉ\n * biết vị trí qua đăng ký trong layout effect, nên HTML server — và khung hình đầu, cả lúc hydrate\n * lẫn lúc mount thuần client — có mọi mục \"pending\", KHÔNG vạch nối nào, và ở `variant=\"alternate\"`\n * mọi mục dồn một bên; mount xong mới tự đúng, thành một khung nháy (kèm bố cục nhảy).\n * - Chụp MỘT lần, ở lượt render đầu, và không bao giờ sửa: nó là snapshot SERVER của `useStore`,\n * nên phải đúng là cái server đã render — kể cả cho phần hydrate muộn hơn gốc.\n * - Chỉ có hiệu lực tới layout effect đầu của gốc (`registeredRef`). Effect của con chạy trước của\n * cha, nên lúc đó mọi mục đọc được đã đăng ký, và thứ tự DOM của chúng chính là thứ tự đọc được —\n * đổi nguồn không đổi gì trên màn hình. Từ đó thứ tự DOM của các mục đã đăng ký thắng như cũ.\n * - Đọc không được (mục nằm trong component của app, hay cây viết thẳng trong Server Component) thì\n * không mục nào có vị trí — y như trước bản này (xem `getItemStatus`).\n */\n const initialItemsRef = useLazyRef(() => getItemsFromChildren(props.children));\n const registeredRef = React.useRef(false);\n\n const store = React.useMemo<Store>(() => {\n return {\n subscribe: (cb) => {\n listenersRef.current.add(cb);\n return () => listenersRef.current.delete(cb);\n },\n getState: () => stateRef.current,\n notify: () => {\n for (const cb of listenersRef.current) {\n cb();\n }\n },\n onItemRegister: (id: string, ref: React.RefObject<ItemElement | null>) => {\n stateRef.current.items.set(id, ref);\n store.notify();\n },\n onItemUnregister: (id: string) => {\n stateRef.current.items.delete(id);\n store.notify();\n },\n getNextItemStatus: (id: string, activeIndex?: number) => {\n const entries = Array.from(stateRef.current.items.entries());\n const sortedEntries = getSortedEntries(entries);\n\n const currentIndex = sortedEntries.findIndex(([key]) => key === id);\n if (currentIndex === -1 || currentIndex === sortedEntries.length - 1) {\n return undefined;\n }\n\n const nextItemIndex = currentIndex + 1;\n return getItemStatus(nextItemIndex, activeIndex);\n },\n getItemIndex: (id: string) => {\n const entries = Array.from(stateRef.current.items.entries());\n const sortedEntries = getSortedEntries(entries);\n return sortedEntries.findIndex(([key]) => key === id);\n },\n hasRegistered: () => registeredRef.current,\n getInitialItemIndex: (itemProps: object) => initialItemsRef.current.indexes.get(itemProps) ?? -1,\n // Cùng luật với `getNextItemStatus`, trên vị trí đọc từ cây.\n getInitialNextItemStatus: (initialIndex: number, activeIndex?: number) => {\n if (initialIndex === -1 || initialIndex === initialItemsRef.current.count - 1) {\n return undefined;\n }\n return getItemStatus(initialIndex + 1, activeIndex);\n }\n };\n }, [listenersRef, stateRef, initialItemsRef]);\n\n // ⚠ Khác thượng nguồn (3.1.0): từ đây vị trí ĐĂNG KÝ là nguồn sự thật — xem `initialItemsRef`.\n useIsomorphicLayoutEffect(() => {\n registeredRef.current = true;\n store.notify();\n }, [store]);\n\n const contextValue = React.useMemo<TimelineContextValue>(\n () => ({\n dir,\n orientation,\n variant,\n activeIndex\n }),\n [dir, orientation, variant, activeIndex]\n );\n\n const RootPrimitive = asChild ? Slot : \"div\";\n\n return (\n <StoreContext.Provider value={store}>\n <TimelineContext.Provider value={contextValue}>\n {/*\n * ⚠ Khác thượng nguồn: bỏ `aria-orientation` khỏi thẻ gốc. `role=\"list\"` không nhận thuộc\n * tính đó theo ARIA 1.2 (axe báo `aria-allowed-attr`); hướng vẫn có ở `data-orientation`.\n */}\n <RootPrimitive\n role=\"list\"\n data-slot=\"timeline\"\n data-orientation={orientation}\n data-variant={variant}\n dir={dir}\n {...rootProps}\n className={cn(timelineVariants({ orientation, variant, className }))}\n />\n </TimelineContext.Provider>\n </StoreContext.Provider>\n );\n}\n\ninterface TimelineItemContextValue {\n id: string;\n status: Status;\n isAlternateRight: boolean;\n /** Vị trí đọc từ cây phần tử (-1 nếu không đọc được) — cho snapshot server của `TimelineConnector`. */\n initialIndex: number;\n}\n\nconst TimelineItemContext = React.createContext<TimelineItemContextValue | null>(null);\n\nfunction useTimelineItemContext(consumerName: string) {\n const context = React.useContext(TimelineItemContext);\n if (!context) {\n throw new Error(`\\`${consumerName}\\` phải nằm bên trong \\`${ITEM_NAME}\\``);\n }\n return context;\n}\n\nconst timelineItemVariants = cva(\"relative flex\", {\n variants: {\n orientation: {\n vertical: \"\",\n horizontal: \"\"\n },\n variant: {\n default: \"\",\n alternate: \"\"\n },\n isAlternateRight: {\n true: \"\",\n false: \"\"\n }\n },\n compoundVariants: [\n {\n orientation: \"vertical\",\n variant: \"default\",\n class: \"gap-3 pb-8 last:pb-0\"\n },\n {\n orientation: \"horizontal\",\n variant: \"default\",\n class: \"flex-col gap-3\"\n },\n {\n orientation: \"vertical\",\n variant: \"alternate\",\n isAlternateRight: false,\n class: \"w-1/2 gap-3 pr-6 pb-12 last:pb-0\"\n },\n {\n orientation: \"vertical\",\n variant: \"alternate\",\n isAlternateRight: true,\n class: \"ml-auto w-1/2 flex-row-reverse gap-3 pb-12 pl-6 last:pb-0\"\n },\n {\n orientation: \"horizontal\",\n variant: \"alternate\",\n class: \"grid min-w-0 grid-rows-[1fr_auto_1fr] gap-3\"\n }\n ],\n defaultVariants: {\n orientation: \"vertical\",\n variant: \"default\",\n isAlternateRight: false\n }\n});\n\nfunction TimelineItem(props: DivProps) {\n const { asChild, className, id, ref, ...itemProps } = props;\n\n const { dir, orientation, variant, activeIndex } = useTimelineContext(ITEM_NAME);\n const store = useStoreContext(ITEM_NAME);\n\n const instanceId = React.useId();\n const itemId = id ?? instanceId;\n const itemRef = React.useRef<ItemElement | null>(null);\n const composedRef = useComposedRefs(ref, itemRef);\n\n // ⚠ Khác thượng nguồn (3.1.0): trước khi đăng ký, vị trí là vị trí đọc từ cây phần tử của gốc —\n // tra bằng chính object `props` này (xem `getItemsFromChildren`).\n const initialIndex = store.getInitialItemIndex(props);\n const itemIndex = useStore(\n (state) => state.getItemIndex(itemId),\n () => initialIndex\n );\n\n const status = React.useMemo<Status>(() => {\n return getItemStatus(itemIndex, activeIndex);\n }, [activeIndex, itemIndex]);\n\n // ⚠ Khác thượng nguồn: phụ thuộc là `itemId` (thứ thật sự được dùng) thay cho `id` — cùng\n // nghĩa, vì `itemId = id ?? instanceId` và `instanceId` không đổi suốt vòng đời.\n useIsomorphicLayoutEffect(() => {\n store.onItemRegister(itemId, itemRef);\n return () => {\n store.onItemUnregister(itemId);\n };\n }, [itemId, store]);\n\n const isAlternateRight = variant === \"alternate\" && itemIndex % 2 === 1;\n\n const itemContextValue = React.useMemo<TimelineItemContextValue>(\n () => ({ id: itemId, status, isAlternateRight, initialIndex }),\n [itemId, status, isAlternateRight, initialIndex]\n );\n\n const ItemPrimitive = asChild ? Slot : \"div\";\n\n return (\n <TimelineItemContext.Provider value={itemContextValue}>\n <ItemPrimitive\n role=\"listitem\"\n aria-current={status === \"active\" ? \"step\" : undefined}\n data-slot=\"timeline-item\"\n data-status={status}\n data-orientation={orientation}\n data-alternate-right={isAlternateRight ? \"\" : undefined}\n id={itemId}\n dir={dir}\n {...itemProps}\n ref={composedRef}\n className={cn(\n timelineItemVariants({\n orientation,\n variant,\n isAlternateRight,\n className\n })\n )}\n />\n </TimelineItemContext.Provider>\n );\n}\n\nconst timelineContentVariants = cva(\"flex-1\", {\n variants: {\n orientation: {\n vertical: \"\",\n horizontal: \"\"\n },\n variant: {\n default: \"\",\n alternate: \"\"\n },\n isAlternateRight: {\n true: \"\",\n false: \"\"\n }\n },\n compoundVariants: [\n {\n variant: \"alternate\",\n orientation: \"vertical\",\n isAlternateRight: false,\n class: \"text-right\"\n },\n {\n variant: \"alternate\",\n orientation: \"horizontal\",\n isAlternateRight: false,\n class: \"row-start-3 pt-2\"\n },\n {\n variant: \"alternate\",\n orientation: \"horizontal\",\n isAlternateRight: true,\n class: \"row-start-1 pb-2\"\n }\n ],\n defaultVariants: {\n orientation: \"vertical\",\n variant: \"default\",\n isAlternateRight: false\n }\n});\n\nfunction TimelineContent(props: DivProps) {\n const { asChild, className, ...contentProps } = props;\n\n const { variant, orientation } = useTimelineContext(CONTENT_NAME);\n const { status, isAlternateRight } = useTimelineItemContext(CONTENT_NAME);\n\n const ContentPrimitive = asChild ? Slot : \"div\";\n\n return (\n <ContentPrimitive\n data-slot=\"timeline-content\"\n data-status={status}\n {...contentProps}\n className={cn(\n timelineContentVariants({\n orientation,\n variant,\n isAlternateRight,\n className\n })\n )}\n />\n );\n}\n\n/*\n * ⚠ Khác thượng nguồn — màu chấm đi qua token VAI TRÒ (docs/hop-dong-mau.md §1):\n * chấm là thành phần PHI VĂN BẢN mang nghĩa (đánh dấu từng mốc và trạng thái của nó) → viền chịu\n * 3:1 với nền trang.\n * - đã xong / đang diễn ra: `border-primary-ink` thay `border-primary` (token TÔ NỀN, ~1,86:1 với\n * nền trang; bậc ink đạt 6,51:1 light · 12,67:1 dark ở bảng tương phản cao).\n * - chờ: `border-muted-foreground` thay `border-border` (bậc TRANG TRÍ 1,16:1, và cổng bắt viền trang\n * trí khi phần tử có bo góc + cỡ cố định). Cùng lựa chọn với tone `neutral` của `StatusPill`\n * (`STATUS_TONES.neutral.borderColor`): 5,23:1 light · 5,70:1 dark.\n */\nconst timelineDotVariants = cva(\n \"relative z-10 flex size-[var(--timeline-dot-size)] shrink-0 items-center justify-center rounded-full border-2 bg-background\",\n {\n variants: {\n status: {\n completed: \"border-primary-ink\",\n active: \"border-primary-ink\",\n pending: \"border-muted-foreground\"\n },\n orientation: {\n vertical: \"\",\n horizontal: \"\"\n },\n variant: {\n default: \"\",\n alternate: \"\"\n },\n isAlternateRight: {\n true: \"\",\n false: \"\"\n }\n },\n compoundVariants: [\n {\n variant: \"alternate\",\n orientation: \"vertical\",\n isAlternateRight: false,\n class: \"absolute -right-[calc(var(--timeline-dot-size)/2-var(--timeline-connector-thickness)/2)] bg-background\"\n },\n {\n variant: \"alternate\",\n orientation: \"vertical\",\n isAlternateRight: true,\n class: \"absolute -left-[calc(var(--timeline-dot-size)/2-var(--timeline-connector-thickness)/2)] bg-background\"\n },\n {\n variant: \"alternate\",\n orientation: \"horizontal\",\n class: \"row-start-2 bg-background\"\n },\n {\n variant: \"alternate\",\n status: \"completed\",\n class: \"bg-background\"\n },\n {\n variant: \"alternate\",\n status: \"active\",\n class: \"bg-background\"\n }\n ],\n defaultVariants: {\n status: \"pending\",\n orientation: \"vertical\",\n variant: \"default\",\n isAlternateRight: false\n }\n }\n);\n\nfunction TimelineDot(props: DivProps) {\n const { asChild, className, ...dotProps } = props;\n\n const { orientation, variant } = useTimelineContext(DOT_NAME);\n const { status, isAlternateRight } = useTimelineItemContext(DOT_NAME);\n\n const DotPrimitive = asChild ? Slot : \"div\";\n\n return (\n <DotPrimitive\n data-slot=\"timeline-dot\"\n data-status={status}\n data-orientation={orientation}\n {...dotProps}\n className={cn(\n timelineDotVariants({\n status,\n orientation,\n variant,\n isAlternateRight,\n className\n })\n )}\n />\n );\n}\n\n/*\n * ⚠ Khác thượng nguồn: đoạn nối ĐÃ XONG mang nghĩa tiến độ → `bg-primary-ink` thay `bg-primary`\n * (token tô nền, ~1,86:1 với nền trang). Đoạn chưa tới giữ `bg-border` — đường kẻ trang trí.\n */\nconst timelineConnectorVariants = cva(\"absolute z-0\", {\n variants: {\n isCompleted: {\n true: \"bg-primary-ink\",\n false: \"bg-border\"\n },\n orientation: {\n vertical: \"\",\n horizontal: \"\"\n },\n variant: {\n default: \"\",\n alternate: \"\"\n },\n isAlternateRight: {\n true: \"\",\n false: \"\"\n }\n },\n compoundVariants: [\n {\n orientation: \"vertical\",\n variant: \"default\",\n class:\n \"start-[calc(var(--timeline-dot-size)/2-var(--timeline-connector-thickness)/2)] top-3 h-[calc(100%+0.5rem)] w-[var(--timeline-connector-thickness)]\"\n },\n {\n orientation: \"horizontal\",\n variant: \"default\",\n class:\n \"start-3 top-[calc(var(--timeline-dot-size)/2-var(--timeline-connector-thickness)/2)] h-[var(--timeline-connector-thickness)] w-[calc(100%+0.5rem)]\"\n },\n {\n orientation: \"vertical\",\n variant: \"alternate\",\n isAlternateRight: false,\n class: \"top-2 -right-[calc(var(--timeline-connector-thickness)/2)] h-full w-[var(--timeline-connector-thickness)]\"\n },\n {\n orientation: \"vertical\",\n variant: \"alternate\",\n isAlternateRight: true,\n class: \"top-2 -left-[calc(var(--timeline-connector-thickness)/2)] h-full w-[var(--timeline-connector-thickness)]\"\n },\n {\n orientation: \"horizontal\",\n variant: \"alternate\",\n class:\n \"top-[calc(var(--timeline-dot-size)/2-var(--timeline-connector-thickness)/2)] left-3 row-start-2 h-[var(--timeline-connector-thickness)] w-[calc(100%+0.5rem)]\"\n }\n ],\n defaultVariants: {\n isCompleted: false,\n orientation: \"vertical\",\n variant: \"default\",\n isAlternateRight: false\n }\n});\n\ninterface TimelineConnectorProps extends DivProps {\n forceMount?: boolean;\n}\n\nfunction TimelineConnector(props: TimelineConnectorProps) {\n const { asChild, forceMount, className, ...connectorProps } = props;\n\n const { orientation, variant, activeIndex } = useTimelineContext(CONNECTOR_NAME);\n const { id, status, isAlternateRight, initialIndex } = useTimelineItemContext(CONNECTOR_NAME);\n\n const nextItemStatus = useStore(\n (state) => state.getNextItemStatus(id, activeIndex),\n (state) => state.getInitialNextItemStatus(initialIndex, activeIndex)\n );\n\n const isLastItem = nextItemStatus === undefined;\n\n if (!forceMount && isLastItem) return null;\n\n const isConnectorCompleted = nextItemStatus === \"completed\" || nextItemStatus === \"active\";\n\n const ConnectorPrimitive = asChild ? Slot : \"div\";\n\n return (\n <ConnectorPrimitive\n aria-hidden=\"true\"\n data-slot=\"timeline-connector\"\n data-completed={isConnectorCompleted ? \"\" : undefined}\n data-status={status}\n data-orientation={orientation}\n {...connectorProps}\n className={cn(\n timelineConnectorVariants({\n isCompleted: isConnectorCompleted,\n orientation,\n variant,\n isAlternateRight,\n className\n })\n )}\n />\n );\n}\n\nfunction TimelineHeader(props: DivProps) {\n const { asChild, className, ...headerProps } = props;\n\n const HeaderPrimitive = asChild ? Slot : \"div\";\n\n return (\n <HeaderPrimitive data-slot=\"timeline-header\" {...headerProps} className={cn(\"flex flex-col gap-1\", className)} />\n );\n}\n\nfunction TimelineTitle(props: DivProps) {\n const { asChild, className, ...titleProps } = props;\n\n const TitlePrimitive = asChild ? Slot : \"div\";\n\n return (\n <TitlePrimitive\n data-slot=\"timeline-title\"\n {...titleProps}\n className={cn(\"leading-none font-semibold\", className)}\n />\n );\n}\n\nfunction TimelineDescription(props: DivProps) {\n const { asChild, className, ...descriptionProps } = props;\n\n const DescriptionPrimitive = asChild ? Slot : \"div\";\n\n return (\n <DescriptionPrimitive\n data-slot=\"timeline-description\"\n {...descriptionProps}\n className={cn(\"text-sm text-muted-foreground\", className)}\n />\n );\n}\n\ninterface TimelineTimeProps extends React.ComponentProps<\"time\"> {\n asChild?: boolean;\n}\n\n/** Mốc thời gian — gói KHÔNG tự định dạng ngày: app truyền chuỗi đã định dạng + `dateTime` máy đọc. */\nfunction TimelineTime(props: TimelineTimeProps) {\n const { asChild, className, ...timeProps } = props;\n\n const TimePrimitive = asChild ? Slot : \"time\";\n\n return (\n <TimePrimitive\n data-slot=\"timeline-time\"\n {...timeProps}\n className={cn(\"text-xs text-muted-foreground\", className)}\n />\n );\n}\n\nexport {\n Timeline,\n TimelineConnector,\n type TimelineConnectorProps,\n TimelineContent,\n TimelineDescription,\n TimelineDot,\n TimelineHeader,\n TimelineItem,\n type TimelineProps,\n TimelineTime,\n type TimelineTimeProps,\n TimelineTitle\n};\n"],"mappings":"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","names":["activeIndex"]}
@@ -105,7 +105,7 @@ function ShortTextCell({
105
105
  setValue(initialValue);
106
106
  cellRef.current?.blur();
107
107
  }
108
- } else if (isFocused && event.key.length === 1 && !event.ctrlKey && !event.metaKey) {
108
+ } else if (isFocused && !readOnly && event.key.length === 1 && !event.ctrlKey && !event.metaKey) {
109
109
  setValue(event.key);
110
110
  queueMicrotask(() => {
111
111
  if (cellRef.current && cellRef.current.contentEditable === "true") {
@@ -120,7 +120,7 @@ function ShortTextCell({
120
120
  });
121
121
  }
122
122
  },
123
- [isEditing, isFocused, initialValue, tableMeta, rowIndex, columnId]
123
+ [isEditing, isFocused, readOnly, initialValue, tableMeta, rowIndex, columnId]
124
124
  );
125
125
  React.useEffect(() => {
126
126
  const wasEditing = prevIsEditingRef.current;
@@ -405,7 +405,7 @@ function NumberCell({
405
405
  setValue(String(initialValue ?? ""));
406
406
  inputRef.current?.blur();
407
407
  }
408
- } else if (isFocused) {
408
+ } else if (isFocused && !readOnly) {
409
409
  if (event.key === "Backspace") {
410
410
  setValue("");
411
411
  } else if (event.key.length === 1 && !event.ctrlKey && !event.metaKey) {
@@ -413,7 +413,7 @@ function NumberCell({
413
413
  }
414
414
  }
415
415
  },
416
- [isEditing, isFocused, initialValue, tableMeta, rowIndex, columnId, value]
416
+ [isEditing, isFocused, readOnly, initialValue, tableMeta, rowIndex, columnId, value]
417
417
  );
418
418
  React.useEffect(() => {
419
419
  const wasEditing = prevIsEditingRef.current;