@expcat/tigercat-react 2.1.4 → 2.3.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 (48) hide show
  1. package/dist/chunk-2MV3F7WP.mjs +56 -0
  2. package/dist/{chunk-SUHSOVWP.mjs → chunk-6T5AEQJV.mjs} +1 -1
  3. package/dist/{chunk-R2VBVZIH.mjs → chunk-75SQCTLC.mjs} +4 -4
  4. package/dist/{chunk-73OFTRG5.mjs → chunk-AHQR57Z4.mjs} +1 -1
  5. package/dist/{chunk-2STETY2J.mjs → chunk-CCFKRKGJ.mjs} +12 -6
  6. package/dist/{chunk-UNT7WJ2M.mjs → chunk-DNRLMEKE.mjs} +10 -3
  7. package/dist/chunk-F4XF5CGQ.mjs +72 -0
  8. package/dist/chunk-FZQUUTWN.mjs +145 -0
  9. package/dist/{chunk-NPXT436C.mjs → chunk-MMDVFCCL.mjs} +1 -1
  10. package/dist/chunk-NCVZCG4W.mjs +138 -0
  11. package/dist/{chunk-25BKSXTX.mjs → chunk-NMRCBGFP.mjs} +1 -1
  12. package/dist/chunk-REHHFHZ3.mjs +67 -0
  13. package/dist/{chunk-XI6KQAHW.mjs → chunk-RJ2FJXHT.mjs} +5 -6
  14. package/dist/{chunk-WN6ZHQTI.mjs → chunk-SIBNSFVR.mjs} +10 -4
  15. package/dist/{chunk-3WP4PGHF.mjs → chunk-TFHQODGK.mjs} +7 -1
  16. package/dist/{chunk-IR45LOEZ.mjs → chunk-UGKTSPS4.mjs} +38 -4
  17. package/dist/components/ActivityFeed.mjs +2 -2
  18. package/dist/components/Anchor.mjs +1 -1
  19. package/dist/components/BackTop.mjs +1 -1
  20. package/dist/components/Badge.d.mts +1 -1
  21. package/dist/components/Calendar.mjs +1 -1
  22. package/dist/components/Code.mjs +1 -1
  23. package/dist/components/CommentThread.mjs +2 -2
  24. package/dist/components/DataTableWithToolbar.mjs +1 -1
  25. package/dist/components/DatePicker.mjs +2 -2
  26. package/dist/components/Drag.d.mts +17 -0
  27. package/dist/components/Drag.mjs +9 -0
  28. package/dist/components/Footer.mjs +1 -1
  29. package/dist/components/FullscreenButton.d.mts +8 -0
  30. package/dist/components/FullscreenButton.mjs +10 -0
  31. package/dist/components/Menu.mjs +1 -1
  32. package/dist/components/NotificationCenter.mjs +2 -2
  33. package/dist/components/Popconfirm.d.mts +1 -1
  34. package/dist/components/Popover.d.mts +1 -1
  35. package/dist/components/ScrollSpy.mjs +1 -1
  36. package/dist/components/Segmented.d.mts +1 -1
  37. package/dist/components/Space.d.mts +1 -1
  38. package/dist/components/Text.d.mts +6 -2
  39. package/dist/components/Text.mjs +2 -1
  40. package/dist/components/Tooltip.d.mts +1 -1
  41. package/dist/components/WorkflowTimeline.d.mts +20 -0
  42. package/dist/components/WorkflowTimeline.mjs +15 -0
  43. package/dist/hooks/useFullscreen.d.mts +13 -0
  44. package/dist/hooks/useFullscreen.mjs +6 -0
  45. package/dist/index.d.mts +6 -2
  46. package/dist/index.mjs +64 -0
  47. package/package.json +27 -2
  48. package/dist/chunk-VDBLI5Y3.mjs +0 -33
