motion 12.9.6 → 12.10.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.
@@ -3187,243 +3187,6 @@ function resolveElements(elementOrSelector, scope, selectorCache) {
3187
3187
  return Array.from(elementOrSelector);
3188
3188
  }
3189
3189
 
3190
- const { schedule: microtask, cancel: cancelMicrotask } =
3191
- /* @__PURE__ */ createRenderBatcher(queueMicrotask, false);
3192
-
3193
- const isDragging = {
3194
- x: false,
3195
- y: false,
3196
- };
3197
- function isDragActive() {
3198
- return isDragging.x || isDragging.y;
3199
- }
3200
-
3201
- function setDragLock(axis) {
3202
- if (axis === "x" || axis === "y") {
3203
- if (isDragging[axis]) {
3204
- return null;
3205
- }
3206
- else {
3207
- isDragging[axis] = true;
3208
- return () => {
3209
- isDragging[axis] = false;
3210
- };
3211
- }
3212
- }
3213
- else {
3214
- if (isDragging.x || isDragging.y) {
3215
- return null;
3216
- }
3217
- else {
3218
- isDragging.x = isDragging.y = true;
3219
- return () => {
3220
- isDragging.x = isDragging.y = false;
3221
- };
3222
- }
3223
- }
3224
- }
3225
-
3226
- function setupGesture(elementOrSelector, options) {
3227
- const elements = resolveElements(elementOrSelector);
3228
- const gestureAbortController = new AbortController();
3229
- const eventOptions = {
3230
- passive: true,
3231
- ...options,
3232
- signal: gestureAbortController.signal,
3233
- };
3234
- const cancel = () => gestureAbortController.abort();
3235
- return [elements, eventOptions, cancel];
3236
- }
3237
-
3238
- function isValidHover(event) {
3239
- return !(event.pointerType === "touch" || isDragActive());
3240
- }
3241
- /**
3242
- * Create a hover gesture. hover() is different to .addEventListener("pointerenter")
3243
- * in that it has an easier syntax, filters out polyfilled touch events, interoperates
3244
- * with drag gestures, and automatically removes the "pointerennd" event listener when the hover ends.
3245
- *
3246
- * @public
3247
- */
3248
- function hover(elementOrSelector, onHoverStart, options = {}) {
3249
- const [elements, eventOptions, cancel] = setupGesture(elementOrSelector, options);
3250
- const onPointerEnter = (enterEvent) => {
3251
- if (!isValidHover(enterEvent))
3252
- return;
3253
- const { target } = enterEvent;
3254
- const onHoverEnd = onHoverStart(target, enterEvent);
3255
- if (typeof onHoverEnd !== "function" || !target)
3256
- return;
3257
- const onPointerLeave = (leaveEvent) => {
3258
- if (!isValidHover(leaveEvent))
3259
- return;
3260
- onHoverEnd(leaveEvent);
3261
- target.removeEventListener("pointerleave", onPointerLeave);
3262
- };
3263
- target.addEventListener("pointerleave", onPointerLeave, eventOptions);
3264
- };
3265
- elements.forEach((element) => {
3266
- element.addEventListener("pointerenter", onPointerEnter, eventOptions);
3267
- });
3268
- return cancel;
3269
- }
3270
-
3271
- /**
3272
- * Recursively traverse up the tree to check whether the provided child node
3273
- * is the parent or a descendant of it.
3274
- *
3275
- * @param parent - Element to find
3276
- * @param child - Element to test against parent
3277
- */
3278
- const isNodeOrChild = (parent, child) => {
3279
- if (!child) {
3280
- return false;
3281
- }
3282
- else if (parent === child) {
3283
- return true;
3284
- }
3285
- else {
3286
- return isNodeOrChild(parent, child.parentElement);
3287
- }
3288
- };
3289
-
3290
- const isPrimaryPointer = (event) => {
3291
- if (event.pointerType === "mouse") {
3292
- return typeof event.button !== "number" || event.button <= 0;
3293
- }
3294
- else {
3295
- /**
3296
- * isPrimary is true for all mice buttons, whereas every touch point
3297
- * is regarded as its own input. So subsequent concurrent touch points
3298
- * will be false.
3299
- *
3300
- * Specifically match against false here as incomplete versions of
3301
- * PointerEvents in very old browser might have it set as undefined.
3302
- */
3303
- return event.isPrimary !== false;
3304
- }
3305
- };
3306
-
3307
- const focusableElements = new Set([
3308
- "BUTTON",
3309
- "INPUT",
3310
- "SELECT",
3311
- "TEXTAREA",
3312
- "A",
3313
- ]);
3314
- function isElementKeyboardAccessible(element) {
3315
- return (focusableElements.has(element.tagName) ||
3316
- element.tabIndex !== -1);
3317
- }
3318
-
3319
- const isPressing = new WeakSet();
3320
-
3321
- /**
3322
- * Filter out events that are not "Enter" keys.
3323
- */
3324
- function filterEvents(callback) {
3325
- return (event) => {
3326
- if (event.key !== "Enter")
3327
- return;
3328
- callback(event);
3329
- };
3330
- }
3331
- function firePointerEvent(target, type) {
3332
- target.dispatchEvent(new PointerEvent("pointer" + type, { isPrimary: true, bubbles: true }));
3333
- }
3334
- const enableKeyboardPress = (focusEvent, eventOptions) => {
3335
- const element = focusEvent.currentTarget;
3336
- if (!element)
3337
- return;
3338
- const handleKeydown = filterEvents(() => {
3339
- if (isPressing.has(element))
3340
- return;
3341
- firePointerEvent(element, "down");
3342
- const handleKeyup = filterEvents(() => {
3343
- firePointerEvent(element, "up");
3344
- });
3345
- const handleBlur = () => firePointerEvent(element, "cancel");
3346
- element.addEventListener("keyup", handleKeyup, eventOptions);
3347
- element.addEventListener("blur", handleBlur, eventOptions);
3348
- });
3349
- element.addEventListener("keydown", handleKeydown, eventOptions);
3350
- /**
3351
- * Add an event listener that fires on blur to remove the keydown events.
3352
- */
3353
- element.addEventListener("blur", () => element.removeEventListener("keydown", handleKeydown), eventOptions);
3354
- };
3355
-
3356
- /**
3357
- * Filter out events that are not primary pointer events, or are triggering
3358
- * while a Motion gesture is active.
3359
- */
3360
- function isValidPressEvent(event) {
3361
- return isPrimaryPointer(event) && !isDragActive();
3362
- }
3363
- /**
3364
- * Create a press gesture.
3365
- *
3366
- * Press is different to `"pointerdown"`, `"pointerup"` in that it
3367
- * automatically filters out secondary pointer events like right
3368
- * click and multitouch.
3369
- *
3370
- * It also adds accessibility support for keyboards, where
3371
- * an element with a press gesture will receive focus and
3372
- * trigger on Enter `"keydown"` and `"keyup"` events.
3373
- *
3374
- * This is different to a browser's `"click"` event, which does
3375
- * respond to keyboards but only for the `"click"` itself, rather
3376
- * than the press start and end/cancel. The element also needs
3377
- * to be focusable for this to work, whereas a press gesture will
3378
- * make an element focusable by default.
3379
- *
3380
- * @public
3381
- */
3382
- function press(targetOrSelector, onPressStart, options = {}) {
3383
- const [targets, eventOptions, cancelEvents] = setupGesture(targetOrSelector, options);
3384
- const startPress = (startEvent) => {
3385
- const target = startEvent.currentTarget;
3386
- if (!isValidPressEvent(startEvent) || isPressing.has(target))
3387
- return;
3388
- isPressing.add(target);
3389
- const onPressEnd = onPressStart(target, startEvent);
3390
- const onPointerEnd = (endEvent, success) => {
3391
- window.removeEventListener("pointerup", onPointerUp);
3392
- window.removeEventListener("pointercancel", onPointerCancel);
3393
- if (!isValidPressEvent(endEvent) || !isPressing.has(target)) {
3394
- return;
3395
- }
3396
- isPressing.delete(target);
3397
- if (typeof onPressEnd === "function") {
3398
- onPressEnd(endEvent, { success });
3399
- }
3400
- };
3401
- const onPointerUp = (upEvent) => {
3402
- onPointerEnd(upEvent, target === window ||
3403
- target === document ||
3404
- options.useGlobalTarget ||
3405
- isNodeOrChild(target, upEvent.target));
3406
- };
3407
- const onPointerCancel = (cancelEvent) => {
3408
- onPointerEnd(cancelEvent, false);
3409
- };
3410
- window.addEventListener("pointerup", onPointerUp, eventOptions);
3411
- window.addEventListener("pointercancel", onPointerCancel, eventOptions);
3412
- };
3413
- targets.forEach((target) => {
3414
- const pointerDownTarget = options.useGlobalTarget ? window : target;
3415
- pointerDownTarget.addEventListener("pointerdown", startPress, eventOptions);
3416
- if (target instanceof HTMLElement) {
3417
- target.addEventListener("focus", (event) => enableKeyboardPress(event, eventOptions));
3418
- if (!isElementKeyboardAccessible(target) &&
3419
- !target.hasAttribute("tabindex")) {
3420
- target.tabIndex = 0;
3421
- }
3422
- }
3423
- });
3424
- return cancelEvents;
3425
- }
3426
-
3427
3190
  /**
3428
3191
  * Maximum time between the value of two frames, beyond which we
3429
3192
  * assume the velocity has since been 0.
@@ -3477,6 +3240,11 @@ class MotionValue {
3477
3240
  // Update update subscribers
3478
3241
  if (this.current !== this.prev) {
3479
3242
  this.events.change?.notify(this.current);
3243
+ if (this.dependents) {
3244
+ for (const dependent of this.dependents) {
3245
+ dependent.dirty();
3246
+ }
3247
+ }
3480
3248
  }
3481
3249
  // Update render subscribers
3482
3250
  if (render) {
@@ -3618,6 +3386,20 @@ class MotionValue {
3618
3386
  if (this.stopPassiveEffect)
3619
3387
  this.stopPassiveEffect();
3620
3388
  }
3389
+ dirty() {
3390
+ this.events.change?.notify(this.current);
3391
+ }
3392
+ addDependent(dependent) {
3393
+ if (!this.dependents) {
3394
+ this.dependents = new Set();
3395
+ }
3396
+ this.dependents.add(dependent);
3397
+ }
3398
+ removeDependent(dependent) {
3399
+ if (this.dependents) {
3400
+ this.dependents.delete(dependent);
3401
+ }
3402
+ }
3621
3403
  /**
3622
3404
  * Returns the latest state of `MotionValue`
3623
3405
  *
@@ -3713,6 +3495,7 @@ class MotionValue {
3713
3495
  * @public
3714
3496
  */
