motion 12.9.7 → 12.10.1
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/cjs/index.js +777 -670
- package/dist/cjs/react-client.js +271 -247
- package/dist/cjs/react-m.js +3 -3
- package/dist/es/framer-motion/dist/es/render/dom/scroll/track.mjs +4 -3
- package/dist/es/motion/lib/index.mjs +1 -1
- package/dist/es/motion/lib/react.mjs +1 -1
- package/dist/es/motion-dom/dist/es/animation/JSAnimation.mjs +3 -1
- package/dist/es/motion-dom/dist/es/animation/drivers/{driver-frameloop.mjs → frame.mjs} +1 -1
- package/dist/es/motion-dom/dist/es/effects/MotionValueState.mjs +41 -0
- package/dist/es/motion-dom/dist/es/effects/style/index.mjs +51 -0
- package/dist/es/motion-dom/dist/es/effects/style/transform.mjs +38 -0
- package/dist/es/motion-dom/dist/es/gestures/press/index.mjs +4 -2
- package/dist/es/motion-dom/dist/es/value/index.mjs +20 -0
- package/dist/motion.dev.js +777 -670
- package/dist/motion.js +1 -1
- package/package.json +3 -3
- package/dist/es/motion-dom/dist/es/effects/style-effect.mjs +0 -36
package/dist/cjs/react-client.js
CHANGED
|
@@ -991,7 +991,7 @@ function mix(from, to, p) {
|
|
|
991
991
|
const frameloopDriver = (update) => {
|
|
992
992
|
const passTimestamp = ({ timestamp }) => update(timestamp);
|
|
993
993
|
return {
|
|
994
|
-
start: () => frame.update(passTimestamp,
|
|
994
|
+
start: (keepAlive = true) => frame.update(passTimestamp, keepAlive),
|
|
995
995
|
stop: () => cancelFrame(passTimestamp),
|
|
996
996
|
/**
|
|
997
997
|
* If we're processing this frame we can use the
|
|
@@ -1818,6 +1818,7 @@ class JSAnimation extends WithPromise {
|
|
|
1818
1818
|
else if (this.driver) {
|
|
1819
1819
|
this.startTime = this.driver.now() - newTime / this.playbackSpeed;
|
|
1820
1820
|
}
|
|
1821
|
+
this.driver?.start(false);
|
|
1821
1822
|
}
|
|
1822
1823
|
get speed() {
|
|
1823
1824
|
return this.playbackSpeed;
|
|
@@ -1906,6 +1907,7 @@ class JSAnimation extends WithPromise {
|
|
|
1906
1907
|
this.options.ease = "linear";
|
|
1907
1908
|
this.initAnimation();
|
|
1908
1909
|
}
|
|
1910
|
+
this.driver?.stop();
|
|
1909
1911
|
return timeline.observe(this);
|
|
1910
1912
|
}
|
|
1911
1913
|
}
|
|
@@ -3187,243 +3189,6 @@ function resolveElements(elementOrSelector, scope, selectorCache) {
|
|
|
3187
3189
|
return Array.from(elementOrSelector);
|
|
3188
3190
|
}
|
|
3189
3191
|
|
|
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
3192
|
/**
|
|
3428
3193
|
* Maximum time between the value of two frames, beyond which we
|
|
3429
3194
|
* assume the velocity has since been 0.
|
|
@@ -3477,6 +3242,11 @@ class MotionValue {
|
|
|
3477
3242
|
// Update update subscribers
|
|
3478
3243
|
if (this.current !== this.prev) {
|
|
3479
3244
|
this.events.change?.notify(this.current);
|
|
3245
|
+
if (this.dependents) {
|
|
3246
|
+
for (const dependent of this.dependents) {
|
|
3247
|
+
dependent.dirty();
|
|
3248
|
+
}
|
|
3249
|
+
}
|
|
3480
3250
|
}
|
|
3481
3251
|
// Update render subscribers
|
|
3482
3252
|
if (render) {
|
|
@@ -3618,6 +3388,20 @@ class MotionValue {
|
|
|
3618
3388
|
if (this.stopPassiveEffect)
|
|
3619
3389
|
this.stopPassiveEffect();
|
|
3620
3390
|
}
|
|
3391
|
+
dirty() {
|
|
3392
|
+
this.events.change?.notify(this.current);
|
|
3393
|
+
}
|
|
3394
|
+
addDependent(dependent) {
|
|
3395
|
+
if (!this.dependents) {
|
|
3396
|
+
this.dependents = new Set();
|
|
3397
|
+
}
|
|
3398
|
+
this.dependents.add(dependent);
|
|
3399
|
+
}
|
|
3400
|
+
removeDependent(dependent) {
|
|
3401
|
+
if (this.dependents) {
|
|
3402
|
+
this.dependents.delete(dependent);
|
|
3403
|
+
}
|
|
3404
|
+
}
|
|
3621
3405
|
/**
|
|
3622
3406
|
* Returns the latest state of `MotionValue`
|
|
3623
3407
|
*
|
|
@@ -3713,6 +3497,7 @@ class MotionValue {
|
|
|
3713
3497
|
* @public
|
|
3714
3498
|
*/
|
|
3715
3499
|
destroy() {
|
|
3500
|
+
this.dependents?.clear();
|
|
3716
3501
|
this.events.destroy?.notify();
|
|
3717
3502
|
this.clearListeners();
|
|
3718
3503
|
this.stop();
|
|
@@ -3725,15 +3510,6 @@ function motionValue(init, options) {
|
|
|
3725
3510
|
return new MotionValue(init, options);
|
|
3726
3511
|
}
|
|
3727
3512
|
|
|
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
3513
|
/**
|
|
3738
3514
|
* Provided a value and a ValueType, returns the value as that value type.
|
|
3739
3515
|
*/
|
|
@@ -3743,6 +3519,254 @@ const getValueAsType = (value, type) => {
|
|
|
3743
3519
|
: value;
|
|
3744
3520
|
};
|
|
3745
3521
|
|
|
3522
|
+
const { schedule: microtask, cancel: cancelMicrotask } =
|
|
3523
|
+
/* @__PURE__ */ createRenderBatcher(queueMicrotask, false);
|
|
3524
|
+
|
|
3525
|
+
const isDragging = {
|
|
3526
|
+
x: false,
|
|
3527
|
+
y: false,
|
|
3528
|
+
};
|
|
3529
|
+
function isDragActive() {
|
|
3530
|
+
return isDragging.x || isDragging.y;
|
|
3531
|
+
}
|
|
3532
|
+
|
|
3533
|
+
function setDragLock(axis) {
|
|
3534
|
+
if (axis === "x" || axis === "y") {
|
|
3535
|
+
if (isDragging[axis]) {
|
|
3536
|
+
return null;
|
|
3537
|
+
}
|
|
3538
|
+
else {
|
|
3539
|
+
isDragging[axis] = true;
|
|
3540
|
+
return () => {
|
|
3541
|
+
isDragging[axis] = false;
|
|
3542
|
+
};
|
|
3543
|
+
}
|
|
3544
|
+
}
|
|
3545
|
+
else {
|
|
3546
|
+
if (isDragging.x || isDragging.y) {
|
|
3547
|
+
return null;
|
|
3548
|
+
}
|
|
3549
|
+
else {
|
|
3550
|
+
isDragging.x = isDragging.y = true;
|
|
3551
|
+
return () => {
|
|
3552
|
+
isDragging.x = isDragging.y = false;
|
|
3553
|
+
};
|
|
3554
|
+
}
|
|
3555
|
+
}
|
|
3556
|
+
}
|
|
3557
|
+
|
|
3558
|
+
function setupGesture(elementOrSelector, options) {
|
|
3559
|
+
const elements = resolveElements(elementOrSelector);
|
|
3560
|
+
const gestureAbortController = new AbortController();
|
|
3561
|
+
const eventOptions = {
|
|
3562
|
+
passive: true,
|
|
3563
|
+
...options,
|
|
3564
|
+
signal: gestureAbortController.signal,
|
|
3565
|
+
};
|
|
3566
|
+
const cancel = () => gestureAbortController.abort();
|
|
3567
|
+
return [elements, eventOptions, cancel];
|
|
3568
|
+
}
|
|
3569
|
+
|
|
3570
|
+
function isValidHover(event) {
|
|
3571
|
+
return !(event.pointerType === "touch" || isDragActive());
|
|
3572
|
+
}
|
|
3573
|
+
/**
|
|
3574
|
+
* Create a hover gesture. hover() is different to .addEventListener("pointerenter")
|
|
3575
|
+
* in that it has an easier syntax, filters out polyfilled touch events, interoperates
|
|
3576
|
+
* with drag gestures, and automatically removes the "pointerennd" event listener when the hover ends.
|
|
3577
|
+
*
|
|
3578
|
+
* @public
|
|
3579
|
+
*/
|
|
3580
|
+
function hover(elementOrSelector, onHoverStart, options = {}) {
|
|
3581
|
+
const [elements, eventOptions, cancel] = setupGesture(elementOrSelector, options);
|
|
3582
|
+
const onPointerEnter = (enterEvent) => {
|
|
3583
|
+
if (!isValidHover(enterEvent))
|
|
3584
|
+
return;
|
|
3585
|
+
const { target } = enterEvent;
|
|
3586
|
+
const onHoverEnd = onHoverStart(target, enterEvent);
|
|
3587
|
+
if (typeof onHoverEnd !== "function" || !target)
|
|
3588
|
+
return;
|
|
3589
|
+
const onPointerLeave = (leaveEvent) => {
|
|
3590
|
+
if (!isValidHover(leaveEvent))
|
|
3591
|
+
return;
|
|
3592
|
+
onHoverEnd(leaveEvent);
|
|
3593
|
+
target.removeEventListener("pointerleave", onPointerLeave);
|
|
3594
|
+
};
|
|
3595
|
+
target.addEventListener("pointerleave", onPointerLeave, eventOptions);
|
|
3596
|
+
};
|
|
3597
|
+
elements.forEach((element) => {
|
|
3598
|
+
element.addEventListener("pointerenter", onPointerEnter, eventOptions);
|
|
3599
|
+
});
|
|
3600
|
+
return cancel;
|
|
3601
|
+
}
|
|
3602
|
+
|
|
3603
|
+
/**
|
|
3604
|
+
* Recursively traverse up the tree to check whether the provided child node
|
|
3605
|
+
* is the parent or a descendant of it.
|
|
3606
|
+
*
|
|
3607
|
+
* @param parent - Element to find
|
|
3608
|
+
* @param child - Element to test against parent
|
|
3609
|
+
*/
|
|
3610
|
+
const isNodeOrChild = (parent, child) => {
|
|
3611
|
+
if (!child) {
|
|
3612
|
+
return false;
|
|
3613
|
+
}
|
|
3614
|
+
else if (parent === child) {
|
|
3615
|
+
return true;
|
|
3616
|
+
}
|
|
3617
|
+
else {
|
|
3618
|
+
return isNodeOrChild(parent, child.parentElement);
|
|
3619
|
+
}
|
|
3620
|
+
};
|
|
3621
|
+
|
|
3622
|
+
const isPrimaryPointer = (event) => {
|
|
3623
|
+
if (event.pointerType === "mouse") {
|
|
3624
|
+
return typeof event.button !== "number" || event.button <= 0;
|
|
3625
|
+
}
|
|
3626
|
+
else {
|
|
3627
|
+
/**
|
|
3628
|
+
* isPrimary is true for all mice buttons, whereas every touch point
|
|
3629
|
+
* is regarded as its own input. So subsequent concurrent touch points
|
|
3630
|
+
* will be false.
|
|
3631
|
+
*
|
|
3632
|
+
* Specifically match against false here as incomplete versions of
|
|
3633
|
+
* PointerEvents in very old browser might have it set as undefined.
|
|
3634
|
+
*/
|
|
3635
|
+
return event.isPrimary !== false;
|
|
3636
|
+
}
|
|
3637
|
+
};
|
|
3638
|
+
|
|
3639
|
+
const focusableElements = new Set([
|
|
3640
|
+
"BUTTON",
|
|
3641
|
+
"INPUT",
|
|
3642
|
+
"SELECT",
|
|
3643
|
+
"TEXTAREA",
|
|
3644
|
+
"A",
|
|
3645
|
+
]);
|
|
3646
|
+
function isElementKeyboardAccessible(element) {
|
|
3647
|
+
return (focusableElements.has(element.tagName) ||
|
|
3648
|
+
element.tabIndex !== -1);
|
|
3649
|
+
}
|
|
3650
|
+
|
|
3651
|
+
const isPressing = new WeakSet();
|
|
3652
|
+
|
|
3653
|
+
/**
|
|
3654
|
+
* Filter out events that are not "Enter" keys.
|
|
3655
|
+
*/
|
|
3656
|
+
function filterEvents(callback) {
|
|
3657
|
+
return (event) => {
|
|
3658
|
+
if (event.key !== "Enter")
|
|
3659
|
+
return;
|
|
3660
|
+
callback(event);
|
|
3661
|
+
};
|
|
3662
|
+
}
|
|
3663
|
+
function firePointerEvent(target, type) {
|
|
3664
|
+
target.dispatchEvent(new PointerEvent("pointer" + type, { isPrimary: true, bubbles: true }));
|
|
3665
|
+
}
|
|
3666
|
+
const enableKeyboardPress = (focusEvent, eventOptions) => {
|
|
3667
|
+
const element = focusEvent.currentTarget;
|
|
3668
|
+
if (!element)
|
|
3669
|
+
return;
|
|
3670
|
+
const handleKeydown = filterEvents(() => {
|
|
3671
|
+
if (isPressing.has(element))
|
|
3672
|
+
return;
|
|
3673
|
+
firePointerEvent(element, "down");
|
|
3674
|
+
const handleKeyup = filterEvents(() => {
|
|
3675
|
+
firePointerEvent(element, "up");
|
|
3676
|
+
});
|
|
3677
|
+
const handleBlur = () => firePointerEvent(element, "cancel");
|
|
3678
|
+
element.addEventListener("keyup", handleKeyup, eventOptions);
|
|
3679
|
+
element.addEventListener("blur", handleBlur, eventOptions);
|
|
3680
|
+
});
|
|
3681
|
+
element.addEventListener("keydown", handleKeydown, eventOptions);
|
|
3682
|
+
/**
|
|
3683
|
+
* Add an event listener that fires on blur to remove the keydown events.
|
|
3684
|
+
*/
|
|
3685
|
+
element.addEventListener("blur", () => element.removeEventListener("keydown", handleKeydown), eventOptions);
|
|
3686
|
+
};
|
|
3687
|
+
|
|
3688
|
+
/**
|
|
3689
|
+
* Filter out events that are not primary pointer events, or are triggering
|
|
3690
|
+
* while a Motion gesture is active.
|
|
3691
|
+
*/
|
|
3692
|
+
function isValidPressEvent(event) {
|
|
3693
|
+
return isPrimaryPointer(event) && !isDragActive();
|
|
3694
|
+
}
|
|
3695
|
+
/**
|
|
3696
|
+
* Create a press gesture.
|
|
3697
|
+
*
|
|
3698
|
+
* Press is different to `"pointerdown"`, `"pointerup"` in that it
|
|
3699
|
+
* automatically filters out secondary pointer events like right
|
|
3700
|
+
* click and multitouch.
|
|
3701
|
+
*
|
|
3702
|
+
* It also adds accessibility support for keyboards, where
|
|
3703
|
+
* an element with a press gesture will receive focus and
|
|
3704
|
+
* trigger on Enter `"keydown"` and `"keyup"` events.
|
|
3705
|
+
*
|
|
3706
|
+
* This is different to a browser's `"click"` event, which does
|
|
3707
|
+
* respond to keyboards but only for the `"click"` itself, rather
|
|
3708
|
+
* than the press start and end/cancel. The element also needs
|
|
3709
|
+
* to be focusable for this to work, whereas a press gesture will
|
|
3710
|
+
* make an element focusable by default.
|
|
3711
|
+
*
|
|
3712
|
+
* @public
|
|
3713
|
+
*/
|
|
3714
|
+
function press(targetOrSelector, onPressStart, options = {}) {
|
|
3715
|
+
const [targets, eventOptions, cancelEvents] = setupGesture(targetOrSelector, options);
|
|
3716
|
+
const startPress = (startEvent) => {
|
|
3717
|
+
const target = startEvent.currentTarget;
|
|
3718
|
+
if (!isValidPressEvent(startEvent) || isPressing.has(target))
|
|
3719
|
+
return;
|
|
3720
|
+
isPressing.add(target);
|
|
3721
|
+
const onPressEnd = onPressStart(target, startEvent);
|
|
3722
|
+
const onPointerEnd = (endEvent, success) => {
|
|
3723
|
+
window.removeEventListener("pointerup", onPointerUp);
|
|
3724
|
+
window.removeEventListener("pointercancel", onPointerCancel);
|
|
3725
|
+
if (isPressing.has(target)) {
|
|
3726
|
+
isPressing.delete(target);
|
|
3727
|
+
}
|
|
3728
|
+
if (!isValidPressEvent(endEvent)) {
|
|
3729
|
+
return;
|
|
3730
|
+
}
|
|
3731
|
+
if (typeof onPressEnd === "function") {
|
|
3732
|
+
onPressEnd(endEvent, { success });
|
|
3733
|
+
}
|
|
3734
|
+
};
|
|
3735
|
+
const onPointerUp = (upEvent) => {
|
|
3736
|
+
onPointerEnd(upEvent, target === window ||
|
|
3737
|
+
target === document ||
|
|
3738
|
+
options.useGlobalTarget ||
|
|
3739
|
+
isNodeOrChild(target, upEvent.target));
|
|
3740
|
+
};
|
|
3741
|
+
const onPointerCancel = (cancelEvent) => {
|
|
3742
|
+
onPointerEnd(cancelEvent, false);
|
|
3743
|
+
};
|
|
3744
|
+
window.addEventListener("pointerup", onPointerUp, eventOptions);
|
|
3745
|
+
window.addEventListener("pointercancel", onPointerCancel, eventOptions);
|
|
3746
|
+
};
|
|
3747
|
+
targets.forEach((target) => {
|
|
3748
|
+
const pointerDownTarget = options.useGlobalTarget ? window : target;
|
|
3749
|
+
pointerDownTarget.addEventListener("pointerdown", startPress, eventOptions);
|
|
3750
|
+
if (target instanceof HTMLElement) {
|
|
3751
|
+
target.addEventListener("focus", (event) => enableKeyboardPress(event, eventOptions));
|
|
3752
|
+
if (!isElementKeyboardAccessible(target) &&
|
|
3753
|
+
!target.hasAttribute("tabindex")) {
|
|
3754
|
+
target.tabIndex = 0;
|
|
3755
|
+
}
|
|
3756
|
+
}
|
|
3757
|
+
});
|
|
3758
|
+
return cancelEvents;
|
|
3759
|
+
}
|
|
3760
|
+
|
|
3761
|
+
/**
|
|
3762
|
+
* A list of all ValueTypes
|
|
3763
|
+
*/
|
|
3764
|
+
const valueTypes = [...dimensionValueTypes, color, complex];
|
|
3765
|
+
/**
|
|
3766
|
+
* Tests a value against the list of ValueTypes
|
|
3767
|
+
*/
|
|
3768
|
+
const findValueType = (v) => valueTypes.find(testValueType(v));
|
|
3769
|
+
|
|
3746
3770
|
const isKeyframesTarget = (v) => {
|
|
3747
3771
|
return Array.isArray(v);
|
|
3748
3772
|
};
|
package/dist/cjs/react-m.js
CHANGED
|
@@ -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
|
*/
|
|
@@ -42,9 +42,9 @@ function scrollInfo(onScroll, { container = document.documentElement, ...options
|
|
|
42
42
|
handler.notify();
|
|
43
43
|
};
|
|
44
44
|
const listener = () => {
|
|
45
|
-
frame.read(measureAll
|
|
46
|
-
frame.read(updateAll
|
|
47
|
-
frame.preUpdate(notifyAll
|
|
45
|
+
frame.read(measureAll);
|
|
46
|
+
frame.read(updateAll);
|
|
47
|
+
frame.preUpdate(notifyAll);
|
|
48
48
|
};
|
|
49
49
|
scrollListeners.set(container, listener);
|
|
50
50
|
const target = getEventTarget(container);
|
|
@@ -53,6 +53,7 @@ function scrollInfo(onScroll, { container = document.documentElement, ...options
|
|
|
53
53
|
resizeListeners.set(container, resize(container, listener));
|
|
54
54
|
}
|
|
55
55
|
target.addEventListener("scroll", listener, { passive: true });
|
|
56
|
+
listener();
|
|
56
57
|
}
|
|
57
58
|
const listener = scrollListeners.get(container);
|
|
58
59
|
frame.read(listener, false, true);
|
|
@@ -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
|
|
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
|
|
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';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { time } from '../frameloop/sync-time.mjs';
|
|
2
2
|
import { activeAnimations } from '../stats/animation-count.mjs';
|
|
3
3
|
import { mix } from '../utils/mix/index.mjs';
|
|
4
|
-
import { frameloopDriver } from './drivers/
|
|
4
|
+
import { frameloopDriver } from './drivers/frame.mjs';
|
|
5
5
|
import { inertia } from './generators/inertia.mjs';
|
|
6
6
|
import { keyframes } from './generators/keyframes.mjs';
|
|
7
7
|
import { calcGeneratorDuration } from './generators/utils/calc-duration.mjs';
|
|
@@ -247,6 +247,7 @@ class JSAnimation extends WithPromise {
|
|
|
247
247
|
else if (this.driver) {
|
|
248
248
|
this.startTime = this.driver.now() - newTime / this.playbackSpeed;
|
|
249
249
|
}
|
|
250
|
+
this.driver?.start(false);
|
|
250
251
|
}
|
|
251
252
|
get speed() {
|
|
252
253
|
return this.playbackSpeed;
|
|
@@ -336,6 +337,7 @@ class JSAnimation extends WithPromise {
|
|
|
336
337
|
this.options.ease = "linear";
|
|
337
338
|
this.initAnimation();
|
|
338
339
|
}
|
|
340
|
+
this.driver?.stop();
|
|
339
341
|
return timeline.observe(this);
|
|
340
342
|
}
|
|
341
343
|
}
|
|
@@ -4,7 +4,7 @@ import { frame, cancelFrame, frameData } from '../../frameloop/frame.mjs';
|
|
|
4
4
|
const frameloopDriver = (update) => {
|
|
5
5
|
const passTimestamp = ({ timestamp }) => update(timestamp);
|
|
6
6
|
return {
|
|
7
|
-
start: () => frame.update(passTimestamp,
|
|
7
|
+
start: (keepAlive = true) => frame.update(passTimestamp, keepAlive),
|
|
8
8
|
stop: () => cancelFrame(passTimestamp),
|
|
9
9
|
/**
|
|
10
10
|
* If we're processing this frame we can use the
|