motionwind-vanilla 2.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 +39 -0
- package/dist/adapter.cjs +50 -0
- package/dist/adapter.cjs.map +1 -0
- package/dist/adapter.d.cts +27 -0
- package/dist/adapter.d.ts +27 -0
- package/dist/adapter.js +9 -0
- package/dist/adapter.js.map +1 -0
- package/dist/cdn/motionwind.global.js +2 -0
- package/dist/cdn/motionwind.global.js.map +1 -0
- package/dist/chunk-PXUTG4VI.js +25 -0
- package/dist/chunk-PXUTG4VI.js.map +1 -0
- package/dist/index.cjs +317 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +36 -0
- package/dist/index.d.ts +36 -0
- package/dist/index.js +279 -0
- package/dist/index.js.map +1 -0
- package/llms.txt +38 -0
- package/package.json +78 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
import {
|
|
2
|
+
VANILLA_CAPABILITIES,
|
|
3
|
+
vanillaAdapter
|
|
4
|
+
} from "./chunk-PXUTG4VI.js";
|
|
5
|
+
|
|
6
|
+
// src/index.ts
|
|
7
|
+
import { animate, hover, press, inView, scroll } from "motion";
|
|
8
|
+
import {
|
|
9
|
+
parseMotionClasses,
|
|
10
|
+
unsupportedCapabilities
|
|
11
|
+
} from "motionwind-core";
|
|
12
|
+
|
|
13
|
+
// src/map.ts
|
|
14
|
+
var RESET_DEFAULTS = {
|
|
15
|
+
scale: 1,
|
|
16
|
+
scaleX: 1,
|
|
17
|
+
scaleY: 1,
|
|
18
|
+
opacity: 1,
|
|
19
|
+
x: 0,
|
|
20
|
+
y: 0,
|
|
21
|
+
z: 0,
|
|
22
|
+
rotate: 0,
|
|
23
|
+
rotateX: 0,
|
|
24
|
+
rotateY: 0,
|
|
25
|
+
skewX: 0,
|
|
26
|
+
skewY: 0
|
|
27
|
+
};
|
|
28
|
+
var OPTION_KEYS = [
|
|
29
|
+
"duration",
|
|
30
|
+
"delay",
|
|
31
|
+
"ease",
|
|
32
|
+
"type",
|
|
33
|
+
"stiffness",
|
|
34
|
+
"damping",
|
|
35
|
+
"mass",
|
|
36
|
+
"bounce",
|
|
37
|
+
"repeat",
|
|
38
|
+
"repeatType",
|
|
39
|
+
"repeatDelay",
|
|
40
|
+
"times"
|
|
41
|
+
];
|
|
42
|
+
function toAnimateOptions(transition) {
|
|
43
|
+
const opts = {};
|
|
44
|
+
for (const key of OPTION_KEYS) {
|
|
45
|
+
if (transition[key] !== void 0) opts[key] = transition[key];
|
|
46
|
+
}
|
|
47
|
+
return opts;
|
|
48
|
+
}
|
|
49
|
+
function baseValues(parsed) {
|
|
50
|
+
const keys = /* @__PURE__ */ new Set();
|
|
51
|
+
for (const g of [
|
|
52
|
+
parsed.gestures.whileHover,
|
|
53
|
+
parsed.gestures.whileTap,
|
|
54
|
+
parsed.gestures.whileFocus,
|
|
55
|
+
parsed.gestures.whileInView
|
|
56
|
+
]) {
|
|
57
|
+
if (g) Object.keys(g).forEach((k) => keys.add(k));
|
|
58
|
+
}
|
|
59
|
+
const base = {};
|
|
60
|
+
const enter = parsed.gestures.animate;
|
|
61
|
+
const initial = parsed.gestures.initial;
|
|
62
|
+
for (const k of keys) {
|
|
63
|
+
const v = enter?.[k] ?? initial?.[k] ?? RESET_DEFAULTS[k] ?? 0;
|
|
64
|
+
base[k] = v;
|
|
65
|
+
}
|
|
66
|
+
return base;
|
|
67
|
+
}
|
|
68
|
+
function subset(values, shape) {
|
|
69
|
+
const out = {};
|
|
70
|
+
for (const k of Object.keys(shape)) {
|
|
71
|
+
if (values[k] !== void 0) out[k] = values[k];
|
|
72
|
+
}
|
|
73
|
+
return out;
|
|
74
|
+
}
|
|
75
|
+
function interactiveValues(parsed, state) {
|
|
76
|
+
return {
|
|
77
|
+
...baseValues(parsed),
|
|
78
|
+
...state.focused ? parsed.gestures.whileFocus : void 0,
|
|
79
|
+
...state.hovered ? parsed.gestures.whileHover : void 0,
|
|
80
|
+
...state.pressed ? parsed.gestures.whileTap : void 0
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// src/index.ts
|
|
85
|
+
import {
|
|
86
|
+
parseMotionClasses as parseMotionClasses2,
|
|
87
|
+
defineConfig,
|
|
88
|
+
definePreset,
|
|
89
|
+
defineMotionwindPlugin,
|
|
90
|
+
MOTIONWIND_RECIPES
|
|
91
|
+
} from "motionwind-core";
|
|
92
|
+
var anim = animate;
|
|
93
|
+
function prefersReducedMotion() {
|
|
94
|
+
return typeof window !== "undefined" && typeof window.matchMedia === "function" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
95
|
+
}
|
|
96
|
+
function resolveGestures(parsed) {
|
|
97
|
+
const { variants, variantState, gestures } = parsed;
|
|
98
|
+
const hasVariants = Object.keys(variants).length > 0;
|
|
99
|
+
return {
|
|
100
|
+
initial: (hasVariants && variantState.initial ? variants[variantState.initial] : void 0) ?? gestures.initial,
|
|
101
|
+
animate: (hasVariants && variantState.animate ? variants[variantState.animate] : void 0) ?? gestures.animate,
|
|
102
|
+
exit: (hasVariants && variantState.exit ? variants[variantState.exit] : void 0) ?? gestures.exit
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
function wireElement(el, parsed, reduce) {
|
|
106
|
+
const opts = toAnimateOptions(parsed.transition);
|
|
107
|
+
const base = baseValues(parsed);
|
|
108
|
+
const cleanups = [];
|
|
109
|
+
const resolved = resolveGestures(parsed);
|
|
110
|
+
const whileHover = parsed.gestures.whileHover;
|
|
111
|
+
const whileTap = parsed.gestures.whileTap;
|
|
112
|
+
const whileFocus = parsed.gestures.whileFocus;
|
|
113
|
+
let hovered = false;
|
|
114
|
+
let pressed = false;
|
|
115
|
+
let focused = false;
|
|
116
|
+
const updateInteractive = () => {
|
|
117
|
+
const target = interactiveValues(parsed, { focused, hovered, pressed });
|
|
118
|
+
if (Object.keys(target).length > 0) anim(el, target, opts);
|
|
119
|
+
};
|
|
120
|
+
if (parsed.tailwindClasses) {
|
|
121
|
+
el.setAttribute("class", parsed.tailwindClasses);
|
|
122
|
+
} else {
|
|
123
|
+
el.removeAttribute("class");
|
|
124
|
+
}
|
|
125
|
+
if (reduce) {
|
|
126
|
+
const rest = {
|
|
127
|
+
...resolved.animate ?? {},
|
|
128
|
+
...parsed.gestures.whileInView ?? {}
|
|
129
|
+
};
|
|
130
|
+
if (Object.keys(rest).length > 0) anim(el, rest, { duration: 0 });
|
|
131
|
+
return () => {
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
if (resolved.initial) anim(el, resolved.initial, { duration: 0 });
|
|
135
|
+
if (resolved.animate) anim(el, resolved.animate, opts);
|
|
136
|
+
const exitValues = resolved.exit;
|
|
137
|
+
if (exitValues && Object.keys(exitValues).length > 0) {
|
|
138
|
+
const handleRemove = () => {
|
|
139
|
+
anim(el, exitValues, {
|
|
140
|
+
...opts,
|
|
141
|
+
onComplete: () => el.remove()
|
|
142
|
+
});
|
|
143
|
+
};
|
|
144
|
+
el.addEventListener("motionwind:remove", handleRemove);
|
|
145
|
+
cleanups.push(
|
|
146
|
+
() => el.removeEventListener(
|
|
147
|
+
"motionwind:remove",
|
|
148
|
+
handleRemove
|
|
149
|
+
)
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
if (whileHover) {
|
|
153
|
+
cleanups.push(
|
|
154
|
+
hover(el, () => {
|
|
155
|
+
hovered = true;
|
|
156
|
+
updateInteractive();
|
|
157
|
+
return () => {
|
|
158
|
+
hovered = false;
|
|
159
|
+
updateInteractive();
|
|
160
|
+
};
|
|
161
|
+
})
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
if (whileTap) {
|
|
165
|
+
cleanups.push(
|
|
166
|
+
press(el, () => {
|
|
167
|
+
pressed = true;
|
|
168
|
+
updateInteractive();
|
|
169
|
+
return () => {
|
|
170
|
+
pressed = false;
|
|
171
|
+
updateInteractive();
|
|
172
|
+
};
|
|
173
|
+
})
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
if (whileFocus) {
|
|
177
|
+
const onFocus = () => {
|
|
178
|
+
focused = true;
|
|
179
|
+
updateInteractive();
|
|
180
|
+
};
|
|
181
|
+
const onBlur = () => {
|
|
182
|
+
focused = false;
|
|
183
|
+
updateInteractive();
|
|
184
|
+
};
|
|
185
|
+
el.addEventListener("focus", onFocus);
|
|
186
|
+
el.addEventListener("blur", onBlur);
|
|
187
|
+
cleanups.push(() => {
|
|
188
|
+
el.removeEventListener("focus", onFocus);
|
|
189
|
+
el.removeEventListener("blur", onBlur);
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
const whileInView = parsed.gestures.whileInView;
|
|
193
|
+
if (whileInView) {
|
|
194
|
+
const viewportOpts = {};
|
|
195
|
+
if (parsed.viewport.amount !== void 0)
|
|
196
|
+
viewportOpts.amount = parsed.viewport.amount;
|
|
197
|
+
if (parsed.viewport.margin !== void 0)
|
|
198
|
+
viewportOpts.margin = parsed.viewport.margin;
|
|
199
|
+
cleanups.push(
|
|
200
|
+
inView(
|
|
201
|
+
el,
|
|
202
|
+
() => {
|
|
203
|
+
anim(el, whileInView, opts);
|
|
204
|
+
if (parsed.viewport.once) return;
|
|
205
|
+
return () => anim(el, subset(base, whileInView), opts);
|
|
206
|
+
},
|
|
207
|
+
viewportOpts
|
|
208
|
+
)
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
if (Object.keys(parsed.scroll.values).length > 0) {
|
|
212
|
+
const scrollOpts = parsed.scroll.container ? { axis: parsed.scroll.axis } : { target: el, axis: parsed.scroll.axis, offset: parsed.scroll.offset };
|
|
213
|
+
const stop = scroll(
|
|
214
|
+
anim(el, parsed.scroll.values, { ease: "linear" }),
|
|
215
|
+
scrollOpts
|
|
216
|
+
);
|
|
217
|
+
if (typeof stop === "function") cleanups.push(stop);
|
|
218
|
+
}
|
|
219
|
+
return () => cleanups.forEach((fn) => fn());
|
|
220
|
+
}
|
|
221
|
+
function motionwind(options = {}) {
|
|
222
|
+
const root = options.root ?? (typeof document !== "undefined" ? document : null);
|
|
223
|
+
if (!root) return () => {
|
|
224
|
+
};
|
|
225
|
+
const selector = options.selector ?? '[class*="animate-"]';
|
|
226
|
+
const reduce = (options.respectReducedMotion ?? true) && prefersReducedMotion();
|
|
227
|
+
const cleanups = [];
|
|
228
|
+
const wire = (el) => {
|
|
229
|
+
try {
|
|
230
|
+
const parsed = parseMotionClasses(
|
|
231
|
+
el.getAttribute("class") ?? "",
|
|
232
|
+
options.config
|
|
233
|
+
);
|
|
234
|
+
const unsupported = unsupportedCapabilities(parsed, VANILLA_CAPABILITIES);
|
|
235
|
+
if (unsupported.length && typeof console !== "undefined") {
|
|
236
|
+
console.warn(
|
|
237
|
+
`[motionwind-vanilla] Unsupported capabilities: ${unsupported.join(", ")}.`,
|
|
238
|
+
el
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
if (parsed.hasMotion) cleanups.push(wireElement(el, parsed, reduce));
|
|
242
|
+
} catch (err) {
|
|
243
|
+
if (typeof console !== "undefined") {
|
|
244
|
+
console.warn(
|
|
245
|
+
"[motionwind-vanilla] failed to animate an element; skipping it.",
|
|
246
|
+
el,
|
|
247
|
+
err
|
|
248
|
+
);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
};
|
|
252
|
+
root.querySelectorAll(selector).forEach(wire);
|
|
253
|
+
if (options.observe && typeof MutationObserver !== "undefined") {
|
|
254
|
+
const target = root instanceof Document ? root.body ?? root.documentElement : root;
|
|
255
|
+
const observer = new MutationObserver((mutations) => {
|
|
256
|
+
for (const m of mutations) {
|
|
257
|
+
m.addedNodes.forEach((node) => {
|
|
258
|
+
if (!(node instanceof Element)) return;
|
|
259
|
+
if (node.matches(selector)) wire(node);
|
|
260
|
+
node.querySelectorAll(selector).forEach(wire);
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
});
|
|
264
|
+
observer.observe(target, { childList: true, subtree: true });
|
|
265
|
+
cleanups.push(() => observer.disconnect());
|
|
266
|
+
}
|
|
267
|
+
return () => cleanups.forEach((fn) => fn());
|
|
268
|
+
}
|
|
269
|
+
export {
|
|
270
|
+
MOTIONWIND_RECIPES,
|
|
271
|
+
VANILLA_CAPABILITIES,
|
|
272
|
+
defineConfig,
|
|
273
|
+
defineMotionwindPlugin,
|
|
274
|
+
definePreset,
|
|
275
|
+
motionwind,
|
|
276
|
+
parseMotionClasses2 as parseMotionClasses,
|
|
277
|
+
vanillaAdapter
|
|
278
|
+
};
|
|
279
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/map.ts"],"sourcesContent":["import { animate, hover, press, inView, scroll } from \"motion\";\nimport {\n parseMotionClasses,\n unsupportedCapabilities,\n type MotionwindConfig,\n type ParsedResult,\n type AnimatableValues,\n} from \"motionwind-core\";\nimport {\n toAnimateOptions,\n baseValues,\n interactiveValues,\n subset,\n} from \"./map.js\";\nimport { VANILLA_CAPABILITIES } from \"./adapter.js\";\n\nexport { vanillaAdapter, VANILLA_CAPABILITIES } from \"./adapter.js\";\n\nexport interface MotionwindOptions {\n /** Where to scan for motion elements. Defaults to `document`. */\n root?: ParentNode;\n /** Selector for candidate elements. Defaults to `[class*=\"animate-\"]`. */\n selector?: string;\n /** Honor `prefers-reduced-motion` (jump to final state, no motion). Default true. */\n respectReducedMotion?: boolean;\n /** Watch the DOM and wire elements added after init (SPA/HTMX). Default false. */\n observe?: boolean;\n /** Project tokens, presets, plugins, and strictness. */\n config?: MotionwindConfig;\n}\n\nconst anim = animate as any;\n\nfunction prefersReducedMotion(): boolean {\n return (\n typeof window !== \"undefined\" &&\n typeof window.matchMedia === \"function\" &&\n window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches\n );\n}\n\n/**\n * Resolve the initial/animate/exit gesture values for an element, preferring\n * named-variant values from `parsed.variants` when `parsed.variantState`\n * references them, and falling back to the inline gesture values otherwise.\n */\nfunction resolveGestures(parsed: ParsedResult): {\n initial?: AnimatableValues;\n animate?: AnimatableValues;\n exit?: AnimatableValues;\n} {\n const { variants, variantState, gestures } = parsed;\n const hasVariants = Object.keys(variants).length > 0;\n return {\n initial:\n (hasVariants && variantState.initial\n ? variants[variantState.initial]\n : undefined) ?? gestures.initial,\n animate:\n (hasVariants && variantState.animate\n ? variants[variantState.animate]\n : undefined) ?? gestures.animate,\n exit:\n (hasVariants && variantState.exit\n ? variants[variantState.exit]\n : undefined) ?? gestures.exit,\n };\n}\n\n/** Wire a single element's gestures/enter/scroll animations. Returns cleanup. */\nfunction wireElement(\n el: Element,\n parsed: ParsedResult,\n reduce: boolean,\n): () => void {\n const opts = toAnimateOptions(parsed.transition);\n const base = baseValues(parsed);\n const cleanups: Array<() => void> = [];\n const resolved = resolveGestures(parsed);\n const whileHover = parsed.gestures.whileHover;\n const whileTap = parsed.gestures.whileTap;\n const whileFocus = parsed.gestures.whileFocus;\n let hovered = false;\n let pressed = false;\n let focused = false;\n const updateInteractive = () => {\n const target = interactiveValues(parsed, { focused, hovered, pressed });\n if (Object.keys(target).length > 0) anim(el, target, opts);\n };\n\n // Strip animate-* classes; keep the passthrough (Tailwind/util) classes. This\n // also makes re-scans idempotent — a wired element no longer matches the\n // `animate-*` selector.\n if (parsed.tailwindClasses) {\n el.setAttribute(\"class\", parsed.tailwindClasses);\n } else {\n el.removeAttribute(\"class\");\n }\n\n // Reduced motion: jump straight to the final resting/visible state with no\n // animation, and skip all interactive + scroll wiring.\n if (reduce) {\n const rest = {\n ...(resolved.animate ?? {}),\n ...(parsed.gestures.whileInView ?? {}),\n };\n if (Object.keys(rest).length > 0) anim(el, rest, { duration: 0 });\n return () => {};\n }\n\n // Initial state (applied instantly), then enter animation.\n // Use resolved values so that named variants are applied correctly.\n if (resolved.initial) anim(el, resolved.initial, { duration: 0 });\n if (resolved.animate) anim(el, resolved.animate, opts);\n\n // Exit animation: when a consumer dispatches a custom \"motionwind:remove\"\n // event on the element, we play the exit keyframes and remove it afterwards.\n const exitValues = resolved.exit;\n if (exitValues && Object.keys(exitValues).length > 0) {\n const handleRemove = () => {\n anim(el, exitValues, {\n ...opts,\n onComplete: () => el.remove(),\n });\n };\n el.addEventListener(\"motionwind:remove\", handleRemove as EventListener);\n cleanups.push(() =>\n el.removeEventListener(\n \"motionwind:remove\",\n handleRemove as EventListener,\n ),\n );\n }\n\n // Hover\n if (whileHover) {\n cleanups.push(\n hover(el, () => {\n hovered = true;\n updateInteractive();\n return () => {\n hovered = false;\n updateInteractive();\n };\n }),\n );\n }\n\n // Tap / press\n if (whileTap) {\n cleanups.push(\n press(el, () => {\n pressed = true;\n updateInteractive();\n return () => {\n pressed = false;\n updateInteractive();\n };\n }),\n );\n }\n\n // Focus\n if (whileFocus) {\n const onFocus = () => {\n focused = true;\n updateInteractive();\n };\n const onBlur = () => {\n focused = false;\n updateInteractive();\n };\n el.addEventListener(\"focus\", onFocus);\n el.addEventListener(\"blur\", onBlur);\n cleanups.push(() => {\n el.removeEventListener(\"focus\", onFocus);\n el.removeEventListener(\"blur\", onBlur);\n });\n }\n\n // In view\n const whileInView = parsed.gestures.whileInView;\n if (whileInView) {\n const viewportOpts: Record<string, unknown> = {};\n if (parsed.viewport.amount !== undefined)\n viewportOpts.amount = parsed.viewport.amount;\n if (parsed.viewport.margin !== undefined)\n viewportOpts.margin = parsed.viewport.margin;\n cleanups.push(\n inView(\n el,\n () => {\n anim(el, whileInView, opts);\n if (parsed.viewport.once) return;\n return () => anim(el, subset(base, whileInView), opts);\n },\n viewportOpts,\n ),\n );\n }\n\n // Scroll-linked: drive style values from scroll progress.\n if (Object.keys(parsed.scroll.values).length > 0) {\n // Motion's ScrollOptions.offset is a strict string union; our offset is\n // user-provided, so cast the options bag.\n const scrollOpts: any = parsed.scroll.container\n ? { axis: parsed.scroll.axis }\n : { target: el, axis: parsed.scroll.axis, offset: parsed.scroll.offset };\n const stop = scroll(\n anim(el, parsed.scroll.values, { ease: \"linear\" }),\n scrollOpts,\n );\n if (typeof stop === \"function\") cleanups.push(stop);\n }\n\n return () => cleanups.forEach((fn) => fn());\n}\n\n/**\n * Scan the DOM for elements with `animate-*` classes and wire up their\n * animations using the vanilla Motion API. Returns a cleanup function.\n *\n * Supports: initial/enter, hover, tap, focus, in-view, scroll-linked, named\n * variants (resolved at wire-up time), and exit animations (triggered by\n * dispatching a `\"motionwind:remove\"` custom event on the element).\n * Honors `prefers-reduced-motion`, is idempotent across re-runs, and can watch\n * for dynamically-added elements via `{ observe: true }`.\n * (drag and layout are React/Vue-only.)\n *\n * @example\n * ```js\n * import { motionwind } from \"motionwind-vanilla\";\n * const stop = motionwind({ observe: true });\n * ```\n */\nexport function motionwind(options: MotionwindOptions = {}): () => void {\n const root =\n options.root ?? (typeof document !== \"undefined\" ? document : null);\n if (!root) return () => {};\n\n const selector = options.selector ?? '[class*=\"animate-\"]';\n const reduce =\n (options.respectReducedMotion ?? true) && prefersReducedMotion();\n const cleanups: Array<() => void> = [];\n\n const wire = (el: Element) => {\n try {\n // SVGElement.className is SVGAnimatedString rather than a string, so the\n // attribute is the portable source for both HTML and SVG elements.\n const parsed = parseMotionClasses(\n el.getAttribute(\"class\") ?? \"\",\n options.config,\n );\n const unsupported = unsupportedCapabilities(parsed, VANILLA_CAPABILITIES);\n if (unsupported.length && typeof console !== \"undefined\") {\n console.warn(\n `[motionwind-vanilla] Unsupported capabilities: ${unsupported.join(\", \")}.`,\n el,\n );\n }\n if (parsed.hasMotion) cleanups.push(wireElement(el, parsed, reduce));\n } catch (err) {\n // A single malformed element/class must never break the whole page.\n if (typeof console !== \"undefined\") {\n console.warn(\n \"[motionwind-vanilla] failed to animate an element; skipping it.\",\n el,\n err,\n );\n }\n }\n };\n\n root.querySelectorAll<Element>(selector).forEach(wire);\n\n if (options.observe && typeof MutationObserver !== \"undefined\") {\n const target =\n root instanceof Document ? (root.body ?? root.documentElement) : root;\n const observer = new MutationObserver((mutations) => {\n for (const m of mutations) {\n m.addedNodes.forEach((node) => {\n if (!(node instanceof Element)) return;\n if (node.matches(selector)) wire(node);\n node.querySelectorAll<Element>(selector).forEach(wire);\n });\n }\n });\n observer.observe(target as Node, { childList: true, subtree: true });\n cleanups.push(() => observer.disconnect());\n }\n\n return () => cleanups.forEach((fn) => fn());\n}\n\nexport {\n parseMotionClasses,\n defineConfig,\n definePreset,\n defineMotionwindPlugin,\n MOTIONWIND_RECIPES,\n} from \"motionwind-core\";\nexport type { ParsedResult, MotionwindConfig } from \"motionwind-core\";\n","import type {\n AnimatableValues,\n ParsedResult,\n TransitionConfig,\n} from \"motionwind-core\";\n\n/** Resting values used to animate back after a gesture ends. */\nconst RESET_DEFAULTS: Record<string, number | string> = {\n scale: 1,\n scaleX: 1,\n scaleY: 1,\n opacity: 1,\n x: 0,\n y: 0,\n z: 0,\n rotate: 0,\n rotateX: 0,\n rotateY: 0,\n skewX: 0,\n skewY: 0,\n};\n\n/** Transition keys that apply to a single vanilla `animate()` call. */\nconst OPTION_KEYS: (keyof TransitionConfig)[] = [\n \"duration\",\n \"delay\",\n \"ease\",\n \"type\",\n \"stiffness\",\n \"damping\",\n \"mass\",\n \"bounce\",\n \"repeat\",\n \"repeatType\",\n \"repeatDelay\",\n \"times\",\n];\n\n/** Project our TransitionConfig onto vanilla Motion's animate() options. */\nexport function toAnimateOptions(\n transition: TransitionConfig,\n): Record<string, unknown> {\n const opts: Record<string, unknown> = {};\n for (const key of OPTION_KEYS) {\n if (transition[key] !== undefined) opts[key] = transition[key];\n }\n return opts;\n}\n\n/**\n * Build the resting values to animate back to when a gesture (hover/tap/focus)\n * ends. Prefers the enter (`animate`) value, then `initial`, then a sensible\n * default, for each key the gestures touch.\n */\nexport function baseValues(parsed: ParsedResult): AnimatableValues {\n const keys = new Set<string>();\n for (const g of [\n parsed.gestures.whileHover,\n parsed.gestures.whileTap,\n parsed.gestures.whileFocus,\n parsed.gestures.whileInView,\n ]) {\n if (g) Object.keys(g).forEach((k) => keys.add(k));\n }\n\n const base: AnimatableValues = {};\n const enter = parsed.gestures.animate;\n const initial = parsed.gestures.initial;\n for (const k of keys) {\n const v =\n (enter as Record<string, AnimatableValues[string]> | undefined)?.[k] ??\n (initial as Record<string, AnimatableValues[string]> | undefined)?.[k] ??\n RESET_DEFAULTS[k] ??\n 0;\n base[k] = v;\n }\n return base;\n}\n\n/** Pick a subset of `values` limited to the keys present in `shape`. */\nexport function subset(\n values: AnimatableValues,\n shape: AnimatableValues,\n): AnimatableValues {\n const out: AnimatableValues = {};\n for (const k of Object.keys(shape)) {\n if (values[k] !== undefined) out[k] = values[k]!;\n }\n return out;\n}\n\n/** Merge concurrent gesture states using Motion's interaction priority. */\nexport function interactiveValues(\n parsed: ParsedResult,\n state: { focused: boolean; hovered: boolean; pressed: boolean },\n): AnimatableValues {\n return {\n ...baseValues(parsed),\n ...(state.focused ? parsed.gestures.whileFocus : undefined),\n ...(state.hovered ? parsed.gestures.whileHover : undefined),\n ...(state.pressed ? parsed.gestures.whileTap : undefined),\n };\n}\n"],"mappings":"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","names":["parseMotionClasses"]}
|
package/llms.txt
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# motionwind-vanilla v2.0.0 — machine reference
|
|
2
|
+
|
|
3
|
+
Stable browser DOM adapter backed by Motion and motionwind-core.
|
|
4
|
+
|
|
5
|
+
Install:
|
|
6
|
+
npm install motionwind-vanilla@2 motion motionwind-core@2
|
|
7
|
+
|
|
8
|
+
```js
|
|
9
|
+
import { motionwind } from "motionwind-vanilla";
|
|
10
|
+
|
|
11
|
+
const stop = motionwind({
|
|
12
|
+
root: document,
|
|
13
|
+
selector: '[class*="animate-"]',
|
|
14
|
+
observe: true,
|
|
15
|
+
respectReducedMotion: true,
|
|
16
|
+
config,
|
|
17
|
+
});
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
The return value removes listeners/observers. The self-contained CDN bundle at
|
|
21
|
+
https://unpkg.com/motionwind-vanilla@2 initializes automatically.
|
|
22
|
+
|
|
23
|
+
Supported: initial/enter, hover, press/tap, focus, in-view, continuous scroll,
|
|
24
|
+
SVG path values, reduced motion, HTML/SVG class attributes, and observed DOM
|
|
25
|
+
insertions.
|
|
26
|
+
|
|
27
|
+
Reduced motion jumps to the resting/visible state and does not wire interactive
|
|
28
|
+
or scroll behavior. Interaction priority is press, then hover, then focus, then
|
|
29
|
+
the base state.
|
|
30
|
+
|
|
31
|
+
Not supported: drag, layout projection, exit orchestration, and variant
|
|
32
|
+
propagation. These require a component runtime and produce capability warnings.
|
|
33
|
+
|
|
34
|
+
The adapter strips recognized animate-* tokens after wiring while preserving
|
|
35
|
+
ordinary classes. Re-scanning is idempotent.
|
|
36
|
+
|
|
37
|
+
Use motionwind-core's registry and parser diagnostics; do not maintain a second
|
|
38
|
+
syntax list.
|
package/package.json
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "motionwind-vanilla",
|
|
3
|
+
"version": "2.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"sideEffects": false,
|
|
6
|
+
"description": "Write Motion animations as Tailwind-like classes in plain HTML/JS — scans the DOM and wires animations via the vanilla Motion API.",
|
|
7
|
+
"author": "piyush555",
|
|
8
|
+
"license": "MIT",
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "https://github.com/piyushzingade/motionwind.git",
|
|
12
|
+
"directory": "packages/motionwind-vanilla"
|
|
13
|
+
},
|
|
14
|
+
"bugs": {
|
|
15
|
+
"url": "https://github.com/piyushzingade/motionwind/issues"
|
|
16
|
+
},
|
|
17
|
+
"homepage": "https://github.com/piyushzingade/motionwind#readme",
|
|
18
|
+
"keywords": [
|
|
19
|
+
"motion",
|
|
20
|
+
"animation",
|
|
21
|
+
"tailwind",
|
|
22
|
+
"vanilla",
|
|
23
|
+
"cdn",
|
|
24
|
+
"motionwind"
|
|
25
|
+
],
|
|
26
|
+
"exports": {
|
|
27
|
+
".": {
|
|
28
|
+
"import": "./dist/index.js",
|
|
29
|
+
"require": "./dist/index.cjs"
|
|
30
|
+
},
|
|
31
|
+
"./adapter": {
|
|
32
|
+
"import": "./dist/adapter.js",
|
|
33
|
+
"require": "./dist/adapter.cjs"
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
"main": "./dist/index.cjs",
|
|
37
|
+
"module": "./dist/index.js",
|
|
38
|
+
"types": "./dist/index.d.ts",
|
|
39
|
+
"typesVersions": {
|
|
40
|
+
"*": {
|
|
41
|
+
"adapter": [
|
|
42
|
+
"./dist/adapter.d.ts"
|
|
43
|
+
]
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
"unpkg": "./dist/cdn/motionwind.global.js",
|
|
47
|
+
"jsdelivr": "./dist/cdn/motionwind.global.js",
|
|
48
|
+
"files": [
|
|
49
|
+
"dist",
|
|
50
|
+
"llms.txt"
|
|
51
|
+
],
|
|
52
|
+
"scripts": {
|
|
53
|
+
"build": "tsup",
|
|
54
|
+
"dev": "tsup --watch",
|
|
55
|
+
"test": "vitest run",
|
|
56
|
+
"test:watch": "vitest",
|
|
57
|
+
"lint": "eslint --max-warnings 0",
|
|
58
|
+
"check-types": "tsc --noEmit"
|
|
59
|
+
},
|
|
60
|
+
"peerDependencies": {
|
|
61
|
+
"motion": "^11.0.0 || ^12.0.0 || ^13.0.0"
|
|
62
|
+
},
|
|
63
|
+
"dependencies": {
|
|
64
|
+
"motionwind-core": "^2.1.0"
|
|
65
|
+
},
|
|
66
|
+
"devDependencies": {
|
|
67
|
+
"@repo/eslint-config": "*",
|
|
68
|
+
"@repo/typescript-config": "*",
|
|
69
|
+
"eslint": "^9.39.1",
|
|
70
|
+
"motion": "^13.4.0",
|
|
71
|
+
"tsup": "^8.5.0",
|
|
72
|
+
"typescript": "5.9.2",
|
|
73
|
+
"vitest": "^3.2.1"
|
|
74
|
+
},
|
|
75
|
+
"publishConfig": {
|
|
76
|
+
"access": "public"
|
|
77
|
+
}
|
|
78
|
+
}
|