3715
3497
  destroy() {
3498
+ this.dependents?.clear();
3716
3499
  this.events.destroy?.notify();
3717
3500
  this.clearListeners();
3718
3501
  this.stop();
@@ -3725,15 +3508,6 @@ function motionValue(init, options) {
3725
3508
  return new MotionValue(init, options);
3726
3509
  }
3727
3510
 
3728
- /**
3729
- * A list of all ValueTypes
3730
- */
3731
- const valueTypes = [...dimensionValueTypes, color, complex];
3732
- /**
3733
- * Tests a value against the list of ValueTypes
3734
- */
3735
- const findValueType = (v) => valueTypes.find(testValueType(v));
3736
-
3737
3511
  /**
3738
3512
  * Provided a value and a ValueType, returns the value as that value type.
3739
3513
  */
@@ -3743,6 +3517,254 @@ const getValueAsType = (value, type) => {
3743
3517
  : value;
3744
3518
  };
3745
3519
 
3520
+ const { schedule: microtask, cancel: cancelMicrotask } =
3521
+ /* @__PURE__ */ createRenderBatcher(queueMicrotask, false);
3522
+
3523
+ const isDragging = {
3524
+ x: false,
3525
+ y: false,
3526
+ };
3527
+ function isDragActive() {
3528
+ return isDragging.x || isDragging.y;
3529
+ }
3530
+
3531
+ function setDragLock(axis) {
3532
+ if (axis === "x" || axis === "y") {
3533
+ if (isDragging[axis]) {
3534
+ return null;
3535
+ }
3536
+ else {
3537
+ isDragging[axis] = true;
3538
+ return () => {
3539
+ isDragging[axis] = false;
3540
+ };
3541
+ }
3542
+ }
3543
+ else {
3544
+ if (isDragging.x || isDragging.y) {
3545
+ return null;
3546
+ }
3547
+ else {
3548
+ isDragging.x = isDragging.y = true;
3549
+ return () => {
3550
+ isDragging.x = isDragging.y = false;
3551
+ };
3552
+ }
3553
+ }
3554
+ }
3555
+
3556
+ function setupGesture(elementOrSelector, options) {
3557
+ const elements = resolveElements(elementOrSelector);
3558
+ const gestureAbortController = new AbortController();
3559
+ const eventOptions = {
3560
+ passive: true,
3561
+ ...options,
3562
+ signal: gestureAbortController.signal,
3563
+ };
3564
+ const cancel = () => gestureAbortController.abort();
3565
+ return [elements, eventOptions, cancel];
3566
+ }
3567
+
3568
+ function isValidHover(event) {
3569
+ return !(event.pointerType === "touch" || isDragActive());
3570
+ }
3571
+ /**
3572
+ * Create a hover gesture. hover() is different to .addEventListener("pointerenter")
3573
+ * in that it has an easier syntax, filters out polyfilled touch events, interoperates
3574
+ * with drag gestures, and automatically removes the "pointerennd" event listener when the hover ends.
3575
+ *
3576
+ * @public
3577
+ */
3578
+ function hover(elementOrSelector, onHoverStart, options = {}) {
3579
+ const [elements, eventOptions, cancel] = setupGesture(elementOrSelector, options);
3580
+ const onPointerEnter = (enterEvent) => {
3581
+ if (!isValidHover(enterEvent))
3582
+ return;
3583
+ const { target } = enterEvent;
3584
+ const onHoverEnd = onHoverStart(target, enterEvent);
3585
+ if (typeof onHoverEnd !== "function" || !target)
3586
+ return;
3587
+ const onPointerLeave = (leaveEvent) => {
3588
+ if (!isValidHover(leaveEvent))
3589
+ return;
3590
+ onHoverEnd(leaveEvent);
3591
+ target.removeEventListener("pointerleave", onPointerLeave);
3592
+ };
3593
+ target.addEventListener("pointerleave", onPointerLeave, eventOptions);
3594
+ };
3595
+ elements.forEach((element) => {
3596
+ element.addEventListener("pointerenter", onPointerEnter, eventOptions);
3597
+ });
3598
+ return cancel;
3599
+ }
3600
+
3601
+ /**
3602
+ * Recursively traverse up the tree to check whether the provided child node
3603
+ * is the parent or a descendant of it.
3604
+ *
3605
+ * @param parent - Element to find
3606
+ * @param child - Element to test against parent
3607
+ */
3608
+ const isNodeOrChild = (parent, child) => {
3609
+ if (!child) {
3610
+ return false;
3611
+ }
3612
+ else if (parent === child) {
3613
+ return true;
3614
+ }
3615
+ else {
3616
+ return isNodeOrChild(parent, child.parentElement);
3617
+ }
3618
+ };
3619
+
3620
+ const isPrimaryPointer = (event) => {
3621
+ if (event.pointerType === "mouse") {
3622
+ return typeof event.button !== "number" || event.button <= 0;
3623
+ }
3624
+ else {
3625
+ /**
3626
+ * isPrimary is true for all mice buttons, whereas every touch point
3627
+ * is regarded as its own input. So subsequent concurrent touch points
3628
+ * will be false.
3629
+ *
3630
+ * Specifically match against false here as incomplete versions of
3631
+ * PointerEvents in very old browser might have it set as undefined.
3632
+ */
3633
+ return event.isPrimary !== false;
3634
+ }
3635
+ };
3636
+
3637
+ const focusableElements = new Set([
3638
+ "BUTTON",
3639
+ "INPUT",
3640
+ "SELECT",
3641
+ "TEXTAREA",
3642
+ "A",
3643
+ ]);
3644
+ function isElementKeyboardAccessible(element) {
3645
+ return (focusableElements.has(element.tagName) ||
3646
+ element.tabIndex !== -1);
3647
+ }
3648
+
3649
+ const isPressing = new WeakSet();
3650
+
3651
+ /**
3652
+ * Filter out events that are not "Enter" keys.
3653
+ */
3654
+ function filterEvents(callback) {
3655
+ return (event) => {
3656
+ if (event.key !== "Enter")
3657
+ return;
3658
+ callback(event);
3659
+ };
3660
+ }
3661
+ function firePointerEvent(target, type) {
3662
+ target.dispatchEvent(new PointerEvent("pointer" + type, { isPrimary: true, bubbles: true }));
3663
+ }
3664
+ const enableKeyboardPress = (focusEvent, eventOptions) => {
3665
+ const element = focusEvent.currentTarget;
3666
+ if (!element)
3667
+ return;
3668
+ const handleKeydown = filterEvents(() => {
3669
+ if (isPressing.has(element))
3670
+ return;
3671
+ firePointerEvent(element, "down");
3672
+ const handleKeyup = filterEvents(() => {
3673
+ firePointerEvent(element, "up");
3674
+ });
3675
+ const handleBlur = () => firePointerEvent(element, "cancel");
3676
+ element.addEventListener("keyup", handleKeyup, eventOptions);
3677
+ element.addEventListener("blur", handleBlur, eventOptions);
3678
+ });
3679
+ element.addEventListener("keydown", handleKeydown, eventOptions);
3680
+ /**
3681
+ * Add an event listener that fires on blur to remove the keydown events.
3682
+ */
3683
+ element.addEventListener("blur", () => element.removeEventListener("keydown", handleKeydown), eventOptions);
3684
+ };
3685
+
3686
+ /**
3687
+ * Filter out events that are not primary pointer events, or are triggering
3688
+ * while a Motion gesture is active.
3689
+ */
3690
+ function isValidPressEvent(event) {
3691
+ return isPrimaryPointer(event) && !isDragActive();
3692
+ }
3693
+ /**
3694
+ * Create a press gesture.
3695
+ *
3696
+ * Press is different to `"pointerdown"`, `"pointerup"` in that it
3697
+ * automatically filters out secondary pointer events like right
3698
+ * click and multitouch.
3699
+ *
3700
+ * It also adds accessibility support for keyboards, where
3701
+ * an element with a press gesture will receive focus and
3702
+ * trigger on Enter `"keydown"` and `"keyup"` events.
3703
+ *
3704
+ * This is different to a browser's `"click"` event, which does
3705
+ * respond to keyboards but only for the `"click"` itself, rather
3706
+ * than the press start and end/cancel. The element also needs
3707
+ * to be focusable for this to work, whereas a press gesture will
3708
+ * make an element focusable by default.
3709
+ *
3710
+ * @public
3711
+ */
3712
+ function press(targetOrSelector, onPressStart, options = {}) {
3713
+ const [targets, eventOptions, cancelEvents] = setupGesture(targetOrSelector, options);
3714
+ const startPress = (startEvent) => {
3715
+ const target = startEvent.currentTarget;
3716
+ if (!isValidPressEvent(startEvent) || isPressing.has(target))
3717
+ return;
3718
+ isPressing.add(target);
3719
+ const onPressEnd = onPressStart(target, startEvent);
3720
+ const onPointerEnd = (endEvent, success) => {
3721
+ window.removeEventListener("pointerup", onPointerUp);
3722
+ window.removeEventListener("pointercancel", onPointerCancel);
3723
+ if (isPressing.has(target)) {
3724
+ isPressing.delete(target);
3725
+ }
3726
+ if (!isValidPressEvent(endEvent)) {
3727
+ return;
3728
+ }
3729
+ if (typeof onPressEnd === "function") {
3730
+ onPressEnd(endEvent, { success });
3731
+ }
3732
+ };
3733
+ const onPointerUp = (upEvent) => {
3734
+ onPointerEnd(upEvent, target === window ||
3735
+ target === document ||
3736
+ options.useGlobalTarget ||
3737
+ isNodeOrChild(target, upEvent.target));
3738
+ };
3739
+ const onPointerCancel = (cancelEvent) => {
3740
+ onPointerEnd(cancelEvent, false);
3741
+ };
3742
+ window.addEventListener("pointerup", onPointerUp, eventOptions);
3743
+ window.addEventListener("pointercancel", onPointerCancel, eventOptions);
3744
+ };
3745
+ targets.forEach((target) => {
3746
+ const pointerDownTarget = options.useGlobalTarget ? window : target;
3747
+ pointerDownTarget.addEventListener("pointerdown", startPress, eventOptions);
3748
+ if (target instanceof HTMLElement) {
3749
+ target.addEventListener("focus", (event) => enableKeyboardPress(event, eventOptions));
3750
+ if (!isElementKeyboardAccessible(target) &&
3751
+ !target.hasAttribute("tabindex")) {
3752
+ target.tabIndex = 0;
3753
+ }
3754
+ }
3755
+ });
3756
+ return cancelEvents;
3757
+ }
3758
+
3759
+ /**
3760
+ * A list of all ValueTypes
3761
+ */
3762
+ const valueTypes = [...dimensionValueTypes, color, complex];
3763
+ /**
3764
+ * Tests a value against the list of ValueTypes
3765
+ */
3766
+ const findValueType = (v) => valueTypes.find(testValueType(v));
3767
+
3746
3768
  const isKeyframesTarget = (v) => {
3747
3769
  return Array.isArray(v);
3748
3770
  };
@@ -485,9 +485,6 @@ const numberValueTypes = {
485
485
  numOctaves: int,
486
486
  };
487
487
 
488
- const { schedule: microtask, cancel: cancelMicrotask } =
489
- /* @__PURE__ */ createRenderBatcher(queueMicrotask, false);
490
-
491
488
  /**
492
489
  * Provided a value and a ValueType, returns the value as that value type.
493
490
  */
@@ -497,6 +494,9 @@ const getValueAsType = (value, type) => {
497
494
  : value;
498
495
  };
499
496
 
497
+ const { schedule: microtask, cancel: cancelMicrotask } =
498
+ /* @__PURE__ */ createRenderBatcher(queueMicrotask, false);
499
+
500
500
  /**
501
501
  * Convert camelCase to dash-case properties.
502
502
  */
@@ -73,7 +73,9 @@ function PopChild({ children, isPresent, anchorX }) {
73
73
  `);
74
74
  }
75
75
  return () => {
76
- document.head.removeChild(style);
76
+ if (document.head.contains(style)) {
77
+ document.head.removeChild(style);
78
+ }
77
79
  };
78
80
  }, [isPresent]);
79
81
  return (jsx(PopChildMeasure, { isPresent: isPresent, childRef: ref, sizeRef: size, children: React.cloneElement(children, { ref }) }));
@@ -39,7 +39,7 @@ export { supportsPartialKeyframes } from '../../motion-dom/dist/es/animation/waa
39
39
  export { supportsBrowserAnimation } from '../../motion-dom/dist/es/animation/waapi/supports/waapi.mjs';
40
40
  export { acceleratedValues } from '../../motion-dom/dist/es/animation/waapi/utils/accelerated-values.mjs';
41
41
  export { generateLinearEasing } from '../../motion-dom/dist/es/animation/waapi/utils/linear.mjs';
42
- export { styleEffect } from '../../motion-dom/dist/es/effects/style-effect.mjs';
42
+ export { styleEffect } from '../../motion-dom/dist/es/effects/style/index.mjs';
43
43
  export { createRenderBatcher } from '../../motion-dom/dist/es/frameloop/batcher.mjs';
44
44
  export { cancelMicrotask, microtask } from '../../motion-dom/dist/es/frameloop/microtask.mjs';
45
45
  export { time } from '../../motion-dom/dist/es/frameloop/sync-time.mjs';
@@ -138,7 +138,7 @@ export { supportsPartialKeyframes } from '../../motion-dom/dist/es/animation/waa
138
138
  export { supportsBrowserAnimation } from '../../motion-dom/dist/es/animation/waapi/supports/waapi.mjs';
139
139
  export { acceleratedValues } from '../../motion-dom/dist/es/animation/waapi/utils/accelerated-values.mjs';
140
140
  export { generateLinearEasing } from '../../motion-dom/dist/es/animation/waapi/utils/linear.mjs';
141
- export { styleEffect } from '../../motion-dom/dist/es/effects/style-effect.mjs';
141
+ export { styleEffect } from '../../motion-dom/dist/es/effects/style/index.mjs';
142
142
  export { createRenderBatcher } from '../../motion-dom/dist/es/frameloop/batcher.mjs';
143
143
  export { cancelMicrotask, microtask } from '../../motion-dom/dist/es/frameloop/microtask.mjs';
144
144
  export { time } from '../../motion-dom/dist/es/frameloop/sync-time.mjs';
@@ -0,0 +1,41 @@
1
+ import { frame, cancelFrame } from '../frameloop/frame.mjs';
2
+ import { numberValueTypes } from '../value/types/maps/number.mjs';
3
+ import { getValueAsType } from '../value/types/utils/get-as-type.mjs';
4
+
5
+ class MotionValueState {
6
+ constructor() {
7
+ this.latest = {};
8
+ this.values = new Map();
9
+ }
10
+ set(name, value, render, computed) {
11
+ const existingValue = this.values.get(name);
12
+ if (existingValue) {
13
+ existingValue.onRemove();
14
+ }
15
+ const onChange = () => {
16
+ this.latest[name] = getValueAsType(value.get(), numberValueTypes[name]);
17
+ render && frame.render(render);
18
+ };
19
+ onChange();
20
+ const cancelOnChange = value.on("change", onChange);
21
+ computed && value.addDependent(computed);
22
+ const remove = () => {
23
+ cancelOnChange();
24
+ render && cancelFrame(render);
25
+ this.values.delete(name);
26
+ computed && value.removeDependent(computed);
27
+ };
28
+ this.values.set(name, { value, onRemove: remove });
29
+ return remove;
30
+ }
31
+ get(name) {
32
+ return this.values.get(name)?.value;
33
+ }
34
+ destroy() {
35
+ for (const value of this.values.values()) {
36
+ value.onRemove();
37
+ }
38
+ }
39
+ }
40
+
41
+ export { MotionValueState };
@@ -0,0 +1,51 @@
1
+ import { isCSSVar } from '../../render/dom/is-css-var.mjs';
2
+ import { transformProps } from '../../render/utils/keys-transform.mjs';
3
+ import { resolveElements } from '../../utils/resolve-elements.mjs';
4
+ import { MotionValue } from '../../value/index.mjs';
5
+ import { MotionValueState } from '../MotionValueState.mjs';
6
+ import { buildTransform } from './transform.mjs';
7
+
8
+ const stateMap = new WeakMap();
9
+ function styleEffect(subject, values) {
10
+ const elements = resolveElements(subject);
11
+ const subscriptions = [];
12
+ for (let i = 0; i < elements.length; i++) {
13
+ const element = elements[i];
14
+ const state = stateMap.get(element) ?? new MotionValueState();
15
+ stateMap.set(element, state);
16
+ for (const key in values) {
17
+ const value = values[key];
18
+ const remove = addValue(element, state, key, value);
19
+ subscriptions.push(remove);
20
+ }
21
+ }
22
+ return () => {
23
+ for (const cancel of subscriptions)
24
+ cancel();
25
+ };
26
+ }
27
+ function addValue(element, state, key, value) {
28
+ let render = undefined;
29
+ let computed = undefined;
30
+ if (transformProps.has(key)) {
31
+ if (!state.get("transform")) {
32
+ state.set("transform", new MotionValue("none"), () => {
33
+ element.style.transform = buildTransform(state);
34
+ });
35
+ }
36
+ computed = state.get("transform");
37
+ }
38
+ else if (isCSSVar(key)) {
39
+ render = () => {
40
+ element.style.setProperty(key, state.latest[key]);
41
+ };
42
+ }
43
+ else {
44
+ render = () => {
45
+ element.style[key] = state.latest[key];
46
+ };
47
+ }
48
+ return state.set(key, value, render, computed);
49
+ }
50
+
51
+ export { styleEffect };