@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.
- package/bin/verify-registry-item.mjs +1 -0
- package/dist/chunk-LRQSVCP6.js +182 -0
- package/dist/create-animated-icon.cjs +437 -0
- package/dist/create-animated-icon.d.cts +210 -0
- package/dist/create-animated-icon.d.ts +210 -0
- package/dist/create-animated-icon.js +350 -0
- package/dist/icons/index.cjs +26 -0
- package/dist/icons/index.d.cts +15 -8
- package/dist/icons/index.d.ts +15 -8
- package/dist/icons/index.js +1 -1
- package/dist/index.cjs +142 -3
- package/dist/index.d.cts +273 -1
- package/dist/index.d.ts +273 -1
- package/dist/index.js +21 -3
- package/package.json +36 -25
- package/preset.css +1 -1
- package/skills/vegastack-consume/SKILL.md +5 -5
- package/skills/vegastack-design-audit/SKILL.md +3 -1
- package/skills/vegastack-design-system/SKILL.md +105 -3
- package/skills/vegastack-design-system/references/components.md +22 -16
- package/dist/chunk-FBU37ITM.js +0 -52
|
@@ -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
|
+
});
|