@vegastack/design 0.3.1 → 0.4.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.
@@ -408,6 +408,7 @@ const JAVASCRIPT_LIKE_RE = /\.[cm]?[jt]sx?$/i;
408
408
  const SHADCN_TRANSFORMED_FILE_TYPES = new Set([
409
409
  "registry:ui",
410
410
  "registry:hook",
411
+ "registry:lib",
411
412
  "registry:page",
412
413
  "registry:component",
413
414
  ]);
@@ -0,0 +1,182 @@
1
+ // src/index.ts
2
+ import { clsx } from "clsx";
3
+ import { extendTailwindMerge } from "tailwind-merge";
4
+
5
+ // src/prose.ts
6
+ var prose = {
7
+ /** The root's own ink and size — every rule below is relative to this. */
8
+ root: "text-base text-foreground",
9
+ // Headings. `scroll-m-20` keeps an anchored heading clear of a sticky header; the weight ladder
10
+ // caps at 500, which the `text-h*` roles already carry.
11
+ h1: "[&_h1]:mt-6 [&_h1]:mb-3 [&_h1]:scroll-m-20 [&_h1]:text-h1 [&_h1]:text-foreground [&_h1]:first:mt-0",
12
+ h2: "[&_h2]:mt-6 [&_h2]:mb-3 [&_h2]:scroll-m-20 [&_h2]:text-h2 [&_h2]:text-foreground [&_h2]:first:mt-0",
13
+ h3: "[&_h3]:mt-5 [&_h3]:mb-2 [&_h3]:scroll-m-20 [&_h3]:text-h3 [&_h3]:text-foreground [&_h3]:first:mt-0",
14
+ h4: "[&_h4]:mt-4 [&_h4]:mb-2 [&_h4]:scroll-m-20 [&_h4]:text-h4 [&_h4]:text-foreground [&_h4]:first:mt-0",
15
+ // h5/h6 leave the display tier and become labels — the type scale has no sixth heading size.
16
+ h5: "[&_h5]:mt-4 [&_h5]:mb-2 [&_h5]:text-label [&_h5]:text-foreground [&_h5]:first:mt-0",
17
+ h6: "[&_h6]:mt-4 [&_h6]:mb-2 [&_h6]:text-label [&_h6]:text-muted-foreground [&_h6]:first:mt-0",
18
+ p: "[&_p]:my-3 [&_p]:leading-relaxed [&_p]:text-foreground [&_p]:first:mt-0 [&_p]:last:mb-0",
19
+ // Marks. Links are `info` ink per design.md §Colours; `s` is Tiptap's strike element and `del`
20
+ // is GFM's — the same mark from two producers.
21
+ a: "[&_a]:font-medium [&_a]:text-info-text [&_a]:underline [&_a]:underline-offset-4 [&_a]:hover:text-info-text/(--alpha-link-hover)",
22
+ strong: "[&_strong]:font-medium [&_strong]:text-foreground",
23
+ em: "[&_em]:italic",
24
+ del: "[&_del]:text-muted-foreground [&_del]:line-through [&_s]:text-muted-foreground [&_s]:line-through",
25
+ // Lists. A GFM task list carries `contains-task-list` and its checkbox IS the marker, so the
26
+ // disc goes — expressed as a second, more specific descendant rule rather than a class on the
27
+ // element, which would lose the cascade (see the header).
28
+ ul: "[&_ul]:my-3 [&_ul]:ms-6 [&_ul]:list-disc [&_ul]:text-foreground [&_ul]:marker:text-muted-foreground [&_ul.contains-task-list]:list-none",
29
+ ol: "[&_ol]:my-3 [&_ol]:ms-6 [&_ol]:list-decimal [&_ol]:text-foreground [&_ol]:marker:text-muted-foreground",
30
+ li: "[&_li]:mt-1.5 [&_li]:leading-relaxed",
31
+ blockquote: "[&_blockquote]:my-3 [&_blockquote]:border-s-2 [&_blockquote]:border-border [&_blockquote]:ps-4 [&_blockquote]:text-muted-foreground [&_blockquote]:italic",
32
+ // Inline code is a chip. Code inside a `pre` is not: it inherits the panel's ground, so the chip
33
+ // is undone at higher specificity (`[&_pre_code]` is (0,1,2) against the chip's (0,1,1)).
34
+ code: "[&_code]:rounded-sm [&_code]:bg-muted [&_code]:px-1.5 [&_code]:py-0.5 [&_code]:font-mono [&_code]:text-base [&_code]:text-foreground",
35
+ // A bare `<pre>` wears `CodeBlock`'s surface — the same sunken panel, one vocabulary (B4-09).
36
+ // `CodeBlock`'s own `pre` is excluded: it already sits inside a `figure` carrying the border,
37
+ // radius and ground, and re-applying them here would draw a second panel inside the first.
38
+ pre: "[&_pre:not([data-slot='code-block-pre'])]:my-3 [&_pre:not([data-slot='code-block-pre'])]:overflow-x-auto [&_pre:not([data-slot='code-block-pre'])]:rounded-lg [&_pre:not([data-slot='code-block-pre'])]:border [&_pre:not([data-slot='code-block-pre'])]:border-border [&_pre:not([data-slot='code-block-pre'])]:bg-muted [&_pre:not([data-slot='code-block-pre'])]:p-4 [&_pre:not([data-slot='code-block-pre'])]:text-foreground",
39
+ preCode: "[&_pre_code]:bg-transparent [&_pre_code]:p-0 [&_pre_code]:font-mono [&_pre_code]:text-code [&_pre_code]:text-foreground",
40
+ hr: "[&_hr]:my-6 [&_hr]:border-border",
41
+ // GFM tables. The scroll container is structural and belongs to the consumer (MarkdownView wraps
42
+ // the table in an `overflow-x-auto` div); these are the cell and rule tokens.
43
+ table: "[&_table]:w-full [&_table]:border-collapse [&_table]:text-base [&_table]:text-foreground [&_thead]:border-b [&_thead]:border-border [&_tr]:border-b [&_tr]:border-border [&_tr]:last:border-0 [&_th]:px-3 [&_th]:py-2 [&_th]:text-start [&_th]:font-medium [&_th]:text-foreground [&_td]:px-3 [&_td]:py-2 [&_td]:text-muted-foreground",
44
+ img: "[&_img]:my-3 [&_img]:max-w-full [&_img]:rounded-lg [&_img]:border [&_img]:border-border"
45
+ };
46
+ var proseClassName = Object.values(prose).join(" ");
47
+
48
+ // src/index.ts
49
+ var twMerge = extendTailwindMerge({
50
+ extend: {
51
+ classGroups: {
52
+ "font-size": [
53
+ {
54
+ text: [
55
+ "h1",
56
+ "h2",
57
+ "h3",
58
+ "h4",
59
+ "label",
60
+ "label-sm",
61
+ "code",
62
+ "code-sm",
63
+ "mono-label",
64
+ "display-sm",
65
+ "display-md",
66
+ "display-lg",
67
+ "display-xl"
68
+ ]
69
+ }
70
+ ]
71
+ }
72
+ }
73
+ });
74
+ function cn(...inputs) {
75
+ return twMerge(clsx(inputs));
76
+ }
77
+ var surfaceInteractive = "hover:bg-surface-2 active:bg-surface-3";
78
+ var surfaceInteractiveGroup = "group-hover/wash:bg-surface-2 group-active/wash:bg-surface-3";
79
+ var fillInteractive = {
80
+ foreground: "hover:bg-foreground/(--alpha-hover) active:bg-foreground/(--alpha-pressed)",
81
+ primary: "hover:bg-primary/(--alpha-hover) active:bg-primary/(--alpha-pressed)",
82
+ destructive: "hover:bg-destructive/(--alpha-hover) active:bg-destructive/(--alpha-pressed)",
83
+ success: "hover:bg-success/(--alpha-hover) active:bg-success/(--alpha-pressed)",
84
+ warning: "hover:bg-warning/(--alpha-hover) active:bg-warning/(--alpha-pressed)",
85
+ info: "hover:bg-info/(--alpha-hover) active:bg-info/(--alpha-pressed)",
86
+ brand: "hover:bg-brand/(--alpha-hover) active:bg-brand/(--alpha-pressed)"
87
+ };
88
+ var fieldControl = [
89
+ "rounded-md border border-input bg-transparent dark:bg-input/(--alpha-input)",
90
+ "placeholder:text-muted-foreground-faint",
91
+ "not-disabled:not-data-disabled:hover:border-foreground/(--alpha-border-subtle)",
92
+ "focus:border-ring/(--alpha-tint-border)",
93
+ "not-focus:aria-invalid:border-destructive-border/(--alpha-tint-border)",
94
+ "not-focus:data-invalid:border-destructive-border/(--alpha-tint-border)",
95
+ "disabled:cursor-not-allowed disabled:bg-surface-1 disabled:opacity-(--opacity-dim)",
96
+ "data-disabled:cursor-not-allowed data-disabled:bg-surface-1 data-disabled:opacity-(--opacity-dim)"
97
+ ].join(" ");
98
+ var fieldControlGroup = [
99
+ "rounded-md border border-input bg-transparent dark:bg-input/(--alpha-input)",
100
+ "not-has-disabled:not-data-disabled:hover:border-foreground/(--alpha-border-subtle)",
101
+ "focus-within:border-ring/(--alpha-tint-border)",
102
+ "data-focused:border-ring/(--alpha-tint-border)",
103
+ // Both the SELF and the DESCENDANT form of the invalid tint (2026-09-09). `has-aria-invalid:` is
104
+ // a `:has()` over descendants, so a group that carries `aria-invalid` on ITSELF — which is where
105
+ // `<NumberField aria-invalid />` lands the attribute, on the `[data-field-group]` element —
106
+ // matched nothing and measured the neutral `--input` border. Inside a `Field` the state arrives
107
+ // as `data-invalid` on the group and was always correct; this is the standalone path.
108
+ "not-focus-within:aria-invalid:border-destructive-border/(--alpha-tint-border)",
109
+ "not-focus-within:has-aria-invalid:border-destructive-border/(--alpha-tint-border)",
110
+ "not-focus-within:data-invalid:border-destructive-border/(--alpha-tint-border)",
111
+ "has-disabled:cursor-not-allowed has-disabled:bg-surface-1 has-disabled:opacity-(--opacity-dim)",
112
+ "data-disabled:cursor-not-allowed data-disabled:bg-surface-1 data-disabled:opacity-(--opacity-dim)"
113
+ ].join(" ");
114
+ var selectedChipVariants = {
115
+ /** The muted track the chips sit in — the ladder's well rung. */
116
+ track: "bg-surface-1",
117
+ /**
118
+ * Chrome shared by every chip: a transparent hairline reserved at rest (so selecting adds no
119
+ * layout shift) and the muted→ink text step.
120
+ */
121
+ item: "border border-transparent hover:text-foreground",
122
+ /** Selected keyed on Base UI's `data-pressed` — Toggle, ToggleGroup, Segmented. */
123
+ pressed: "not-data-pressed:hover:bg-foreground/(--alpha-hover) not-data-pressed:active:bg-foreground/(--alpha-pressed) data-pressed:border-border data-pressed:bg-foreground/(--alpha-ink-tint) data-pressed:text-foreground data-pressed:hover:bg-foreground/(--alpha-ink-tint-strong) data-pressed:active:bg-foreground/(--alpha-ink-tint)",
124
+ /** Selected keyed on Base UI's `data-active` — Tabs. */
125
+ active: "not-data-[active]:hover:bg-foreground/(--alpha-hover) not-data-[active]:active:bg-foreground/(--alpha-pressed) data-[active]:border-border data-[active]:bg-foreground/(--alpha-ink-tint) data-[active]:text-foreground data-[active]:hover:bg-foreground/(--alpha-ink-tint-strong) data-[active]:active:bg-foreground/(--alpha-ink-tint)"
126
+ };
127
+ var TIMINGS = {
128
+ /** How long transient success feedback holds before reverting (CopyButton "Copied ✓"). */
129
+ feedbackRevertMs: 1500,
130
+ /** Debounce before auto-persisting a text field (AutoSaveInput). */
131
+ autoSaveDebounceMs: 800,
132
+ /** Hover delay before a rich preview (HoverCard) opens — guards accidental opens. */
133
+ hoverOpenDelayMs: 700,
134
+ /** Hover delay before a rich preview closes — lets the pointer travel into the card. */
135
+ hoverCloseDelayMs: 300,
136
+ /**
137
+ * Hover delay before a tooltip opens. A tooltip is a cheap label, not a preview, so it is
138
+ * deliberately much faster than {@link TIMINGS.hoverOpenDelayMs} — long enough that sweeping
139
+ * across a toolbar does not flash five tips, short enough that a deliberate hover feels
140
+ * instant. Base UI's `Tooltip.Provider` grouping then opens adjacent tips with no delay at
141
+ * all. Set once, in the app-root provider.
142
+ */
143
+ tooltipOpenDelayMs: 300,
144
+ /**
145
+ * Delay before a tooltip closes. Zero: a tooltip has nothing to travel into (it is not
146
+ * hoverable content, unlike a HoverCard), so holding it after the pointer leaves only
147
+ * obscures what the user moved on to.
148
+ */
149
+ tooltipCloseDelayMs: 0
150
+ };
151
+ var FLOATING = {
152
+ sideOffsetAttached: 4,
153
+ sideOffsetDetached: 8,
154
+ collisionPadding: 8
155
+ };
156
+ function mergeRefs(...refs) {
157
+ return (node) => {
158
+ for (const ref of refs) {
159
+ if (ref == null) continue;
160
+ if (typeof ref === "function") {
161
+ ref(node);
162
+ } else {
163
+ ref.current = node;
164
+ }
165
+ }
166
+ };
167
+ }
168
+
169
+ export {
170
+ prose,
171
+ proseClassName,
172
+ cn,
173
+ surfaceInteractive,
174
+ surfaceInteractiveGroup,
175
+ fillInteractive,
176
+ fieldControl,
177
+ fieldControlGroup,
178
+ selectedChipVariants,
179
+ TIMINGS,
180
+ FLOATING,
181
+ mergeRefs
182
+ };
@@ -0,0 +1,437 @@
1
+ "use strict";
2
+ "use client";
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __export = (target, all) => {
10
+ for (var name in all)
11
+ __defProp(target, name, { get: all[name], enumerable: true });
12
+ };
13
+ var __copyProps = (to, from, except, desc) => {
14
+ if (from && typeof from === "object" || typeof from === "function") {
15
+ for (let key of __getOwnPropNames(from))
16
+ if (!__hasOwnProp.call(to, key) && key !== except)
17
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
18
+ }
19
+ return to;
20
+ };
21
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
22
+ // If the importer is in node compatibility mode or this is not an ESM
23
+ // file that has been converted to a CommonJS file using a Babel-
24
+ // compatible transform (i.e. "__esModule" has not been set), then set
25
+ // "default" to the CommonJS "module.exports" for node compatibility.
26
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
27
+ mod
28
+ ));
29
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
30
+
31
+ // src/icons/create-animated-icon.tsx
32
+ var create_animated_icon_exports = {};
33
+ __export(create_animated_icon_exports, {
34
+ ANIMATED_ICON_RESERVED_KEYS: () => ANIMATED_ICON_RESERVED_KEYS,
35
+ createAnimatedIcon: () => createAnimatedIcon
36
+ });
37
+ module.exports = __toCommonJS(create_animated_icon_exports);
38
+ var React = __toESM(require("react"), 1);
39
+ var import_react = require("motion/react");
40
+
41
+ // src/index.ts
42
+ var import_clsx = require("clsx");
43
+ var import_tailwind_merge = require("tailwind-merge");
44
+ var twMerge = (0, import_tailwind_merge.extendTailwindMerge)({
45
+ extend: {
46
+ classGroups: {
47
+ "font-size": [
48
+ {
49
+ text: [
50
+ "h1",
51
+ "h2",
52
+ "h3",
53
+ "h4",
54
+ "label",
55
+ "label-sm",
56
+ "code",
57
+ "code-sm",
58
+ "mono-label",
59
+ "display-sm",
60
+ "display-md",
61
+ "display-lg",
62
+ "display-xl"
63
+ ]
64
+ }
65
+ ]
66
+ }
67
+ }
68
+ });
69
+ function cn(...inputs) {
70
+ return twMerge((0, import_clsx.clsx)(inputs));
71
+ }
72
+ var fieldControl = [
73
+ "rounded-md border border-input bg-transparent dark:bg-input/(--alpha-input)",
74
+ "placeholder:text-muted-foreground-faint",
75
+ "not-disabled:not-data-disabled:hover:border-foreground/(--alpha-border-subtle)",
76
+ "focus:border-ring/(--alpha-tint-border)",
77
+ "not-focus:aria-invalid:border-destructive-border/(--alpha-tint-border)",
78
+ "not-focus:data-invalid:border-destructive-border/(--alpha-tint-border)",
79
+ "disabled:cursor-not-allowed disabled:bg-surface-1 disabled:opacity-(--opacity-dim)",
80
+ "data-disabled:cursor-not-allowed data-disabled:bg-surface-1 data-disabled:opacity-(--opacity-dim)"
81
+ ].join(" ");
82
+ var fieldControlGroup = [
83
+ "rounded-md border border-input bg-transparent dark:bg-input/(--alpha-input)",
84
+ "not-has-disabled:not-data-disabled:hover:border-foreground/(--alpha-border-subtle)",
85
+ "focus-within:border-ring/(--alpha-tint-border)",
86
+ "data-focused:border-ring/(--alpha-tint-border)",
87
+ // Both the SELF and the DESCENDANT form of the invalid tint (2026-09-09). `has-aria-invalid:` is
88
+ // a `:has()` over descendants, so a group that carries `aria-invalid` on ITSELF — which is where
89
+ // `<NumberField aria-invalid />` lands the attribute, on the `[data-field-group]` element —
90
+ // matched nothing and measured the neutral `--input` border. Inside a `Field` the state arrives
91
+ // as `data-invalid` on the group and was always correct; this is the standalone path.
92
+ "not-focus-within:aria-invalid:border-destructive-border/(--alpha-tint-border)",
93
+ "not-focus-within:has-aria-invalid:border-destructive-border/(--alpha-tint-border)",
94
+ "not-focus-within:data-invalid:border-destructive-border/(--alpha-tint-border)",
95
+ "has-disabled:cursor-not-allowed has-disabled:bg-surface-1 has-disabled:opacity-(--opacity-dim)",
96
+ "data-disabled:cursor-not-allowed data-disabled:bg-surface-1 data-disabled:opacity-(--opacity-dim)"
97
+ ].join(" ");
98
+
99
+ // src/icons/create-animated-icon.tsx
100
+ var import_jsx_runtime = require("react/jsx-runtime");
101
+ var REDUCED_MOTION_QUERY = "(prefers-reduced-motion: reduce)";
102
+ function subscribeToReducedMotion(onStoreChange) {
103
+ if (typeof window === "undefined" || typeof window.matchMedia !== "function")
104
+ return () => {
105
+ };
106
+ const query = window.matchMedia(REDUCED_MOTION_QUERY);
107
+ query.addEventListener("change", onStoreChange);
108
+ return () => query.removeEventListener("change", onStoreChange);
109
+ }
110
+ function readReducedMotion() {
111
+ if (typeof window === "undefined" || typeof window.matchMedia !== "function")
112
+ return false;
113
+ return window.matchMedia(REDUCED_MOTION_QUERY).matches;
114
+ }
115
+ function readReducedMotionOnServer() {
116
+ return false;
117
+ }
118
+ function useLiveReducedMotion() {
119
+ const preference = React.useSyncExternalStore(
120
+ subscribeToReducedMotion,
121
+ readReducedMotion,
122
+ readReducedMotionOnServer
123
+ );
124
+ const { reducedMotion } = React.useContext(import_react.MotionConfigContext);
125
+ if (reducedMotion === "always") return true;
126
+ return preference;
127
+ }
128
+ var TAGS = {
129
+ circle: "circle",
130
+ defs: "defs",
131
+ ellipse: "ellipse",
132
+ g: "g",
133
+ line: "line",
134
+ path: "path",
135
+ pattern: "pattern",
136
+ polygon: "polygon",
137
+ polyline: "polyline",
138
+ rect: "rect",
139
+ text: "text",
140
+ "motion.circle": import_react.motion.circle,
141
+ "motion.ellipse": import_react.motion.ellipse,
142
+ "motion.g": import_react.motion.g,
143
+ "motion.line": import_react.motion.line,
144
+ "motion.path": import_react.motion.path,
145
+ "motion.pattern": import_react.motion.pattern,
146
+ "motion.polygon": import_react.motion.polygon,
147
+ "motion.polyline": import_react.motion.polyline,
148
+ "motion.rect": import_react.motion.rect,
149
+ "motion.text": import_react.motion.text
150
+ };
151
+ var ANIMATED_ICON_RESERVED_KEYS = /* @__PURE__ */ new Set([
152
+ "animate",
153
+ "children",
154
+ "className",
155
+ "custom",
156
+ "exit",
157
+ "group",
158
+ "inherit",
159
+ "initial",
160
+ "style",
161
+ "tag",
162
+ "text",
163
+ "transition",
164
+ "variants"
165
+ ]);
166
+ var ROOT_DEFAULTS = {
167
+ viewBox: "0 0 24 24",
168
+ fill: "none",
169
+ stroke: "currentColor",
170
+ strokeWidth: "2",
171
+ strokeLinecap: "round",
172
+ strokeLinejoin: "round"
173
+ };
174
+ function isPresence(node) {
175
+ return typeof node === "object" && node.tag === "presence";
176
+ }
177
+ function isMotionTag(tag) {
178
+ return tag.startsWith("motion.");
179
+ }
180
+ function asNode(child) {
181
+ return typeof child === "string" ? { tag: "path", d: child } : child;
182
+ }
183
+ function specUsesControls(spec) {
184
+ if (spec.start || spec.stop) return true;
185
+ if (spec.svg?.tag === "motion.svg" && !spec.svg.inherit) return true;
186
+ const walk = (nodes) => nodes.some((child) => {
187
+ if (isPresence(child)) return false;
188
+ const node = asNode(child);
189
+ if (isMotionTag(node.tag) && !node.inherit && !node.animate) return true;
190
+ return node.children ? walk(node.children) : false;
191
+ });
192
+ return walk(spec.elements);
193
+ }
194
+ function hasPresenceNode(spec) {
195
+ return spec.elements.some(isPresence);
196
+ }
197
+ function svgAttributes(node) {
198
+ const attributes = {};
199
+ for (const [key, value] of Object.entries(node)) {
200
+ if (ANIMATED_ICON_RESERVED_KEYS.has(key)) continue;
201
+ if (value !== void 0) attributes[key] = value;
202
+ }
203
+ return attributes;
204
+ }
205
+ function renderNode(child, key, controls) {
206
+ const node = asNode(child);
207
+ const Tag = TAGS[node.tag];
208
+ const motionProps = isMotionTag(node.tag) ? {
209
+ animate: node.animate ?? (node.inherit ? void 0 : controls[node.group ?? "default"]),
210
+ initial: node.initial,
211
+ exit: node.exit,
212
+ variants: node.variants,
213
+ transition: node.transition,
214
+ custom: node.custom
215
+ } : void 0;
216
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
217
+ Tag,
218
+ {
219
+ ...svgAttributes(node),
220
+ className: node.className,
221
+ style: node.style,
222
+ ...motionProps,
223
+ children: [
224
+ node.text,
225
+ node.children?.map(
226
+ (grandchild, index) => renderNode(grandchild, index, controls)
227
+ )
228
+ ]
229
+ },
230
+ key
231
+ );
232
+ }
233
+ function createAnimatedIcon(spec) {
234
+ const groupNames = spec.groups ?? ["default"];
235
+ const usesControls = specUsesControls(spec);
236
+ const usesPresence = hasPresenceNode(spec);
237
+ const root = spec.svg ?? {};
238
+ const rootTag = root.tag ?? "svg";
239
+ const RootTag = rootTag === "motion.svg" ? import_react.motion.svg : "svg";
240
+ function AnimatedIconComponent({
241
+ className,
242
+ size = "var(--icon-default)",
243
+ ref,
244
+ onPointerEnter,
245
+ onPointerLeave,
246
+ onPointerDown,
247
+ onFocus,
248
+ onBlur,
249
+ ...props
250
+ }) {
251
+ const controlList = groupNames.map(() => (0, import_react.useAnimation)());
252
+ const shouldReduceMotion = useLiveReducedMotion();
253
+ const [isActive, setIsActive] = React.useState(false);
254
+ const reduceRef = React.useRef(shouldReduceMotion);
255
+ reduceRef.current = shouldReduceMotion;
256
+ const isControlledRef = React.useRef(false);
257
+ const timersRef = React.useRef([]);
258
+ const controls = React.useMemo(
259
+ () => Object.fromEntries(
260
+ groupNames.map((name, index) => [name, controlList[index]])
261
+ ),
262
+ // Each entry is referentially stable for the life of the component.
263
+ // eslint-disable-next-line react-hooks/exhaustive-deps
264
+ controlList
265
+ );
266
+ const clearTimers = React.useCallback(() => {
267
+ for (const timer of timersRef.current) clearTimeout(timer);
268
+ timersRef.current = [];
269
+ }, []);
270
+ React.useEffect(() => clearTimers, [clearTimers]);
271
+ const run = React.useCallback(
272
+ (control2, definition, transition) => {
273
+ if (reduceRef.current) {
274
+ control2.stop();
275
+ return Promise.resolve();
276
+ }
277
+ return Promise.resolve(control2.start(definition, transition)).then(
278
+ () => void 0,
279
+ () => void 0
280
+ );
281
+ },
282
+ []
283
+ );
284
+ const reset = React.useCallback(
285
+ (control2, definition, transition) => {
286
+ if (reduceRef.current) {
287
+ control2.stop();
288
+ control2.set(definition);
289
+ return Promise.resolve();
290
+ }
291
+ return Promise.resolve(control2.start(definition, transition)).then(
292
+ () => void 0,
293
+ () => void 0
294
+ );
295
+ },
296
+ []
297
+ );
298
+ const set = React.useCallback(
299
+ (control2, definition) => {
300
+ control2.stop();
301
+ control2.set(definition);
302
+ },
303
+ []
304
+ );
305
+ const after = React.useCallback(
306
+ (delayMs, task) => {
307
+ timersRef.current.push(setTimeout(task, delayMs));
308
+ },
309
+ []
310
+ );
311
+ const flagsRef = React.useRef({});
312
+ const control = React.useCallback(
313
+ (group) => {
314
+ const index = group ? groupNames.indexOf(group) : 0;
315
+ return controlList[index === -1 ? 0 : index];
316
+ },
317
+ // eslint-disable-next-line react-hooks/exhaustive-deps -- stable entries
318
+ controlList
319
+ );
320
+ const choreography = React.useMemo(
321
+ () => ({
322
+ control,
323
+ shouldReduceMotion,
324
+ run,
325
+ reset,
326
+ set,
327
+ after,
328
+ flags: flagsRef.current
329
+ }),
330
+ [control, shouldReduceMotion, run, reset, set, after]
331
+ );
332
+ const primaryControl = control();
333
+ const startAnimation = React.useCallback(() => {
334
+ clearTimers();
335
+ if (usesPresence) setIsActive(!reduceRef.current);
336
+ if (spec.start) {
337
+ void spec.start(choreography);
338
+ return;
339
+ }
340
+ if (usesControls) void run(primaryControl, "animate");
341
+ }, [choreography, clearTimers, run, primaryControl]);
342
+ const stopAnimation = React.useCallback(() => {
343
+ clearTimers();
344
+ if (usesPresence) setIsActive(false);
345
+ if (spec.stop) {
346
+ void spec.stop(choreography);
347
+ return;
348
+ }
349
+ if (usesControls) void reset(primaryControl, "normal");
350
+ }, [choreography, clearTimers, reset, primaryControl]);
351
+ React.useImperativeHandle(ref, () => {
352
+ isControlledRef.current = true;
353
+ return { startAnimation, stopAnimation };
354
+ });
355
+ React.useEffect(() => {
356
+ if (shouldReduceMotion) stopAnimation();
357
+ }, [shouldReduceMotion, stopAnimation]);
358
+ const handlePointerEnter = (event) => {
359
+ onPointerEnter?.(event);
360
+ if (!isControlledRef.current && event.pointerType !== "touch")
361
+ startAnimation();
362
+ };
363
+ const handlePointerLeave = (event) => {
364
+ onPointerLeave?.(event);
365
+ if (!isControlledRef.current && event.pointerType !== "touch")
366
+ stopAnimation();
367
+ };
368
+ const handlePointerDown = (event) => {
369
+ onPointerDown?.(event);
370
+ if (!isControlledRef.current && event.pointerType === "touch")
371
+ startAnimation();
372
+ };
373
+ const handleFocus = (event) => {
374
+ onFocus?.(event);
375
+ if (!isControlledRef.current) startAnimation();
376
+ };
377
+ const handleBlur = (event) => {
378
+ onBlur?.(event);
379
+ if (!isControlledRef.current) stopAnimation();
380
+ };
381
+ const rootMotionProps = rootTag === "motion.svg" ? {
382
+ animate: root.animate ?? (root.inherit ? void 0 : controls[root.group ?? "default"]),
383
+ initial: root.initial,
384
+ variants: root.variants,
385
+ transition: root.transition,
386
+ custom: root.custom
387
+ } : void 0;
388
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
389
+ "span",
390
+ {
391
+ className: cn(
392
+ "inline-flex shrink-0 items-center justify-center",
393
+ className
394
+ ),
395
+ onPointerEnter: handlePointerEnter,
396
+ onPointerLeave: handlePointerLeave,
397
+ onPointerDown: handlePointerDown,
398
+ onFocus: handleFocus,
399
+ onBlur: handleBlur,
400
+ ...props,
401
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
402
+ RootTag,
403
+ {
404
+ xmlns: "http://www.w3.org/2000/svg",
405
+ width: size,
406
+ height: size,
407
+ viewBox: root.viewBox ?? ROOT_DEFAULTS.viewBox,
408
+ fill: root.fill ?? ROOT_DEFAULTS.fill,
409
+ stroke: root.stroke ?? ROOT_DEFAULTS.stroke,
410
+ strokeWidth: root.strokeWidth ?? ROOT_DEFAULTS.strokeWidth,
411
+ strokeLinecap: root.strokeLinecap ?? ROOT_DEFAULTS.strokeLinecap,
412
+ strokeLinejoin: root.strokeLinejoin ?? ROOT_DEFAULTS.strokeLinejoin,
413
+ overflow: root.overflow,
414
+ className: root.className,
415
+ style: root.style,
416
+ ...rootMotionProps,
417
+ children: spec.elements.map((node, index) => {
418
+ if (!isPresence(node)) return renderNode(node, index, controls);
419
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react.AnimatePresence, { initial: false, mode: "wait", children: isActive ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(React.Fragment, { children: node.active.map(
420
+ (child, childIndex) => renderNode(child, childIndex, controls)
421
+ ) }, `${spec.name}-active`) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(React.Fragment, { children: node.rest.map(
422
+ (child, childIndex) => renderNode(child, childIndex, controls)
423
+ ) }, `${spec.name}-rest`) }, index);
424
+ })
425
+ }
426
+ )
427
+ }
428
+ );
429
+ }
430
+ AnimatedIconComponent.displayName = spec.name;
431
+ return AnimatedIconComponent;
432
+ }
433
+ // Annotate the CommonJS export names for ESM import in node:
434
+ 0 && (module.exports = {
435
+ ANIMATED_ICON_RESERVED_KEYS,
436
+ createAnimatedIcon
437
+ });