@@ -0,0 +1,56 @@
1
+ // src/hooks/useFullscreen.ts
2
+ import { useCallback, useEffect, useRef, useState } from "react";
3
+ import {
4
+ exitElementFullscreen,
5
+ getFullscreenElement,
6
+ isElementFullscreen,
7
+ isFullscreenSupported,
8
+ requestElementFullscreen,
9
+ resolveFullscreenTarget,
10
+ subscribeFullscreenChange
11
+ } from "@expcat/tigercat-core";
12
+ function useFullscreen(options = {}) {
13
+ const optionsRef = useRef(options);
14
+ optionsRef.current = options;
15
+ const [supported] = useState(() => isFullscreenSupported());
16
+ const [isFullscreen, setIsFullscreen] = useState(false);
17
+ const sync = useCallback(() => {
18
+ const target = resolveFullscreenTarget(optionsRef.current.target);
19
+ const next = isElementFullscreen(target);
20
+ setIsFullscreen(next);
21
+ optionsRef.current.onChange?.(next);
22
+ }, []);
23
+ useEffect(() => {
24
+ sync();
25
+ return subscribeFullscreenChange(sync);
26
+ }, [sync]);
27
+ const enter = useCallback(async () => {
28
+ const target = resolveFullscreenTarget(optionsRef.current.target);
29
+ if (!target) return;
30
+ if (isElementFullscreen(target)) return;
31
+ try {
32
+ await requestElementFullscreen(target);
33
+ } catch (error) {
34
+ const err = error instanceof Error ? error : new Error("Fullscreen request failed");
35
+ optionsRef.current.onError?.(err);
36
+ }
37
+ }, []);
38
+ const exit = useCallback(async () => {
39
+ if (!getFullscreenElement()) return;
40
+ try {
41
+ await exitElementFullscreen();
42
+ } catch (error) {
43
+ const err = error instanceof Error ? error : new Error("Fullscreen exit failed");
44
+ optionsRef.current.onError?.(err);
45
+ }
46
+ }, []);
47
+ const toggle = useCallback(async () => {
48
+ if (isFullscreen) await exit();
49
+ else await enter();
50
+ }, [enter, exit, isFullscreen]);
51
+ return { isFullscreen, supported, enter, exit, toggle };
52
+ }
53
+
54
+ export {
55
+ useFullscreen
56
+ };
@@ -12,7 +12,7 @@ import {
12
12
  } from "./chunk-FVA5VKN2.mjs";
13
13
  import {
14
14
  Text
15
- } from "./chunk-VDBLI5Y3.mjs";
15
+ } from "./chunk-FZQUUTWN.mjs";
16
16
  import {
17
17
  Card
18
18
  } from "./chunk-WCIUNNIN.mjs";
@@ -2,13 +2,13 @@
2
2
  import { forwardRef } from "react";
3
3
  import {
4
4
  classNames,
5
- injectLayoutGridStyles,
6
- layoutFooterClasses
5
+ getLayoutFooterClasses,
6
+ injectLayoutGridStyles
7
7
  } from "@expcat/tigercat-core";
8
8
  import { jsx } from "react/jsx-runtime";
