@aphrody/m3-motion 3.3.1 → 3.3.3

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/dist/index.js CHANGED
@@ -1,9 +1,5 @@
1
1
  'use client';
2
- import * as React5 from 'react';
3
- import { motion, AnimatePresence, useAnimate } from 'motion/react';
4
- import { jsx } from 'react/jsx-runtime';
5
-
6
- // src/springs.ts
2
+ // packages/m3-motion/src/springs.ts
7
3
  var m3Springs = {
8
4
  fast: {
9
5
  spatial: {
@@ -48,10 +44,8 @@ var m3Springs = {
48
44
  }
49
45
  }
50
46
  };
51
-
52
- // src/easings.ts
47
+ // packages/m3-motion/src/easings.ts
53
48
  var m3Easings = {
54
- /** Closest single-bezier approximation. Use emphasizedDecelerate/Accelerate for transitions. */
55
49
  emphasized: [0.2, 0, 0, 1],
56
50
  emphasizedDecelerate: [0.05, 0.7, 0.1, 1],
57
51
  emphasizedAccelerate: [0.3, 0, 0.8, 0.15],
@@ -59,7 +53,6 @@ var m3Easings = {
59
53
  standardDecelerate: [0, 0, 0, 1],
60
54
  standardAccelerate: [0.3, 0, 1, 1],
61
55
  linear: [0, 0, 1, 1],
62
- /** Legacy (M2 default) — kept for migration compatibility. */
63
56
  legacy: [0.4, 0, 0.2, 1],
64
57
  legacyDecelerate: [0, 0, 0.2, 1],
65
58
  legacyAccelerate: [0.4, 0, 1, 1]
@@ -82,16 +75,17 @@ var m3Durations = {
82
75
  extraLong3: 0.9,
83
76
  extraLong4: 1
84
77
  };
85
-
86
- // src/spring-interpolation.ts
78
+ // packages/m3-motion/src/spring-interpolation.ts
87
79
  var MIN_DURATION_MS = 50;
88
- var MAX_DURATION_MS = 2e3;
89
- var SETTLE_THRESHOLD = 5e-3;
80
+ var MAX_DURATION_MS = 2000;
81
+ var SETTLE_THRESHOLD = 0.005;
90
82
  var DEFAULT_MASS = 1;
91
83
  var DEFAULT_STEPS = 60;
92
84
  function clamp(value, min, max) {
93
- if (value < min) return min;
94
- if (value > max) return max;
85
+ if (value < min)
86
+ return min;
87
+ if (value > max)
88
+ return max;
95
89
  return value;
96
90
  }
97
91
  function normalize(params) {
@@ -122,15 +116,15 @@ function springDurationMs(params) {
122
116
  return MAX_DURATION_MS;
123
117
  }
124
118
  const settleSeconds = -Math.log(SETTLE_THRESHOLD) / decayRate;
125
- const settleMs = settleSeconds * 1e3;
119
+ const settleMs = settleSeconds * 1000;
126
120
  return clamp(settleMs, MIN_DURATION_MS, MAX_DURATION_MS);
127
121
  }
128
122
  function springToCssEasing(params) {
129
123
  const { k, c, m } = normalize(params);
130
124
  const zeta = dampingRatio(k, c, m);
131
125
  if (zeta < 0.85) {
132
- const [x12, y12, x22, y22] = [0.05, 0.7, 0.1, 1];
133
- return `cubic-bezier(${x12}, ${y12}, ${x22}, ${y22})`;
126
+ const [x1, y1, x2, y2] = [0.05, 0.7, 0.1, 1];
127
+ return `cubic-bezier(${x1}, ${y1}, ${x2}, ${y2})`;
134
128
  }
135
129
  const t = clamp((zeta - 0.85) / (1.6 - 0.85), 0, 1);
136
130
  const x1 = lerp(0.1, 0, t);
@@ -143,17 +137,18 @@ function lerp(a, b, t) {
143
137
  return a + (b - a) * t;
144
138
  }
145
139
  function round(n) {
146
- return Math.round(n * 1e3) / 1e3;
140
+ return Math.round(n * 1000) / 1000;
147
141
  }
148
142
  function springPosition(t, w0, zeta) {
149
- if (t <= 0) return 0;
150
- if (zeta < 1 - 1e-6) {
143
+ if (t <= 0)
144
+ return 0;
145
+ if (zeta < 1 - 0.000001) {
151
146
  const wd = w0 * Math.sqrt(1 - zeta * zeta);
152
147
  const envelope = Math.exp(-zeta * w0 * t);
153
148
  const osc = Math.cos(wd * t) + zeta * w0 / wd * Math.sin(wd * t);
154
149
  return 1 - envelope * osc;
155
150
  }
156
- if (zeta <= 1 + 1e-6) {
151
+ if (zeta <= 1 + 0.000001) {
157
152
  const envelope = Math.exp(-w0 * t);
158
153
  return 1 - envelope * (1 + w0 * t);
159
154
  }
@@ -173,9 +168,9 @@ function springToWaapiKeyframes(params, opts) {
173
168
  const to = opts?.to ?? 1;
174
169
  const span = to - from;
175
170
  const duration = springDurationMs(params);
176
- const durationSeconds = duration / 1e3;
171
+ const durationSeconds = duration / 1000;
177
172
  const samples = [];
178
- for (let i = 0; i < steps; i++) {
173
+ for (let i = 0;i < steps; i++) {
179
174
  const offset = i / (steps - 1);
180
175
  let value;
181
176
  if (i === 0) {
@@ -193,8 +188,6 @@ function springToWaapiKeyframes(params, opts) {
193
188
  return {
194
189
  samples,
195
190
  keyframes,
196
- // Easing is linear: the spring's shape is encoded in the samples
197
- // themselves, so the browser must interpolate them at constant rate.
198
191
  options: { duration, easing: "linear" }
199
192
  };
200
193
  }
@@ -215,103 +208,157 @@ function springFromPreset(preset) {
215
208
  mass: preset.mass != null && preset.mass > 0 ? preset.mass : DEFAULT_MASS
216
209
  };
217
210
  }
218
- var M3Fade = React5.forwardRef(
219
- ({ in: inProp, appear = true, children, ...props }, ref) => {
220
- const variants = {
221
- initial: { opacity: 0 },
222
- animate: {
223
- opacity: 1,
224
- transition: {
225
- ease: m3Easings.emphasizedDecelerate,
226
- duration: m3Durations.medium2
227
- }
228
- },
229
- exit: {
230
- opacity: 0,
231
- transition: {
232
- ease: m3Easings.emphasizedAccelerate,
233
- duration: m3Durations.short4
234
- }
211
+ // packages/m3-motion/src/components/M3Fade.tsx
212
+ import * as React from "react";
213
+ import { motion, AnimatePresence } from "motion/react";
214
+
215
+ // packages/m3-motion/src/hooks/useM3ReducedMotion.ts
216
+ import { useSyncExternalStore } from "react";
217
+ "use client";
218
+ var QUERY = "(prefers-reduced-motion: reduce)";
219
+ function subscribe(onChange) {
220
+ if (typeof window === "undefined" || !window.matchMedia)
221
+ return () => {};
222
+ const media = window.matchMedia(QUERY);
223
+ media.addEventListener("change", onChange);
224
+ return () => media.removeEventListener("change", onChange);
225
+ }
226
+ function useM3ReducedMotion() {
227
+ return useSyncExternalStore(subscribe, () => typeof window !== "undefined" && !!window.matchMedia?.(QUERY).matches, () => false);
228
+ }
229
+ function immediate(target) {
230
+ if (typeof target === "string")
231
+ return target;
232
+ return { ...target, transition: { type: "tween", duration: 0, delay: 0 } };
233
+ }
234
+ function motionVariants(variants, reduced) {
235
+ if (!reduced)
236
+ return variants;
237
+ return Object.fromEntries(Object.entries(variants).map(([key, variant]) => [
238
+ key,
239
+ typeof variant === "function" ? (...args) => immediate(variant(...args)) : immediate(variant)
240
+ ]));
241
+ }
242
+
243
+ // packages/m3-motion/src/components/M3Fade.tsx
244
+ import { jsx } from "react/jsx-runtime";
245
+ var M3Fade = React.forwardRef(({ in: inProp, appear = true, children, variants: customVariants, ...props }, ref) => {
246
+ const reduced = useM3ReducedMotion();
247
+ const variants = {
248
+ initial: { opacity: 0 },
249
+ animate: {
250
+ opacity: 1,
251
+ transition: {
252
+ ease: m3Easings.emphasizedDecelerate,
253
+ duration: m3Durations.medium2
235
254
  }
236
- };
237
- const content = /* @__PURE__ */ jsx(
238
- motion.div,
239
- {
240
- ref,
241
- variants,
242
- initial: appear ? "initial" : false,
243
- animate: "animate",
244
- exit: "exit",
245
- style: { willChange: "opacity" },
246
- ...props,
247
- children
255
+ },
256
+ exit: {
257
+ opacity: 0,
258
+ transition: {
259
+ ease: m3Easings.emphasizedAccelerate,
260
+ duration: m3Durations.short4
248
261
  }
249
- );
250
- if (inProp !== void 0) {
251
- return /* @__PURE__ */ jsx(AnimatePresence, { children: inProp ? content : null });
252
262
  }
253
- return content;
263
+ };
264
+ const content = /* @__PURE__ */ jsx(motion.div, {
265
+ ref,
266
+ variants: motionVariants(customVariants ?? variants, reduced),
267
+ initial: appear && !reduced ? "initial" : false,
268
+ animate: "animate",
269
+ exit: "exit",
270
+ style: { willChange: "opacity" },
271
+ ...props,
272
+ children
273
+ });
274
+ if (inProp !== undefined) {
275
+ return /* @__PURE__ */ jsx(AnimatePresence, {
276
+ children: inProp ? content : null
277
+ });
254
278
  }
255
- );
279
+ return content;
280
+ });
256
281
  M3Fade.displayName = "M3Fade";
257
- var M3SharedAxis = React5.forwardRef(
258
- ({ in: inProp, axis = "x", forward = true, appear = true, transition: customTransition, variants: customVariants, children, ...props }, ref) => {
259
- const translateOffset = 30;
260
- const scaleOffset = 0.08;
261
- const defaultVariants = {
262
- initial: {
263
- opacity: 0,
264
- x: axis === "x" ? forward ? translateOffset : -translateOffset : 0,
265
- y: axis === "y" ? forward ? translateOffset : -translateOffset : 0,
266
- scale: axis === "z" ? forward ? 1 - scaleOffset : 1 + scaleOffset : 1
267
- },
268
- animate: {
269
- opacity: 1,
270
- x: 0,
271
- y: 0,
272
- scale: 1,
273
- transition: customTransition || {
274
- x: { ease: m3Easings.emphasizedDecelerate, duration: m3Durations.medium2 },
275
- y: { ease: m3Easings.emphasizedDecelerate, duration: m3Durations.medium2 },
276
- scale: { ease: m3Easings.emphasizedDecelerate, duration: m3Durations.medium2 },
277
- opacity: { ease: m3Easings.standard, duration: m3Durations.medium2 }
278
- }
279
- },
280
- exit: {
281
- opacity: 0,
282
- x: axis === "x" ? forward ? -translateOffset : translateOffset : 0,
283
- y: axis === "y" ? forward ? -translateOffset : translateOffset : 0,
284
- scale: axis === "z" ? forward ? 1 + scaleOffset : 1 - scaleOffset : 1,
285
- transition: customTransition || {
286
- x: { ease: m3Easings.emphasizedAccelerate, duration: m3Durations.short4 },
287
- y: { ease: m3Easings.emphasizedAccelerate, duration: m3Durations.short4 },
288
- scale: { ease: m3Easings.emphasizedAccelerate, duration: m3Durations.short4 },
289
- opacity: { ease: m3Easings.standard, duration: m3Durations.short4 }
290
- }
282
+ // packages/m3-motion/src/components/M3SharedAxis.tsx
283
+ import * as React2 from "react";
284
+ import { motion as motion2, AnimatePresence as AnimatePresence2 } from "motion/react";
285
+ import { jsx as jsx2 } from "react/jsx-runtime";
286
+ var M3SharedAxis = React2.forwardRef(({
287
+ in: inProp,
288
+ axis = "x",
289
+ forward = true,
290
+ appear = true,
291
+ transition: customTransition,
292
+ variants: customVariants,
293
+ children,
294
+ ...props
295
+ }, ref) => {
296
+ const reduced = useM3ReducedMotion();
297
+ const translateOffset = 30;
298
+ const scaleOffset = 0.08;
299
+ const defaultVariants = {
300
+ initial: {
301
+ opacity: 0,
302
+ x: axis === "x" ? forward ? translateOffset : -translateOffset : 0,
303
+ y: axis === "y" ? forward ? translateOffset : -translateOffset : 0,
304
+ scale: axis === "z" ? forward ? 1 - scaleOffset : 1 + scaleOffset : 1
305
+ },
306
+ animate: {
307
+ opacity: 1,
308
+ x: 0,
309
+ y: 0,
310
+ scale: 1,
311
+ transition: customTransition || {
312
+ x: { ease: m3Easings.emphasizedDecelerate, duration: m3Durations.medium2 },
313
+ y: { ease: m3Easings.emphasizedDecelerate, duration: m3Durations.medium2 },
314
+ scale: { ease: m3Easings.emphasizedDecelerate, duration: m3Durations.medium2 },
315
+ opacity: { ease: m3Easings.standard, duration: m3Durations.medium2 }
291
316
  }
292
- };
293
- const resolvedVariants = customVariants || defaultVariants;
294
- const content = /* @__PURE__ */ jsx(
295
- motion.div,
296
- {
297
- ref,
298
- variants: resolvedVariants,
299
- initial: appear ? "initial" : false,
300
- animate: "animate",
301
- exit: "exit",
302
- style: { willChange: "opacity, transform" },
303
- ...props,
304
- children
317
+ },
318
+ exit: {
319
+ opacity: 0,
320
+ x: axis === "x" ? forward ? -translateOffset : translateOffset : 0,
321
+ y: axis === "y" ? forward ? -translateOffset : translateOffset : 0,
322
+ scale: axis === "z" ? forward ? 1 + scaleOffset : 1 - scaleOffset : 1,
323
+ transition: customTransition || {
324
+ x: { ease: m3Easings.emphasizedAccelerate, duration: m3Durations.short4 },
325
+ y: { ease: m3Easings.emphasizedAccelerate, duration: m3Durations.short4 },
326
+ scale: { ease: m3Easings.emphasizedAccelerate, duration: m3Durations.short4 },
327
+ opacity: { ease: m3Easings.standard, duration: m3Durations.short4 }
305
328
  }
306
- );
307
- if (inProp !== void 0) {
308
- return /* @__PURE__ */ jsx(AnimatePresence, { mode: "wait", children: inProp ? content : null });
309
329
  }
310
- return content;
330
+ };
331
+ const resolvedVariants = motionVariants(customVariants ?? defaultVariants, reduced);
332
+ const content = /* @__PURE__ */ jsx2(motion2.div, {
333
+ ref,
334
+ variants: resolvedVariants,
335
+ initial: appear && !reduced ? "initial" : false,
336
+ animate: "animate",
337
+ exit: "exit",
338
+ style: { willChange: "opacity, transform" },
339
+ ...props,
340
+ children
341
+ });
342
+ if (inProp !== undefined) {
343
+ return /* @__PURE__ */ jsx2(AnimatePresence2, {
344
+ mode: "wait",
345
+ children: inProp ? content : null
346
+ });
311
347
  }
312
- );
348
+ return content;
349
+ });
313
350
  M3SharedAxis.displayName = "M3SharedAxis";
314
- var M3FadeThrough = ({ stateKey, transition: customTransition, variants: customVariants, children, ...props }) => {
351
+ // packages/m3-motion/src/components/M3FadeThrough.tsx
352
+ import { motion as motion3, AnimatePresence as AnimatePresence3 } from "motion/react";
353
+ import { jsx as jsx3 } from "react/jsx-runtime";
354
+ var M3FadeThrough = ({
355
+ stateKey,
356
+ transition: customTransition,
357
+ variants: customVariants,
358
+ children,
359
+ ...props
360
+ }) => {
361
+ const reduced = useM3ReducedMotion();
315
362
  const defaultVariants = {
316
363
  initial: {
317
364
  opacity: 0,
@@ -341,76 +388,82 @@ var M3FadeThrough = ({ stateKey, transition: customTransition, variants: customV
341
388
  }
342
389
  }
343
390
  };
344
- const resolvedVariants = customVariants || defaultVariants;
345
- return /* @__PURE__ */ jsx(AnimatePresence, { mode: "wait", children: /* @__PURE__ */ jsx(
346
- motion.div,
347
- {
391
+ const resolvedVariants = motionVariants(customVariants ?? defaultVariants, reduced);
392
+ return /* @__PURE__ */ jsx3(AnimatePresence3, {
393
+ mode: "wait",
394
+ children: /* @__PURE__ */ jsx3(motion3.div, {
348
395
  variants: resolvedVariants,
349
- initial: "initial",
396
+ initial: reduced ? false : "initial",
350
397
  animate: "animate",
351
398
  exit: "exit",
352
399
  style: { willChange: "opacity, transform" },
353
400
  ...props,
354
401
  children
355
- },
356
- stateKey
357
- ) });
402
+ }, stateKey)
403
+ });
358
404
  };
359
405
  M3FadeThrough.displayName = "M3FadeThrough";
360
- var M3Collapse = React5.forwardRef(
361
- ({ in: inProp, appear = false, children, ...props }, ref) => {
362
- const variants = {
363
- initial: { height: 0, opacity: 0 },
364
- animate: {
365
- height: "auto",
366
- opacity: 1,
367
- transition: {
368
- height: {
369
- ease: m3Easings.emphasized,
370
- duration: m3Durations.medium4
371
- },
372
- opacity: {
373
- ease: m3Easings.standard,
374
- duration: m3Durations.medium2
375
- }
376
- }
377
- },
378
- exit: {
379
- height: 0,
380
- opacity: 0,
381
- transition: {
382
- height: {
383
- ease: m3Easings.emphasized,
384
- duration: m3Durations.medium4
385
- },
386
- opacity: {
387
- ease: m3Easings.standard,
388
- duration: m3Durations.medium2
389
- }
406
+ // packages/m3-motion/src/components/M3Collapse.tsx
407
+ import * as React3 from "react";
408
+ import { motion as motion4, AnimatePresence as AnimatePresence4 } from "motion/react";
409
+ import { jsx as jsx4 } from "react/jsx-runtime";
410
+ var M3Collapse = React3.forwardRef(({ in: inProp, appear = false, children, variants: customVariants, ...props }, ref) => {
411
+ const reduced = useM3ReducedMotion();
412
+ const variants = {
413
+ initial: { height: 0, opacity: 0 },
414
+ animate: {
415
+ height: "auto",
416
+ opacity: 1,
417
+ transition: {
418
+ height: {
419
+ ease: m3Easings.emphasized,
420
+ duration: m3Durations.medium4
421
+ },
422
+ opacity: {
423
+ ease: m3Easings.standard,
424
+ duration: m3Durations.medium2
390
425
  }
391
426
  }
392
- };
393
- const content = /* @__PURE__ */ jsx(
394
- motion.div,
395
- {
396
- ref,
397
- variants,
398
- initial: appear ? "initial" : false,
399
- animate: "animate",
400
- exit: "exit",
401
- style: { overflow: "hidden", willChange: "height, opacity" },
402
- ...props,
403
- children
427
+ },
428
+ exit: {
429
+ height: 0,
430
+ opacity: 0,
431
+ transition: {
432
+ height: {
433
+ ease: m3Easings.emphasized,
434
+ duration: m3Durations.medium4
435
+ },
436
+ opacity: {
437
+ ease: m3Easings.standard,
438
+ duration: m3Durations.medium2
439
+ }
404
440
  }
405
- );
406
- if (inProp !== void 0) {
407
- return /* @__PURE__ */ jsx(AnimatePresence, { initial: appear, children: inProp ? content : null });
408
441
  }
409
- return content;
442
+ };
443
+ const content = /* @__PURE__ */ jsx4(motion4.div, {
444
+ ref,
445
+ variants: motionVariants(customVariants ?? variants, reduced),
446
+ initial: appear && !reduced ? "initial" : false,
447
+ animate: "animate",
448
+ exit: "exit",
449
+ style: { overflow: "hidden", willChange: "height, opacity" },
450
+ ...props,
451
+ children
452
+ });
453
+ if (inProp !== undefined) {
454
+ return /* @__PURE__ */ jsx4(AnimatePresence4, {
455
+ initial: appear,
456
+ children: inProp ? content : null
457
+ });
410
458
  }
411
- );
459
+ return content;
460
+ });
412
461
  M3Collapse.displayName = "M3Collapse";
413
- var M3ContainerTransformContext = React5.createContext(null);
462
+ // packages/m3-motion/src/components/M3ContainerTransform.tsx
463
+ import * as React4 from "react";
464
+ import { motion as motion5 } from "motion/react";
465
+ import { jsx as jsx5 } from "react/jsx-runtime";
466
+ var M3ContainerTransformContext = React4.createContext(null);
414
467
  function getDefaultTransition(isActive, speed) {
415
468
  if (speed === "fast") {
416
469
  return isActive ? { delay: 0.05, duration: 0.15, ease: m3Easings.emphasizedDecelerate } : { duration: 0.08, ease: m3Easings.emphasizedAccelerate };
@@ -420,99 +473,84 @@ function getDefaultTransition(isActive, speed) {
420
473
  }
421
474
  return isActive ? { delay: 0.1, duration: 0.35, ease: m3Easings.emphasizedDecelerate } : { duration: 0.15, ease: m3Easings.emphasizedAccelerate };
422
475
  }
423
- var M3ContainerTransform = React5.forwardRef(
424
- ({ layoutId, speed = "default", isExpanded = false, children, transition, style, ...props }, ref) => {
425
- const springConfig = m3Springs[speed].spatial;
426
- const contextValue = React5.useMemo(
427
- () => ({ isExpanded, speed }),
428
- [isExpanded, speed]
429
- );
430
- return /* @__PURE__ */ jsx(M3ContainerTransformContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx(
431
- motion.div,
432
- {
433
- ref,
434
- layoutId,
435
- layout: true,
436
- transition: transition || springConfig,
437
- style: {
438
- willChange: "transform, border-radius",
439
- overflow: "hidden",
440
- ...style
441
- },
442
- ...props,
443
- children
444
- }
445
- ) });
446
- }
447
- );
448
- M3ContainerTransform.displayName = "M3ContainerTransform";
449
- var M3ContainerTransformStart = React5.forwardRef(
450
- ({ active, children, style, transition, layout = "position", ...props }, ref) => {
451
- const context = React5.useContext(M3ContainerTransformContext);
452
- const isActive = active ?? (context ? !context.isExpanded : true);
453
- const speed = context?.speed ?? "default";
454
- const baseStyle = {
455
- width: "100%",
456
- height: "100%",
457
- boxSizing: "border-box",
458
- pointerEvents: isActive ? "auto" : "none",
459
- ...!isActive && {
460
- position: "absolute",
461
- top: 0,
462
- left: 0
476
+ var M3ContainerTransform = React4.forwardRef(({
477
+ layoutId,
478
+ speed = "default",
479
+ isExpanded = false,
480
+ children,
481
+ transition,
482
+ style,
483
+ ...props
484
+ }, ref) => {
485
+ const reduced = useM3ReducedMotion();
486
+ const springConfig = m3Springs[speed].spatial;
487
+ const contextValue = React4.useMemo(() => ({ isExpanded, speed }), [isExpanded, speed]);
488
+ return /* @__PURE__ */ jsx5(M3ContainerTransformContext.Provider, {
489
+ value: contextValue,
490
+ children: /* @__PURE__ */ jsx5(motion5.div, {
491
+ ref,
492
+ layoutId: reduced ? undefined : layoutId,
493
+ layout: !reduced,
494
+ transition: reduced ? { type: "tween", duration: 0, delay: 0 } : transition || springConfig,
495
+ style: {
496
+ position: "relative",
497
+ willChange: "transform, border-radius",
498
+ overflow: "hidden",
499
+ ...style
463
500
  },
464
- ...style
465
- };
466
- const resolvedTransition = transition || getDefaultTransition(isActive, speed);
467
- return /* @__PURE__ */ jsx(
468
- motion.div,
469
- {
470
- ref,
471
- layout,
472
- animate: { opacity: isActive ? 1 : 0 },
473
- transition: resolvedTransition,
474
- style: baseStyle,
475
- ...props,
476
- children
477
- }
478
- );
479
- }
480
- );
501
+ ...props,
502
+ children
503
+ })
504
+ });
505
+ });
506
+ M3ContainerTransform.displayName = "M3ContainerTransform";
507
+ var ContainerTransformLayer = React4.forwardRef(({ layer, active, children, style, transition, layout = "position", ...props }, ref) => {
508
+ const reduced = useM3ReducedMotion();
509
+ const context = React4.useContext(M3ContainerTransformContext);
510
+ const isActive = active ?? (context ? context.isExpanded === (layer === "end") : true);
511
+ const speed = context?.speed ?? "default";
512
+ const baseStyle = {
513
+ width: "100%",
514
+ height: "100%",
515
+ boxSizing: "border-box",
516
+ pointerEvents: isActive ? "auto" : "none",
517
+ ...!isActive && {
518
+ position: "absolute",
519
+ top: 0,
520
+ left: 0
521
+ },
522
+ ...style
523
+ };
524
+ return /* @__PURE__ */ jsx5(motion5.div, {
525
+ ref,
526
+ layout: reduced ? false : layout,
527
+ ...layer === "end" ? { initial: reduced ? false : { opacity: 0 } } : {},
528
+ animate: { opacity: isActive ? 1 : 0 },
529
+ transition: reduced ? { type: "tween", duration: 0, delay: 0 } : transition || getDefaultTransition(isActive, speed),
530
+ style: baseStyle,
531
+ ...props,
532
+ inert: !isActive || props.inert,
533
+ "aria-hidden": !isActive || props["aria-hidden"],
534
+ children
535
+ });
536
+ });
537
+ var M3ContainerTransformStart = React4.forwardRef((props, ref) => /* @__PURE__ */ jsx5(ContainerTransformLayer, {
538
+ layer: "start",
539
+ ref,
540
+ ...props
541
+ }));
481
542
  M3ContainerTransformStart.displayName = "M3ContainerTransformStart";
482
- var M3ContainerTransformEnd = React5.forwardRef(
483
- ({ active, children, style, transition, layout = "position", ...props }, ref) => {
484
- const context = React5.useContext(M3ContainerTransformContext);
485
- const isActive = active ?? (context ? context.isExpanded : true);
486
- const speed = context?.speed ?? "default";
487
- const baseStyle = {
488
- width: "100%",
489
- height: "100%",
490
- boxSizing: "border-box",
491
- pointerEvents: isActive ? "auto" : "none",
492
- ...!isActive && {
493
- position: "absolute",
494
- top: 0,
495
- left: 0
496
- },
497
- ...style
498
- };
499
- const resolvedTransition = transition || getDefaultTransition(isActive, speed);
500
- return /* @__PURE__ */ jsx(
501
- motion.div,
502
- {
503
- ref,
504
- layout,
505
- initial: { opacity: 0 },
506
- animate: { opacity: isActive ? 1 : 0 },
507
- transition: resolvedTransition,
508
- style: baseStyle,
509
- ...props,
510
- children
511
- }
512
- );
513
- }
514
- );
543
+ var M3ContainerTransformEnd = React4.forwardRef((props, ref) => /* @__PURE__ */ jsx5(ContainerTransformLayer, {
544
+ layer: "end",
545
+ ref,
546
+ ...props
547
+ }));
515
548
  M3ContainerTransformEnd.displayName = "M3ContainerTransformEnd";
549
+ // packages/m3-motion/src/components/M3Transition.tsx
550
+ import * as React5 from "react";
551
+ import { AnimatePresence as AnimatePresence5, motion as motion6 } from "motion/react";
552
+ import { jsx as jsx6 } from "react/jsx-runtime";
553
+ "use client";
516
554
  var OFFSET = 30;
517
555
  var SCALE_OFFSET = 0.08;
518
556
  function buildVariants(pattern, forward) {
@@ -630,37 +668,40 @@ function buildVariants(pattern, forward) {
630
668
  };
631
669
  }
632
670
  }
633
- var M3Transition = React5.forwardRef(
634
- ({
635
- stateKey,
636
- pattern = "fade",
637
- forward = true,
638
- mode = "wait",
639
- variants,
640
- children,
641
- style,
642
- ...props
643
- }, ref) => {
644
- const resolvedVariants = variants ?? buildVariants(pattern, forward);
645
- const baseStyle = pattern === "collapse" ? { overflow: "hidden" } : { willChange: "opacity, transform" };
646
- const resolvedStyle = { ...baseStyle, ...style };
647
- return /* @__PURE__ */ jsx(AnimatePresence, { mode, children: /* @__PURE__ */ jsx(
648
- motion.div,
649
- {
650
- ref,
651
- variants: resolvedVariants,
652
- initial: "initial",
653
- animate: "animate",
654
- exit: "exit",
655
- style: resolvedStyle,
656
- ...props,
657
- children
658
- },
659
- stateKey
660
- ) });
661
- }
662
- );
671
+ var M3Transition = React5.forwardRef(({
672
+ stateKey,
673
+ pattern = "fade",
674
+ forward = true,
675
+ mode = "wait",
676
+ variants,
677
+ children,
678
+ style,
679
+ ...props
680
+ }, ref) => {
681
+ const reduced = useM3ReducedMotion();
682
+ const resolvedVariants = motionVariants(variants ?? buildVariants(pattern, forward), reduced);
683
+ const baseStyle = pattern === "collapse" ? { overflow: "hidden" } : { willChange: "opacity, transform" };
684
+ const resolvedStyle = { ...baseStyle, ...style };
685
+ return /* @__PURE__ */ jsx6(AnimatePresence5, {
686
+ mode,
687
+ children: /* @__PURE__ */ jsx6(motion6.div, {
688
+ ref,
689
+ variants: resolvedVariants,
690
+ initial: reduced ? false : "initial",
691
+ animate: "animate",
692
+ exit: "exit",
693
+ style: resolvedStyle,
694
+ ...props,
695
+ children
696
+ }, stateKey)
697
+ });
698
+ });
663
699
  M3Transition.displayName = "M3Transition";
700
+ // packages/m3-motion/src/components/M3ListStagger.tsx
701
+ import * as React6 from "react";
702
+ import { AnimatePresence as AnimatePresence6, motion as motion7, useIsPresent } from "motion/react";
703
+ import { jsx as jsx7 } from "react/jsx-runtime";
704
+ "use client";
664
705
  var containerVariants = {
665
706
  hidden: {},
666
707
  visible: (_custom) => ({
@@ -690,65 +731,84 @@ var itemVariants = {
690
731
  }
691
732
  }
692
733
  };
693
- var M3ListStagger = React5.forwardRef(
694
- ({ staggerDelay = 0.05, delayChildren = 0, appear = true, children, className, style }, ref) => {
695
- return /* @__PURE__ */ jsx(AnimatePresence, { children: /* @__PURE__ */ jsx(
696
- motion.div,
697
- {
698
- ref,
699
- className,
700
- style,
701
- variants: containerVariants,
702
- initial: appear ? "hidden" : false,
703
- animate: "visible",
704
- exit: "exit",
705
- custom: { staggerDelay, delayChildren },
706
- children
707
- }
708
- ) });
709
- }
710
- );
734
+ var M3ListStagger = React6.forwardRef(({ staggerDelay = 0.05, delayChildren = 0, appear = true, children, className, style }, ref) => {
735
+ const reduced = useM3ReducedMotion();
736
+ return /* @__PURE__ */ jsx7(motion7.div, {
737
+ ref,
738
+ className,
739
+ style,
740
+ variants: motionVariants(containerVariants, reduced),
741
+ initial: appear && !reduced ? "hidden" : false,
742
+ animate: "visible",
743
+ exit: "exit",
744
+ custom: { staggerDelay, delayChildren },
745
+ children: /* @__PURE__ */ jsx7(AnimatePresence6, {
746
+ initial: appear && !reduced,
747
+ children
748
+ })
749
+ });
750
+ });
711
751
  M3ListStagger.displayName = "M3ListStagger";
712
- var M3ListStaggerItem = React5.forwardRef(
713
- ({ children, style, ...props }, ref) => {
714
- return /* @__PURE__ */ jsx(
715
- motion.div,
716
- {
717
- ref,
718
- variants: itemVariants,
719
- style: { willChange: "opacity, transform", ...style },
720
- ...props,
721
- children
722
- }
723
- );
724
- }
725
- );
752
+ var M3ListStaggerItem = React6.forwardRef(({ children, style, ...props }, ref) => {
753
+ const present = useIsPresent();
754
+ const reduced = useM3ReducedMotion();
755
+ return /* @__PURE__ */ jsx7(motion7.div, {
756
+ ref,
757
+ variants: motionVariants(itemVariants, reduced),
758
+ style: { willChange: "opacity, transform", ...style },
759
+ ...props,
760
+ inert: !present || props.inert,
761
+ "aria-hidden": !present || props["aria-hidden"],
762
+ children
763
+ });
764
+ });
726
765
  M3ListStaggerItem.displayName = "M3ListStaggerItem";
766
+ // packages/m3-motion/src/hooks/useM3Animate.ts
767
+ import { useAnimate } from "motion/react";
727
768
  function useM3Animate() {
728
769
  const [scope, animate] = useAnimate();
770
+ const reduced = useM3ReducedMotion();
729
771
  const m3Animate = (elementOrSelector, keyframes, options) => {
730
- if (Array.isArray(elementOrSelector)) {
731
- return animate(
732
- elementOrSelector,
733
- keyframes
734
- );
735
- }
736
- if (typeof elementOrSelector === "string" || elementOrSelector instanceof Element || typeof elementOrSelector === "object" && elementOrSelector !== null && "current" in elementOrSelector || typeof elementOrSelector === "number" || typeof elementOrSelector === "object" && elementOrSelector !== null && "get" in elementOrSelector) {
737
- return animate(elementOrSelector, keyframes, {
738
- ease: m3Easings.emphasized,
739
- duration: m3Durations.medium2,
740
- ...typeof options === "object" && options !== null ? options : {}
772
+ const defaults = { ease: m3Easings.emphasized, duration: m3Durations.medium2 };
773
+ const immediate = reduced ? { type: "tween", duration: 0, delay: 0, repeat: 0 } : {};
774
+ if (Array.isArray(elementOrSelector) && elementOrSelector.some(Array.isArray)) {
775
+ const sequenceOptions = typeof keyframes === "object" && keyframes !== null ? keyframes : {};
776
+ const sequence = reduced ? elementOrSelector.map((segment) => Array.isArray(segment) ? [segment[0], segment[1], { ...segment[2], ...immediate, at: 0 }] : segment) : elementOrSelector;
777
+ return animate(sequence, {
778
+ ...sequenceOptions,
779
+ defaultTransition: { ...defaults, ...sequenceOptions.defaultTransition, ...immediate }
741
780
  });
742
781
  }
743
782
  return animate(elementOrSelector, keyframes, {
744
- ease: m3Easings.emphasized,
745
- duration: m3Durations.medium2,
746
- ...typeof options === "object" && options !== null ? options : {}
783
+ ...defaults,
784
+ ...typeof options === "object" && options !== null ? options : {},
785
+ ...immediate
747
786
  });
748
787
  };
749
788
  return [scope, m3Animate];
750
789
  }
790
+ export {
791
+ M3Collapse,
792
+ M3ContainerTransform,
793
+ M3ContainerTransformContext,
794
+ M3ContainerTransformEnd,
795
+ M3ContainerTransformStart,
796
+ M3Fade,
797
+ M3FadeThrough,
798
+ M3ListStagger,
799
+ M3ListStaggerItem,
800
+ M3SharedAxis,
801
+ M3Transition,
802
+ m3Durations,
803
+ m3Easings,
804
+ m3Springs,
805
+ springDurationMs,
806
+ springFromPreset,
807
+ springKeyframesForProperty,
808
+ springToCssEasing,
809
+ springToWaapiKeyframes,
810
+ useM3Animate,
811
+ useM3ReducedMotion
812
+ };
751
813
 
752
- export { M3Collapse, M3ContainerTransform, M3ContainerTransformContext, M3ContainerTransformEnd, M3ContainerTransformStart, M3Fade, M3FadeThrough, M3ListStagger, M3ListStaggerItem, M3SharedAxis, M3Transition, m3Durations, m3Easings, m3Springs, springDurationMs, springFromPreset, springKeyframesForProperty, springToCssEasing, springToWaapiKeyframes, useM3Animate };
753
- //# sourceMappingURL=index.js.map
754
- //# sourceMappingURL=index.js.map
814
+ //# debugId=32BD74EF26CFB5FE64756E2164756E21