@comitor/ui 3.0.0 → 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.
- package/README.md +5 -1
- package/dist/components/composite/confirm-dialog.js +56 -35
- package/dist/components/composite/confirm-dialog.js.map +1 -1
- package/dist/components/composite/search-filter-bar-constants.d.ts +3 -0
- package/dist/components/composite/search-filter-bar-constants.js.map +1 -1
- package/dist/components/composite/table-pagination-constants.d.ts +3 -1
- package/dist/components/composite/table-pagination-constants.js.map +1 -1
- package/dist/components/composite/table-pagination.js +10 -2
- package/dist/components/composite/table-pagination.js.map +1 -1
- package/dist/components/composite/text-utils.d.ts +4 -23
- package/dist/components/composite/text-utils.js +1 -11
- package/dist/components/composite/text-utils.js.map +1 -1
- package/dist/components/composite/toast.d.ts +2 -1
- package/dist/components/composite/toast.js +3 -9
- package/dist/components/composite/toast.js.map +1 -1
- package/dist/components/ui/action-bar.js +45 -1
- package/dist/components/ui/action-bar.js.map +1 -1
- package/dist/components/ui/banner.d.ts +8 -0
- package/dist/components/ui/banner.js +149 -35
- package/dist/components/ui/banner.js.map +1 -1
- package/dist/components/ui/circular-progress.js +10 -2
- package/dist/components/ui/circular-progress.js.map +1 -1
- package/dist/components/ui/kanban.js +9 -3
- package/dist/components/ui/kanban.js.map +1 -1
- package/dist/components/ui/key-value.js +70 -76
- package/dist/components/ui/key-value.js.map +1 -1
- package/dist/components/ui/mask-input-constants.d.ts +34 -2
- package/dist/components/ui/mask-input-constants.js +87 -76
- package/dist/components/ui/mask-input-constants.js.map +1 -1
- package/dist/components/ui/mask-input.d.ts +6 -5
- package/dist/components/ui/mask-input.js +23 -21
- package/dist/components/ui/mask-input.js.map +1 -1
- package/dist/components/ui/mention.d.ts +14 -2
- package/dist/components/ui/mention.js +33 -6
- package/dist/components/ui/mention.js.map +1 -1
- package/dist/components/ui/phone-input.d.ts +18 -8
- package/dist/components/ui/phone-input.js +125 -35
- package/dist/components/ui/phone-input.js.map +1 -1
- package/dist/components/ui/rating.js +4 -2
- package/dist/components/ui/rating.js.map +1 -1
- package/dist/components/ui/scroll-spy.js +46 -31
- package/dist/components/ui/scroll-spy.js.map +1 -1
- package/dist/components/ui/slider.d.ts +1 -1
- package/dist/components/ui/slider.js +15 -1
- package/dist/components/ui/slider.js.map +1 -1
- package/dist/components/ui/sonner.js +2 -0
- package/dist/components/ui/sonner.js.map +1 -1
- package/dist/components/ui/stepper.js +26 -3
- package/dist/components/ui/stepper.js.map +1 -1
- package/dist/components/ui/time-picker.d.ts +24 -4
- package/dist/components/ui/time-picker.js +425 -162
- package/dist/components/ui/time-picker.js.map +1 -1
- package/dist/components/ui/timeline.js +45 -9
- package/dist/components/ui/timeline.js.map +1 -1
- package/dist/components/ui/toggle-group.js +12 -1
- package/dist/components/ui/toggle-group.js.map +1 -1
- package/dist/components/ui/tour.js +3 -2
- package/dist/components/ui/tour.js.map +1 -1
- package/dist/data-grid/data-grid-cell-variants.js +4 -4
- package/dist/data-grid/data-grid-cell-variants.js.map +1 -1
- package/dist/data-grid/data-grid-cell-wrapper.d.ts +1 -1
- package/dist/data-grid/data-grid-cell-wrapper.js +6 -0
- package/dist/data-grid/data-grid-cell-wrapper.js.map +1 -1
- package/dist/data-grid/data-grid-row.js +1 -1
- package/dist/data-grid/data-grid-row.js.map +1 -1
- package/dist/data-grid/data-grid-select-column.js +6 -2
- package/dist/data-grid/data-grid-select-column.js.map +1 -1
- package/dist/data-grid/data-grid-skeleton.d.ts +5 -0
- package/dist/data-grid/data-grid-skeleton.js +1 -4
- package/dist/data-grid/data-grid-skeleton.js.map +1 -1
- package/dist/data-grid/data-grid.d.ts +1 -1
- package/dist/data-grid/data-grid.js +3 -2
- package/dist/data-grid/data-grid.js.map +1 -1
- package/dist/data-grid/filters.js +3 -2
- package/dist/data-grid/filters.js.map +1 -1
- package/dist/data-grid/types.d.ts +7 -0
- package/dist/data-grid/use-data-grid.d.ts +1 -0
- package/dist/data-grid/use-data-grid.js +70 -24
- package/dist/data-grid/use-data-grid.js.map +1 -1
- package/dist/data-grid/utils.d.ts +7 -0
- package/dist/data-grid/utils.js +3 -1
- package/dist/data-grid/utils.js.map +1 -1
- package/dist/i18n/locale-provider.d.ts +18 -0
- package/dist/i18n/locale-provider.js.map +1 -1
- package/dist/i18n/namespaces/rating.js +2 -1
- package/dist/i18n/namespaces/rating.js.map +1 -1
- package/dist/i18n/namespaces/search-filter-bar.js +8 -6
- package/dist/i18n/namespaces/search-filter-bar.js.map +1 -1
- package/dist/i18n/namespaces/shell.d.ts +4 -0
- package/dist/i18n/namespaces/shell.js +1 -1
- package/dist/i18n/namespaces/shell.js.map +1 -1
- package/dist/i18n/namespaces/table-pagination.js +6 -4
- package/dist/i18n/namespaces/table-pagination.js.map +1 -1
- package/dist/i18n/namespaces/toast.d.ts +3 -2
- package/dist/i18n/namespaces/toast.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/lib/collect-item-elements.d.ts +47 -0
- package/dist/lib/collect-item-elements.js +22 -0
- package/dist/lib/collect-item-elements.js.map +1 -0
- package/dist/lib/text-search.d.ts +32 -0
- package/dist/lib/text-search.js +17 -0
- package/dist/lib/text-search.js.map +1 -0
- package/dist/lib/toast-language.d.ts +8 -0
- package/dist/lib/toast-language.js +19 -0
- package/dist/lib/toast-language.js.map +1 -0
- package/dist/shell/app-shell.d.ts +1 -0
- package/dist/shell/index.d.ts +2 -1
- package/dist/shell/shell-context.d.ts +1 -0
- package/dist/shell/utils.d.ts +2 -1
- 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
|
|
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(
|
|
39
|
-
|
|
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
|
|
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(
|
|
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":"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","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"]}
|
|
@@ -37,7 +37,18 @@ function ToggleGroupItem({ className, children, variant, size, ...props }) {
|
|
|
37
37
|
variant: context.variant || variant,
|
|
38
38
|
size: context.size || size
|
|
39
39
|
}),
|
|
40
|
-
|
|
40
|
+
/*
|
|
41
|
+
* ⚠ Khác shadcn (3.0.1): `min-w-auto` thay cho `min-w-0`. Với `flex-1` (nền 0) mọi mục được
|
|
42
|
+
* chia ĐỀU bề rộng của nhóm, nên mục có nhãn dài hẹp hơn chính nhãn của nó và chữ in đè sang
|
|
43
|
+
* mục bên cạnh — đo ở nhóm `w-fit` mặc định: "vi + locale=en-US" (chữ 120px) trong mục 86px.
|
|
44
|
+
* `min-w-auto` trả lại sàn mặc định của flex item là bề rộng NỘI DUNG (`whitespace-nowrap` nên
|
|
45
|
+
* đúng bằng nhãn): nhóm `w-fit` thì mỗi mục vừa nhãn của nó, nhóm `w-full` vẫn chia đều, chỉ
|
|
46
|
+
* mục nào nhãn dài hơn phần chia mới rộng hơn.
|
|
47
|
+
* ⚠ Chỉ BỎ `min-w-0` là không đủ: tailwind-merge khi đó giữ lại `min-w-9` của `toggleVariants`
|
|
48
|
+
* — một sàn 36px CỐ ĐỊNH, vẫn không theo nhãn. Cả `min-w-0` lẫn `min-w-auto` đều đè nó đi, nên
|
|
49
|
+
* nút chỉ có icon trong nhóm vẫn rộng theo icon như ở `3.0.0`.
|
|
50
|
+
*/
|
|
51
|
+
"min-w-auto flex-1 shrink-0 rounded-none shadow-none first:rounded-l-md last:rounded-r-md focus:z-10 focus-visible:z-10 data-[variant=outline]:border-l-0 data-[variant=outline]:first:border-l",
|
|
41
52
|
className
|
|
42
53
|
),
|
|
43
54
|
...props,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/ui/toggle-group.tsx"],"sourcesContent":["\"use client\";\n\nimport * as ToggleGroupPrimitive from \"@radix-ui/react-toggle-group\";\nimport type { VariantProps } from \"class-variance-authority\";\nimport * as React from \"react\";\nimport { cn } from \"../../lib/cn.js\";\nimport { toggleVariants } from \"./toggle.js\";\n\n/**\n * ToggleGroup (Radix) — dãy Toggle dính liền, dùng cho bộ lọc dạng segmented.\n * `variant`/`size` đặt ở group sẽ truyền xuống item qua context; item vẫn override được.\n */\n\nexport type ToggleGroupVariantProps = VariantProps<typeof toggleVariants>;\nexport type ToggleGroupProps = React.ComponentProps<typeof ToggleGroupPrimitive.Root> & ToggleGroupVariantProps;\nexport type ToggleGroupItemProps = React.ComponentProps<typeof ToggleGroupPrimitive.Item> & ToggleGroupVariantProps;\n\nconst ToggleGroupContext = React.createContext<ToggleGroupVariantProps>({\n size: \"default\",\n variant: \"default\"\n});\n\nfunction ToggleGroup({ className, variant, size, children, ...props }: ToggleGroupProps) {\n return (\n <ToggleGroupPrimitive.Root\n data-slot=\"toggle-group\"\n data-variant={variant}\n data-size={size}\n className={cn(\n \"group/toggle-group flex w-fit items-center rounded-md data-[variant=outline]:shadow-xs\",\n className\n )}\n {...props}\n >\n <ToggleGroupContext.Provider value={{ variant, size }}>{children}</ToggleGroupContext.Provider>\n </ToggleGroupPrimitive.Root>\n );\n}\n\nfunction ToggleGroupItem({ className, children, variant, size, ...props }: ToggleGroupItemProps) {\n const context = React.useContext(ToggleGroupContext);\n\n return (\n <ToggleGroupPrimitive.Item\n data-slot=\"toggle-group-item\"\n data-variant={context.variant || variant}\n data-size={context.size || size}\n className={cn(\n toggleVariants({\n variant: context.variant || variant,\n size: context.size || size\n }),\n \"min-w-0 flex-1 shrink-0 rounded-none shadow-none first:rounded-l-md last:rounded-r-md focus:z-10 focus-visible:z-10 data-[variant=outline]:border-l-0 data-[variant=outline]:first:border-l\",\n className\n )}\n {...props}\n >\n {children}\n </ToggleGroupPrimitive.Item>\n );\n}\n\nexport { ToggleGroup, ToggleGroupItem };\n"],"mappings":";AAkCM;AAhCN,YAAY,0BAA0B;AAEtC,YAAY,WAAW;AACvB,SAAS,UAAU;AACnB,SAAS,sBAAsB;AAW/B,MAAM,qBAAqB,MAAM,cAAuC;AAAA,EACtE,MAAM;AAAA,EACN,SAAS;AACX,CAAC;AAED,SAAS,YAAY,EAAE,WAAW,SAAS,MAAM,UAAU,GAAG,MAAM,GAAqB;AACvF,SACE;AAAA,IAAC,qBAAqB;AAAA,IAArB;AAAA,MACC,aAAU;AAAA,MACV,gBAAc;AAAA,MACd,aAAW;AAAA,MACX,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MACC,GAAG;AAAA,MAEJ,8BAAC,mBAAmB,UAAnB,EAA4B,OAAO,EAAE,SAAS,KAAK,GAAI,UAAS;AAAA;AAAA,EACnE;AAEJ;AAEA,SAAS,gBAAgB,EAAE,WAAW,UAAU,SAAS,MAAM,GAAG,MAAM,GAAyB;AAC/F,QAAM,UAAU,MAAM,WAAW,kBAAkB;AAEnD,SACE;AAAA,IAAC,qBAAqB;AAAA,IAArB;AAAA,MACC,aAAU;AAAA,MACV,gBAAc,QAAQ,WAAW;AAAA,MACjC,aAAW,QAAQ,QAAQ;AAAA,MAC3B,WAAW;AAAA,QACT,eAAe;AAAA,UACb,SAAS,QAAQ,WAAW;AAAA,UAC5B,MAAM,QAAQ,QAAQ;AAAA,QACxB,CAAC;AAAA,
|
|
1
|
+
{"version":3,"sources":["../../../src/components/ui/toggle-group.tsx"],"sourcesContent":["\"use client\";\n\nimport * as ToggleGroupPrimitive from \"@radix-ui/react-toggle-group\";\nimport type { VariantProps } from \"class-variance-authority\";\nimport * as React from \"react\";\nimport { cn } from \"../../lib/cn.js\";\nimport { toggleVariants } from \"./toggle.js\";\n\n/**\n * ToggleGroup (Radix) — dãy Toggle dính liền, dùng cho bộ lọc dạng segmented.\n * `variant`/`size` đặt ở group sẽ truyền xuống item qua context; item vẫn override được.\n */\n\nexport type ToggleGroupVariantProps = VariantProps<typeof toggleVariants>;\nexport type ToggleGroupProps = React.ComponentProps<typeof ToggleGroupPrimitive.Root> & ToggleGroupVariantProps;\nexport type ToggleGroupItemProps = React.ComponentProps<typeof ToggleGroupPrimitive.Item> & ToggleGroupVariantProps;\n\nconst ToggleGroupContext = React.createContext<ToggleGroupVariantProps>({\n size: \"default\",\n variant: \"default\"\n});\n\nfunction ToggleGroup({ className, variant, size, children, ...props }: ToggleGroupProps) {\n return (\n <ToggleGroupPrimitive.Root\n data-slot=\"toggle-group\"\n data-variant={variant}\n data-size={size}\n className={cn(\n \"group/toggle-group flex w-fit items-center rounded-md data-[variant=outline]:shadow-xs\",\n className\n )}\n {...props}\n >\n <ToggleGroupContext.Provider value={{ variant, size }}>{children}</ToggleGroupContext.Provider>\n </ToggleGroupPrimitive.Root>\n );\n}\n\nfunction ToggleGroupItem({ className, children, variant, size, ...props }: ToggleGroupItemProps) {\n const context = React.useContext(ToggleGroupContext);\n\n return (\n <ToggleGroupPrimitive.Item\n data-slot=\"toggle-group-item\"\n data-variant={context.variant || variant}\n data-size={context.size || size}\n className={cn(\n toggleVariants({\n variant: context.variant || variant,\n size: context.size || size\n }),\n /*\n * ⚠ Khác shadcn (3.0.1): `min-w-auto` thay cho `min-w-0`. Với `flex-1` (nền 0) mọi mục được\n * chia ĐỀU bề rộng của nhóm, nên mục có nhãn dài hẹp hơn chính nhãn của nó và chữ in đè sang\n * mục bên cạnh — đo ở nhóm `w-fit` mặc định: \"vi + locale=en-US\" (chữ 120px) trong mục 86px.\n * `min-w-auto` trả lại sàn mặc định của flex item là bề rộng NỘI DUNG (`whitespace-nowrap` nên\n * đúng bằng nhãn): nhóm `w-fit` thì mỗi mục vừa nhãn của nó, nhóm `w-full` vẫn chia đều, chỉ\n * mục nào nhãn dài hơn phần chia mới rộng hơn.\n * ⚠ Chỉ BỎ `min-w-0` là không đủ: tailwind-merge khi đó giữ lại `min-w-9` của `toggleVariants`\n * — một sàn 36px CỐ ĐỊNH, vẫn không theo nhãn. Cả `min-w-0` lẫn `min-w-auto` đều đè nó đi, nên\n * nút chỉ có icon trong nhóm vẫn rộng theo icon như ở `3.0.0`.\n */\n \"min-w-auto flex-1 shrink-0 rounded-none shadow-none first:rounded-l-md last:rounded-r-md focus:z-10 focus-visible:z-10 data-[variant=outline]:border-l-0 data-[variant=outline]:first:border-l\",\n className\n )}\n {...props}\n >\n {children}\n </ToggleGroupPrimitive.Item>\n );\n}\n\nexport { ToggleGroup, ToggleGroupItem };\n"],"mappings":";AAkCM;AAhCN,YAAY,0BAA0B;AAEtC,YAAY,WAAW;AACvB,SAAS,UAAU;AACnB,SAAS,sBAAsB;AAW/B,MAAM,qBAAqB,MAAM,cAAuC;AAAA,EACtE,MAAM;AAAA,EACN,SAAS;AACX,CAAC;AAED,SAAS,YAAY,EAAE,WAAW,SAAS,MAAM,UAAU,GAAG,MAAM,GAAqB;AACvF,SACE;AAAA,IAAC,qBAAqB;AAAA,IAArB;AAAA,MACC,aAAU;AAAA,MACV,gBAAc;AAAA,MACd,aAAW;AAAA,MACX,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MACC,GAAG;AAAA,MAEJ,8BAAC,mBAAmB,UAAnB,EAA4B,OAAO,EAAE,SAAS,KAAK,GAAI,UAAS;AAAA;AAAA,EACnE;AAEJ;AAEA,SAAS,gBAAgB,EAAE,WAAW,UAAU,SAAS,MAAM,GAAG,MAAM,GAAyB;AAC/F,QAAM,UAAU,MAAM,WAAW,kBAAkB;AAEnD,SACE;AAAA,IAAC,qBAAqB;AAAA,IAArB;AAAA,MACC,aAAU;AAAA,MACV,gBAAc,QAAQ,WAAW;AAAA,MACjC,aAAW,QAAQ,QAAQ;AAAA,MAC3B,WAAW;AAAA,QACT,eAAe;AAAA,UACb,SAAS,QAAQ,WAAW;AAAA,UAC5B,MAAM,QAAQ,QAAQ;AAAA,QACxB,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAYD;AAAA,QACA;AAAA,MACF;AAAA,MACC,GAAG;AAAA,MAEH;AAAA;AAAA,EACH;AAEJ;","names":[]}
|
|
@@ -386,6 +386,7 @@ function Tour(props) {
|
|
|
386
386
|
},
|
|
387
387
|
setState: (key, value) => {
|
|
388
388
|
if (Object.is(stateRef.current[key], value)) return;
|
|
389
|
+
const previousValue = stateRef.current.value;
|
|
389
390
|
stateRef.current[key] = value;
|
|
390
391
|
if (key === "open" && typeof value === "boolean") {
|
|
391
392
|
propsRef.current.onOpenChange?.(value);
|
|
@@ -396,12 +397,12 @@ function Tour(props) {
|
|
|
396
397
|
}
|
|
397
398
|
}
|
|
398
399
|
} else {
|
|
399
|
-
if (stateRef.current.value < (stateRef.current.steps.length || 0)
|
|
400
|
+
if (stateRef.current.value < (stateRef.current.steps.length || 0)) {
|
|
400
401
|
propsRef.current.onSkip?.();
|
|
401
402
|
}
|
|
402
403
|
}
|
|
403
404
|
} else if (key === "value" && typeof value === "number") {
|
|
404
|
-
const prevStep = stateRef.current.steps[
|
|
405
|
+
const prevStep = stateRef.current.steps[previousValue];
|
|
405
406
|
const nextStep = stateRef.current.steps[value];
|
|
406
407
|
prevStep?.onStepLeave?.();
|
|
407
408
|
nextStep?.onStepEnter?.();
|