9
- var Footer = forwardRef(function Footer2({ className, height, style, as = "footer", children, ...props }, ref) {
9
+ var Footer = forwardRef(function Footer2({ className, height, size = "default", style, as = "footer", children, ...props }, ref) {
10
10
  injectLayoutGridStyles();
11
- const footerClasses = classNames(layoutFooterClasses, className);
11
+ const footerClasses = classNames(getLayoutFooterClasses(size), className);
12
12
  const footerStyle = height ? { ...style, height } : style;
13
13
  const Tag = as;
14
14
  return /* @__PURE__ */ jsx(Tag, { ref, className: footerClasses, style: footerStyle, ...props, children });
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  Calendar
3
- } from "./chunk-IR45LOEZ.mjs";
3
+ } from "./chunk-UGKTSPS4.mjs";
4
4
  import {
5
5
  useInputGroupContext
6
6
  } from "./chunk-2AVQQGL2.mjs";
@@ -65,13 +65,18 @@ var ScrollSpy = forwardRef(function ScrollSpy2({
65
65
  const flatItems = useMemo(() => flattenScrollSpyItems(items), [items]);
66
66
  const activeKeyRef = useRef(currentActiveKey);
67
67
  activeKeyRef.current = currentActiveKey;
68
- const resolvedContainer = resolveScrollSpyContainer(getContainer);
68
+ const hostRef = useRef(null);
69
+ const setHostRef = (node) => {
70
+ hostRef.current = node;
71
+ if (typeof ref === "function") ref(node);
72
+ else if (ref) ref.current = node;
73
+ };
74
+ const resolvedContainer = resolveScrollSpyContainer(getContainer, hostRef.current);
69
75
  const containerKey = resolvedContainer === window ? "window" : resolvedContainer;
70
76
  const getContainerRef = useRef(getContainer);
71
77
  getContainerRef.current = getContainer;
72
- const scrollLockRef = useRef(
73
- createProgrammaticScrollLock(() => resolveScrollSpyContainer(getContainerRef.current))
74
- );
78
+ const resolveContainer = () => resolveScrollSpyContainer(getContainerRef.current, hostRef.current);
79
+ const scrollLockRef = useRef(createProgrammaticScrollLock(() => resolveContainer()));
75
80
  const emitActive = useCallback(
76
81
  (item, source) => {
77
82
  const nextKeyString = getScrollSpyKeyString(item.key);
@@ -85,6 +90,7 @@ var ScrollSpy = forwardRef(function ScrollSpy2({
85
90
  useEffect(() => {
86
91
  return createScrollSpyObserver(items, {
87
92
  container: getContainerRef.current,
93
+ from: hostRef.current,
88
94
  offsetTop: offset,
89
95
  bounds,
90
96
  onChange: (item) => {
@@ -110,7 +116,7 @@ var ScrollSpy = forwardRef(function ScrollSpy2({
110
116
  onClick?.(item, event);
111
117
  emitActive(item, "click");
112
118
  scrollLockRef.current.lock();
113
- activateScrollSpyClick(item, resolveScrollSpyContainer(getContainerRef.current), offset);
119
+ activateScrollSpyClick(item, resolveContainer(), offset);
114
120
  },
115
121
  [emitActive, offset, onClick]
116
122
  );
@@ -144,7 +150,7 @@ var ScrollSpy = forwardRef(function ScrollSpy2({
144
150
  "nav",
145
151
  {
146
152
  ...rest,
147
- ref,
153
+ ref: setHostRef,
148
154
  className: classNames(getScrollSpyRootClasses(sticky, className)),
149
155
  style: getScrollSpyRootStyle(sticky, offset, style),
150
156
  "aria-label": ariaLabel ?? labels.ariaLabel,
@@ -50,7 +50,9 @@ import {
50
50
  reconcileSearchOpenKeys,
51
51
  resolveMenuCollapsed,
52
52
  resolveMenuMode,
53
+ resolveMenuSearchQuery,
53
54
  resolveSearchFilter,
55
+ shouldShowMenuSearch,
54
56
  warnControlledSearchOpenKeys
55
57
  } from "@expcat/tigercat-core";
56
58
 
@@ -201,9 +203,14 @@ function useMenuRootState(props) {
201
203
  },
202
204
  [setSearchValue]
203
205
  );
206
+ const showSearch = shouldShowMenuSearch(searchable, collapsed);
204
207
  const { filtered: filteredItems, expandKeys } = useMemo(
205
- () => resolveSearchFilter({ items, query: searchValue, filterMode }),
206
- [items, searchValue, filterMode]
208
+ () => resolveSearchFilter({
209
+ items,
210
+ query: resolveMenuSearchQuery(searchable, collapsed, searchValue),
211
+ filterMode
212
+ }),
213
+ [items, searchValue, filterMode, searchable, collapsed]
207
214
  );
208
215
  useEffect(() => {
209
216
  const current = openKeysRef.current;
@@ -285,7 +292,7 @@ function useMenuRootState(props) {
285
292
  resolvedMode,
286
293
  mode,
287
294
  contextValue,
288
- searchable,
295
+ searchable: showSearch,
289
296
  searchValue,
290
297
  searchPlaceholder: searchPlaceholder ?? locale?.common?.searchPlaceholder ?? "Search",
291
298
  emptyText: emptyText ?? locale?.common?.emptyText ?? "No data",
@@ -0,0 +1,72 @@
1
+ import {
2
+ useDrag
3
+ } from "./chunk-REJVXLW5.mjs";
4
+
5
+ // src/components/Drag.tsx
6
+ import React from "react";
7
+ import {
8
+ classNames,
9
+ reorderSequence
10
+ } from "@expcat/tigercat-core";
11
+ import { jsx } from "react/jsx-runtime";
12
+ function Drag({
13
+ items = [],
14
+ onItemsChange,
15
+ config,
16
+ containerId,
17
+ onDragStart,
18
+ onDragOver,
19
+ onDrop,
20
+ onDragEnd,
21
+ className,
22
+ children,
23
+ renderItem
24
+ }) {
25
+ const itemsRef = React.useRef(items);
26
+ itemsRef.current = items;
27
+ const onItemsChangeRef = React.useRef(onItemsChange);
28
+ onItemsChangeRef.current = onItemsChange;
29
+ const onDropRef = React.useRef(onDrop);
30
+ onDropRef.current = onDrop;
31
+ const drag = useDrag({
32
+ config,
33
+ containerId,
34
+ onDragStart,
35
+ onDragOver,
36
+ onDragEnd,
37
+ onDrop: (event) => {
38
+ onDropRef.current?.(event);
39
+ if (event.fromIndex === event.toIndex) return;
40
+ const next = reorderSequence(itemsRef.current, event.fromIndex, event.toIndex).map(
41
+ (item, index) => ({ ...item, index })
42
+ );
43
+ onItemsChangeRef.current?.(next);
44
+ }
45
+ });
46
+ const render = children ?? renderItem;
47
+ const zoneProps = drag.getDropZoneProps();
48
+ return /* @__PURE__ */ jsx(
49
+ "ul",
50
+ {
51
+ ...zoneProps,
52
+ className: classNames("m-0 list-none p-0", className),
53
+ "data-tiger-drag": "",
54
+ role: "list",
55
+ children: items.map((item) => {
56
+ const itemProps = drag.getDragItemProps(item);
57
+ const node = render?.(item, {
58
+ dragItemProps: itemProps,
59
+ isDragging: drag.draggedItem?.id === item.id
60
+ });
61
+ return /* @__PURE__ */ jsx(React.Fragment, { children: node ?? /* @__PURE__ */ jsx("li", { ...itemProps, role: "listitem", children: String(item.id) }) }, item.id);
62
+ })
63
+ }
64
+ );
65
+ }
66
+ Drag.displayName = "Drag";
67
+ var Drag_default = Drag;
68
+
69
+ export {
70
+ Drag,
71
+ Drag_default
72
+ };
@@ -0,0 +1,145 @@
1
+ import {
2
+ useTigerConfig
3
+ } from "./chunk-RUIFGSVN.mjs";
4
+
5
+ // src/components/Text.tsx
6
+ import React, { forwardRef, useEffect, useMemo, useRef, useState } from "react";
7
+ import {
8
+ classNames,
9
+ copyTextToClipboard,
10
+ createCopyStatusReset,
11
+ getCodeLabels,
12
+ getIconDefinition,
13
+ getTextClasses,
14
+ isTextCopyable,
15
+ mergeTigerLocale,
16
+ resolveLocaleText,
17
+ resolveTextCopyableOptions,
18
+ resolveTextCopyContent,
19
+ resolveTextTag,
20
+ textCopyableBodyClasses,
21
+ textCopyableButtonClasses,
22
+ textCopyableLiveClasses,
23
+ textCopyableRootClasses
24
+ } from "@expcat/tigercat-core";
25
+ import { jsx } from "react/jsx-runtime";
26
+ var copyIcon = getIconDefinition("copy");
27
+ function CopyGlyph() {
28
+ if (!copyIcon) return null;
29
+ return /* @__PURE__ */ jsx(
30
+ "svg",
31
+ {
32
+ xmlns: "http://www.w3.org/2000/svg",
33
+ viewBox: copyIcon.viewBox,
34
+ fill: "none",
35
+ stroke: "currentColor",
36
+ strokeWidth: "1.5",
37
+ strokeLinecap: "round",
38
+ strokeLinejoin: "round",
39
+ className: "h-3.5 w-3.5",
40
+ "aria-hidden": "true",
41
+ children: copyIcon.paths.map((d, i) => /* @__PURE__ */ jsx("path", { d }, i))
42
+ }
43
+ );
44
+ }
45
+ var Text = forwardRef(function Text2({
46
+ tag = "p",
47
+ size,
48
+ weight,
49
+ align,
50
+ color,
51
+ truncate,
52
+ italic,
53
+ underline,
54
+ lineThrough,
55
+ copyable,
56
+ locale,
57
+ children,
58
+ className,
59
+ onCopy,
60
+ ...props
61
+ }, ref) {
62
+ const resolvedTag = resolveTextTag(tag);
63
+ const copyEnabled = isTextCopyable(copyable);
64
+ const copyOptions = resolveTextCopyableOptions(copyable);
65
+ const textClasses = classNames(
66
+ getTextClasses({
67
+ size,
68
+ weight,
69
+ align,
70
+ color,
71
+ truncate,
72
+ italic,
73
+ underline,
74
+ lineThrough,
75
+ copyable
76
+ }),
77
+ !copyEnabled && className
78
+ );
79
+ const config = useTigerConfig();
80
+ const mergedLocale = useMemo(
81
+ () => mergeTigerLocale(config.locale, locale),
82
+ [config.locale, locale]
83
+ );
84
+ const labels = useMemo(() => getCodeLabels(mergedLocale), [mergedLocale]);
85
+ const idleLabel = resolveLocaleText(labels.copyLabel, copyOptions?.tooltip);
86
+ const [copyStatus, setCopyStatus] = useState("idle");
87
+ const resetRef = useRef(null);
88
+ if (resetRef.current == null) {
89
+ resetRef.current = createCopyStatusReset(setCopyStatus);
90
+ }
91
+ useEffect(() => {
92
+ const machine = resetRef.current;
93
+ return () => machine?.dispose();
94
+ }, []);
95
+ const bodyRef = useRef(null);
96
+ const buttonLabel = copyStatus === "failed" ? labels.copyFailedLabel : copyStatus === "copied" ? labels.copiedLabel : idleLabel;
97
+ const liveText = copyStatus === "idle" ? "" : buttonLabel;
98
+ const handleCopy = async () => {
99
+ if (!copyOptions) return;
100
+ const fallback = bodyRef.current?.textContent ?? "";
101
+ const text = resolveTextCopyContent(copyOptions, fallback);
102
+ const ok = await copyTextToClipboard(text);
103
+ if (ok) {
104
+ resetRef.current?.schedule("copied");
105
+ copyOptions.onCopy?.(text);
106
+ onCopy?.(text);
107
+ } else {
108
+ resetRef.current?.schedule("failed");
109
+ }
110
+ };
111
+ if (!copyEnabled) {
112
+ return React.createElement(resolvedTag, { ...props, ref, className: textClasses }, children);
113
+ }
114
+ return React.createElement(
115
+ resolvedTag,
116
+ { ...props, ref, className: classNames(textCopyableRootClasses, className) },
117
+ /* @__PURE__ */ jsx(
118
+ "span",
119
+ {
120
+ ref: bodyRef,
121
+ className: classNames(textCopyableBodyClasses, truncate && "truncate", textClasses),
122
+ children
123
+ }
124
+ ),
125
+ /* @__PURE__ */ jsx(
126
+ "button",
127
+ {
128
+ type: "button",
129
+ className: textCopyableButtonClasses,
130
+ "aria-label": buttonLabel,
131
+ title: buttonLabel,
132
+ onClick: () => {
133
+ void handleCopy();
134
+ },
135
+ children: /* @__PURE__ */ jsx(CopyGlyph, {})
136
+ }
137
+ ),
138
+ /* @__PURE__ */ jsx("span", { className: textCopyableLiveClasses, "aria-live": "polite", children: liveText })
139
+ );
140
+ });
141
+ Text.displayName = "Text";
142
+
143
+ export {
144
+ Text
145
+ };
@@ -10,7 +10,7 @@ import {
10
10
  } from "./chunk-VW6RNQK4.mjs";
11
11
  import {
12
12
  Text
13
- } from "./chunk-VDBLI5Y3.mjs";
13
+ } from "./chunk-FZQUUTWN.mjs";
14
14
  import {
15
15
  Card
16
16
  } from "./chunk-WCIUNNIN.mjs";
@@ -0,0 +1,138 @@
1
+ import {
2
+ Timeline
3
+ } from "./chunk-4DFN6RZ4.mjs";
4
+ import {
5
+ Tag
6
+ } from "./chunk-FVA5VKN2.mjs";
7
+ import {
8
+ Button
9
+ } from "./chunk-WFLXJOFU.mjs";
10
+
11
+ // src/components/WorkflowTimeline.tsx
12
+ import { useMemo } from "react";
13
+ import {
14
+ classNames,
15
+ resolveWorkflowActionButtonProps,
16
+ shouldShowWorkflowActions,
17
+ timelineDescriptionClasses,
18
+ timelineLabelClasses,
19
+ workflowStepsToTimelineItems,
20
+ workflowStepStatusLabel,
21
+ workflowStepStatusTagVariant
22
+ } from "@expcat/tigercat-core";
23
+ import { jsx, jsxs } from "react/jsx-runtime";
24
+ var workflowTimelineRootClasses = "flex flex-col gap-4";
25
+ var workflowActionBarClasses = "flex flex-wrap items-center gap-2";
26
+ var workflowStepHeaderClasses = "flex flex-wrap items-center gap-2";
27
+ var workflowStepActorClasses = "text-sm text-[var(--tiger-text-muted,#6b7280)]";
28
+ var workflowStepCommentClasses = "text-sm text-[var(--tiger-text-secondary,#4b5563)] mt-1";
29
+ function isWorkflowTimelineItem(item) {
30
+ return typeof item === "object" && item != null && "step" in item && "status" in item && typeof item.status === "string";
31
+ }
32
+ function renderStepContent(item) {
33
+ const step = item.step;
34
+ const title = step.title ?? step.label;
35
+ const statusLabel = workflowStepStatusLabel(item.status);
36
+ return /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
37
+ step.time ? /* @__PURE__ */ jsx("div", { className: timelineLabelClasses, children: step.time }) : null,
38
+ /* @__PURE__ */ jsxs("div", { className: workflowStepHeaderClasses, children: [
39
+ title ? /* @__PURE__ */ jsx("div", { className: timelineDescriptionClasses, children: title }) : null,
40
+ /* @__PURE__ */ jsx(Tag, { variant: workflowStepStatusTagVariant(item.status), size: "sm", pill: true, children: statusLabel })
41
+ ] }),
42
+ step.actor?.name ? /* @__PURE__ */ jsx("div", { className: workflowStepActorClasses, children: step.actor.name }) : null,
43
+ step.comment ? /* @__PURE__ */ jsx("div", { className: workflowStepCommentClasses, children: step.comment }) : null
44
+ ] });
45
+ }
46
+ var WorkflowActionBar = ({
47
+ items,
48
+ disabled,
49
+ ariaLabel,
50
+ className,
51
+ style,
52
+ onAction,
53
+ "aria-label": ariaLabelAttr,
54
+ ...rest
55
+ }) => {
56
+ const toolbarClasses = useMemo(() => classNames(workflowActionBarClasses, className), [className]);
57
+ return /* @__PURE__ */ jsx(
58
+ "div",
59
+ {
60
+ ...rest,
61
+ className: toolbarClasses,
62
+ style,
63
+ role: "toolbar",
64
+ "aria-label": ariaLabel ?? ariaLabelAttr ?? "Workflow actions",
65
+ children: (items ?? []).map((item) => {
66
+ const buttonProps = resolveWorkflowActionButtonProps(item);
67
+ const isDisabled = Boolean(disabled || item.disabled);
68
+ return /* @__PURE__ */ jsx(
69
+ Button,
70
+ {
71
+ size: "sm",
72
+ variant: buttonProps.variant,
73
+ danger: buttonProps.danger,
74
+ disabled: isDisabled,
75
+ onClick: () => {
76
+ if (isDisabled) return;
77
+ onAction?.(item);
78
+ },
79
+ children: item.label
80
+ },
81
+ item.key
82
+ );
83
+ })
84
+ }
85
+ );
86
+ };
87
+ var WorkflowTimeline = ({
88
+ steps,
89
+ actions,
90
+ showActions,
91
+ mode = "left",
92
+ pending = false,
93
+ pendingDot,
94
+ pendingContent,
95
+ reverse = false,
96
+ className,
97
+ style,
98
+ onAction,
99
+ renderItem,
100
+ renderDot,
101
+ renderActions,
102
+ "aria-label": ariaLabel,
103
+ ...rest
104
+ }) => {
105
+ const timelineItems = useMemo(() => workflowStepsToTimelineItems(steps), [steps]);
106
+ const showActionBar = shouldShowWorkflowActions(steps, actions, showActions);
107
+ const rootClasses = useMemo(() => classNames(workflowTimelineRootClasses, className), [className]);
108
+ const handleRenderItem = (item, index) => {
109
+ if (renderItem) return renderItem(item, index);
110
+ if (isWorkflowTimelineItem(item)) return renderStepContent(item);
111
+ return null;
112
+ };
113
+ const actionBar = showActionBar && actions ? renderActions ? renderActions(actions) : /* @__PURE__ */ jsx(WorkflowActionBar, { items: actions, onAction }) : null;
114
+ return /* @__PURE__ */ jsxs("div", { ...rest, className: rootClasses, style, children: [
115
+ /* @__PURE__ */ jsx(
116
+ Timeline,
117
+ {
118
+ items: timelineItems,
119
+ mode,
120
+ pending,
121
+ pendingDot,
122
+ pendingContent,
123
+ reverse,
124
+ renderItem: handleRenderItem,
125
+ renderDot,
126
+ "aria-label": ariaLabel ?? "Workflow timeline"
127
+ }
128
+ ),
129
+ actionBar
130
+ ] });
131
+ };
132
+ var WorkflowTimeline_default = WorkflowTimeline;
133
+
134
+ export {
135
+ WorkflowActionBar,
136
+ WorkflowTimeline,
137
+ WorkflowTimeline_default
138
+ };
@@ -6,7 +6,7 @@ import {
6
6
  } from "./chunk-FVA5VKN2.mjs";
7
7
  import {
8
8
  Text
9
- } from "./chunk-VDBLI5Y3.mjs";
9
+ } from "./chunk-FZQUUTWN.mjs";
10
10
  import {
11
11
  Avatar
12
12
  } from "./chunk-3KBFOO2E.mjs";
@@ -0,0 +1,67 @@
1
+ import {
2
+ useFullscreen
3
+ } from "./chunk-2MV3F7WP.mjs";
4
+ import {
5
+ useTigerConfig
6
+ } from "./chunk-RUIFGSVN.mjs";
7
+
8
+ // src/components/FullscreenButton.tsx
9
+ import { forwardRef } from "react";
10
+ import {
11
+ classNames,
12
+ fullscreenButtonClasses,
13
+ getFullscreenLabels,
14
+ getIconDefinition,
15
+ mergeTigerLocale
16
+ } from "@expcat/tigercat-core";
17
+ import { jsx } from "react/jsx-runtime";
18
+ function Glyph({ name }) {
19
+ const definition = getIconDefinition(name);
20
+ if (!definition) return null;
21
+ return /* @__PURE__ */ jsx(
22
+ "svg",
23
+ {
24
+ xmlns: "http://www.w3.org/2000/svg",
25
+ viewBox: definition.viewBox,
26
+ fill: "none",
27
+ stroke: "currentColor",
28
+ strokeWidth: "1.5",
29
+ strokeLinecap: "round",
30
+ strokeLinejoin: "round",
31
+ className: "h-5 w-5",
32
+ "aria-hidden": "true",
33
+ children: definition.paths.map((d, i) => /* @__PURE__ */ jsx("path", { d }, i))
34
+ }
35
+ );
36
+ }
37
+ var FullscreenButton = forwardRef(
38
+ function FullscreenButton2({ target, locale, labels, className, onChange, onError, ...props }, ref) {
39
+ const config = useTigerConfig();
40
+ const labelSet = getFullscreenLabels(mergeTigerLocale(config.locale, locale), labels);
41
+ const fullscreen = useFullscreen({ target, onChange, onError });
42
+ const label = fullscreen.isFullscreen ? labelSet.exitAriaLabel : labelSet.enterAriaLabel;
43
+ return /* @__PURE__ */ jsx(
44
+ "button",
45
+ {
46
+ ...props,
47
+ ref,
48
+ type: "button",
49
+ className: classNames(fullscreenButtonClasses, className),
50
+ "aria-label": label,
51
+ "aria-pressed": fullscreen.isFullscreen,
52
+ disabled: !fullscreen.supported,
53
+ onClick: () => {
54
+ void fullscreen.toggle();
55
+ },
56
+ children: /* @__PURE__ */ jsx(Glyph, { name: fullscreen.isFullscreen ? "fullscreen-exit" : "fullscreen" })
57
+ }
58
+ );
59
+ }
60
+ );
61
+ FullscreenButton.displayName = "FullscreenButton";
62
+ var FullscreenButton_default = FullscreenButton;
63
+
64
+ export {
65
+ FullscreenButton,
66
+ FullscreenButton_default
67
+ };
@@ -122,9 +122,8 @@ var Anchor = forwardRef(function Anchor2({
122
122
  getCurrentAnchorRef.current = getCurrentAnchor;
123
123
  const onChangeRef = useRef(onChange);
124
124
  onChangeRef.current = onChange;
125
- const scrollLockRef = useRef(
126
- createProgrammaticScrollLock(() => resolveAnchorScrollContainer(getContainerRef.current))
127
- );
125
+ const resolveContainer = () => resolveAnchorScrollContainer(getContainerRef.current, anchorRef.current);
126
+ const scrollLockRef = useRef(createProgrammaticScrollLock(() => resolveContainer()));
128
127
  const config = useTigerConfig();
129
128
  const mergedLocale = useMemo(
130
129
  () => mergeTigerLocale(config.locale, locale),
@@ -158,7 +157,7 @@ var Anchor = forwardRef(function Anchor2({
158
157
  }, []);
159
158
  const scrollTo = useCallback(
160
159
  (href) => {
161
- const container = resolveAnchorScrollContainer(getContainerRef.current);
160
+ const container = resolveContainer();
162
161
  scrollToAnchor(href, container, scrollOffset);
163
162
  },
164
163
  [scrollOffset]
@@ -182,10 +181,10 @@ var Anchor = forwardRef(function Anchor2({
182
181
  },
183
182
  [applyActive, onClick, scrollTo]
184
183
  );
185
- const resolved = resolveScrollRoot(getContainer);
184
+ const resolved = resolveScrollRoot(getContainer, { from: anchorRef.current });
186
185
  const resolvedKey = resolved.isWindow ? "window" : resolved.target;
187
186
  useEffect(() => {
188
- const container = resolveAnchorScrollContainer(getContainerRef.current);
187
+ const container = resolveContainer();
189
188
  const root = container === window ? null : container;
190
189
  const stop = createAnchorObserver(links, {
191
190
  offsetTop: scrollOffset,