@teamturing/react-kit 2.3.1 → 2.5.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/dist/core/Dialog/index.d.ts +16 -0
- package/dist/core/DialogHandler/index.d.ts +13 -0
- package/dist/core/Grid/index.d.ts +2 -2
- package/dist/core/MotionView/index.d.ts +3 -0
- package/dist/core/Stack/index.d.ts +2 -2
- package/dist/enigma/EnigmaUI/index.d.ts +12 -2
- package/dist/hook/useDialogHandler.d.ts +6 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +9769 -325
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/isFunction.d.ts +1 -0
- package/esm/core/Dialog/index.js +188 -0
- package/esm/core/DialogHandler/index.js +33 -0
- package/esm/core/MotionView/index.js +6 -0
- package/esm/enigma/EnigmaUI/index.js +6 -1
- package/esm/hook/useDialogHandler.js +14 -0
- package/esm/index.js +3 -0
- package/esm/node_modules/framer-motion/dist/es/animation/animators/instant.js +40 -0
- package/esm/node_modules/framer-motion/dist/es/animation/animators/js/driver-frameloop.js +16 -0
- package/esm/node_modules/framer-motion/dist/es/animation/animators/js/index.js +303 -0
- package/esm/node_modules/framer-motion/dist/es/animation/animators/waapi/create-accelerated-animation.js +199 -0
- package/esm/node_modules/framer-motion/dist/es/animation/animators/waapi/easing.js +31 -0
- package/esm/node_modules/framer-motion/dist/es/animation/animators/waapi/index.js +23 -0
- package/esm/node_modules/framer-motion/dist/es/animation/animators/waapi/utils/get-final-keyframe.js +8 -0
- package/esm/node_modules/framer-motion/dist/es/animation/generators/inertia.js +87 -0
- package/esm/node_modules/framer-motion/dist/es/animation/generators/keyframes.js +51 -0
- package/esm/node_modules/framer-motion/dist/es/animation/generators/spring/find.js +89 -0
- package/esm/node_modules/framer-motion/dist/es/animation/generators/spring/index.js +129 -0
- package/esm/node_modules/framer-motion/dist/es/animation/generators/utils/calc-duration.js +17 -0
- package/esm/node_modules/framer-motion/dist/es/animation/generators/utils/velocity.js +9 -0
- package/esm/node_modules/framer-motion/dist/es/animation/interfaces/motion-value.js +101 -0
- package/esm/node_modules/framer-motion/dist/es/animation/interfaces/single-value.js +11 -0
- package/esm/node_modules/framer-motion/dist/es/animation/interfaces/visual-element-target.js +71 -0
- package/esm/node_modules/framer-motion/dist/es/animation/interfaces/visual-element-variant.js +63 -0
- package/esm/node_modules/framer-motion/dist/es/animation/interfaces/visual-element.js +24 -0
- package/esm/node_modules/framer-motion/dist/es/animation/optimized-appear/data-id.js +6 -0
- package/esm/node_modules/framer-motion/dist/es/animation/utils/default-transitions.js +40 -0
- package/esm/node_modules/framer-motion/dist/es/animation/utils/is-animatable.js +30 -0
- package/esm/node_modules/framer-motion/dist/es/animation/utils/is-animation-controls.js +5 -0
- package/esm/node_modules/framer-motion/dist/es/animation/utils/is-keyframes-target.js +5 -0
- package/esm/node_modules/framer-motion/dist/es/animation/utils/is-none.js +12 -0
- package/esm/node_modules/framer-motion/dist/es/animation/utils/keyframes.js +45 -0
- package/esm/node_modules/framer-motion/dist/es/animation/utils/transitions.js +13 -0
- package/esm/node_modules/framer-motion/dist/es/components/AnimatePresence/PopChild.js +71 -0
- package/esm/node_modules/framer-motion/dist/es/components/AnimatePresence/PresenceChild.js +56 -0
- package/esm/node_modules/framer-motion/dist/es/components/AnimatePresence/index.js +158 -0
- package/esm/node_modules/framer-motion/dist/es/components/AnimatePresence/use-presence.js +40 -0
- package/esm/node_modules/framer-motion/dist/es/context/LayoutGroupContext.js +5 -0
- package/esm/node_modules/framer-motion/dist/es/context/LazyContext.js +5 -0
- package/esm/node_modules/framer-motion/dist/es/context/MotionConfigContext.js +12 -0
- package/esm/node_modules/framer-motion/dist/es/context/MotionContext/create.js +13 -0
- package/esm/node_modules/framer-motion/dist/es/context/MotionContext/index.js +5 -0
- package/esm/node_modules/framer-motion/dist/es/context/MotionContext/utils.js +17 -0
- package/esm/node_modules/framer-motion/dist/es/context/PresenceContext.js +8 -0
- package/esm/node_modules/framer-motion/dist/es/context/SwitchLayoutGroupContext.js +8 -0
- package/esm/node_modules/framer-motion/dist/es/debug/record.js +7 -0
- package/esm/node_modules/framer-motion/dist/es/easing/anticipate.js +5 -0
- package/esm/node_modules/framer-motion/dist/es/easing/back.js +9 -0
- package/esm/node_modules/framer-motion/dist/es/easing/circ.js +8 -0
- package/esm/node_modules/framer-motion/dist/es/easing/cubic-bezier.js +51 -0
- package/esm/node_modules/framer-motion/dist/es/easing/ease.js +7 -0
- package/esm/node_modules/framer-motion/dist/es/easing/modifiers/mirror.js +5 -0
- package/esm/node_modules/framer-motion/dist/es/easing/modifiers/reverse.js +5 -0
- package/esm/node_modules/framer-motion/dist/es/easing/utils/is-bezier-definition.js +3 -0
- package/esm/node_modules/framer-motion/dist/es/easing/utils/is-easing-array.js +5 -0
- package/esm/node_modules/framer-motion/dist/es/easing/utils/map.js +37 -0
- package/esm/node_modules/framer-motion/dist/es/events/add-dom-event.js +6 -0
- package/esm/node_modules/framer-motion/dist/es/events/add-pointer-event.js +8 -0
- package/esm/node_modules/framer-motion/dist/es/events/event-info.js +15 -0
- package/esm/node_modules/framer-motion/dist/es/events/utils/is-primary-pointer.js +18 -0
- package/esm/node_modules/framer-motion/dist/es/frameloop/batcher.js +60 -0
- package/esm/node_modules/framer-motion/dist/es/frameloop/frame.js +6 -0
- package/esm/node_modules/framer-motion/dist/es/frameloop/render-step.js +104 -0
- package/esm/node_modules/framer-motion/dist/es/gestures/drag/VisualElementDragControls.js +457 -0
- package/esm/node_modules/framer-motion/dist/es/gestures/drag/index.js +27 -0
- package/esm/node_modules/framer-motion/dist/es/gestures/drag/utils/constraints.js +125 -0
- package/esm/node_modules/framer-motion/dist/es/gestures/drag/utils/lock.js +53 -0
- package/esm/node_modules/framer-motion/dist/es/gestures/focus.js +41 -0
- package/esm/node_modules/framer-motion/dist/es/gestures/hover.js +32 -0
- package/esm/node_modules/framer-motion/dist/es/gestures/pan/PanSession.js +148 -0
- package/esm/node_modules/framer-motion/dist/es/gestures/pan/index.js +46 -0
- package/esm/node_modules/framer-motion/dist/es/gestures/press.js +120 -0
- package/esm/node_modules/framer-motion/dist/es/gestures/utils/is-node-or-child.js +20 -0
- package/esm/node_modules/framer-motion/dist/es/motion/features/Feature.js +9 -0
- package/esm/node_modules/framer-motion/dist/es/motion/features/animation/exit.js +31 -0
- package/esm/node_modules/framer-motion/dist/es/motion/features/animation/index.js +38 -0
- package/esm/node_modules/framer-motion/dist/es/motion/features/animations.js +13 -0
- package/esm/node_modules/framer-motion/dist/es/motion/features/definitions.js +28 -0
- package/esm/node_modules/framer-motion/dist/es/motion/features/drag.js +17 -0
- package/esm/node_modules/framer-motion/dist/es/motion/features/gestures.js +21 -0
- package/esm/node_modules/framer-motion/dist/es/motion/features/layout/MeasureLayout.js +131 -0
- package/esm/node_modules/framer-motion/dist/es/motion/features/layout.js +11 -0
- package/esm/node_modules/framer-motion/dist/es/motion/features/load-features.js +12 -0
- package/esm/node_modules/framer-motion/dist/es/motion/features/viewport/index.js +72 -0
- package/esm/node_modules/framer-motion/dist/es/motion/features/viewport/observers.js +49 -0
- package/esm/node_modules/framer-motion/dist/es/motion/index.js +79 -0
- package/esm/node_modules/framer-motion/dist/es/motion/utils/is-forced-motion-value.js +11 -0
- package/esm/node_modules/framer-motion/dist/es/motion/utils/symbol.js +3 -0
- package/esm/node_modules/framer-motion/dist/es/motion/utils/use-motion-ref.js +33 -0
- package/esm/node_modules/framer-motion/dist/es/motion/utils/use-visual-element.js +75 -0
- package/esm/node_modules/framer-motion/dist/es/motion/utils/use-visual-state.js +81 -0
- package/esm/node_modules/framer-motion/dist/es/motion/utils/valid-prop.js +59 -0
- package/esm/node_modules/framer-motion/dist/es/projection/animation/mix-values.js +93 -0
- package/esm/node_modules/framer-motion/dist/es/projection/geometry/conversion.js +33 -0
- package/esm/node_modules/framer-motion/dist/es/projection/geometry/copy.js +20 -0
- package/esm/node_modules/framer-motion/dist/es/projection/geometry/delta-apply.js +122 -0
- package/esm/node_modules/framer-motion/dist/es/projection/geometry/delta-calc.js +41 -0
- package/esm/node_modules/framer-motion/dist/es/projection/geometry/delta-remove.js +54 -0
- package/esm/node_modules/framer-motion/dist/es/projection/geometry/models.js +17 -0
- package/esm/node_modules/framer-motion/dist/es/projection/geometry/utils.js +25 -0
- package/esm/node_modules/framer-motion/dist/es/projection/node/DocumentProjectionNode.js +13 -0
- package/esm/node_modules/framer-motion/dist/es/projection/node/HTMLProjectionNode.js +27 -0
- package/esm/node_modules/framer-motion/dist/es/projection/node/create-projection-node.js +1494 -0
- package/esm/node_modules/framer-motion/dist/es/projection/node/state.js +19 -0
- package/esm/node_modules/framer-motion/dist/es/projection/shared/stack.js +112 -0
- package/esm/node_modules/framer-motion/dist/es/projection/styles/scale-border-radius.js +41 -0
- package/esm/node_modules/framer-motion/dist/es/projection/styles/scale-box-shadow.js +35 -0
- package/esm/node_modules/framer-motion/dist/es/projection/styles/scale-correction.js +6 -0
- package/esm/node_modules/framer-motion/dist/es/projection/styles/transform.js +42 -0
- package/esm/node_modules/framer-motion/dist/es/projection/utils/each-axis.js +5 -0
- package/esm/node_modules/framer-motion/dist/es/projection/utils/has-transform.js +24 -0
- package/esm/node_modules/framer-motion/dist/es/projection/utils/measure.js +17 -0
- package/esm/node_modules/framer-motion/dist/es/render/VisualElement.js +507 -0
- package/esm/node_modules/framer-motion/dist/es/render/dom/DOMVisualElement.js +48 -0
- package/esm/node_modules/framer-motion/dist/es/render/dom/create-visual-element.js +11 -0
- package/esm/node_modules/framer-motion/dist/es/render/dom/motion-proxy.js +47 -0
- package/esm/node_modules/framer-motion/dist/es/render/dom/motion.js +23 -0
- package/esm/node_modules/framer-motion/dist/es/render/dom/use-render.js +35 -0
- package/esm/node_modules/framer-motion/dist/es/render/dom/utils/camel-to-dash.js +6 -0
- package/esm/node_modules/framer-motion/dist/es/render/dom/utils/create-config.js +19 -0
- package/esm/node_modules/framer-motion/dist/es/render/dom/utils/css-variables-conversion.js +89 -0
- package/esm/node_modules/framer-motion/dist/es/render/dom/utils/filter-props.js +57 -0
- package/esm/node_modules/framer-motion/dist/es/render/dom/utils/is-css-variable.js +6 -0
- package/esm/node_modules/framer-motion/dist/es/render/dom/utils/is-svg-component.js +30 -0
- package/esm/node_modules/framer-motion/dist/es/render/dom/utils/is-svg-element.js +5 -0
- package/esm/node_modules/framer-motion/dist/es/render/dom/utils/parse-dom-variant.js +15 -0
- package/esm/node_modules/framer-motion/dist/es/render/dom/utils/unit-conversion.js +230 -0
- package/esm/node_modules/framer-motion/dist/es/render/dom/value-types/animatable-none.js +15 -0
- package/esm/node_modules/framer-motion/dist/es/render/dom/value-types/defaults.js +30 -0
- package/esm/node_modules/framer-motion/dist/es/render/dom/value-types/dimensions.js +15 -0
- package/esm/node_modules/framer-motion/dist/es/render/dom/value-types/find.js +15 -0
- package/esm/node_modules/framer-motion/dist/es/render/dom/value-types/get-as-type.js +10 -0
- package/esm/node_modules/framer-motion/dist/es/render/dom/value-types/number.js +72 -0
- package/esm/node_modules/framer-motion/dist/es/render/dom/value-types/test.js +6 -0
- package/esm/node_modules/framer-motion/dist/es/render/dom/value-types/type-auto.js +9 -0
- package/esm/node_modules/framer-motion/dist/es/render/dom/value-types/type-int.js +8 -0
- package/esm/node_modules/framer-motion/dist/es/render/html/HTMLVisualElement.js +55 -0
- package/esm/node_modules/framer-motion/dist/es/render/html/config-motion.js +12 -0
- package/esm/node_modules/framer-motion/dist/es/render/html/use-props.js +57 -0
- package/esm/node_modules/framer-motion/dist/es/render/html/utils/build-styles.js +74 -0
- package/esm/node_modules/framer-motion/dist/es/render/html/utils/build-transform.js +45 -0
- package/esm/node_modules/framer-motion/dist/es/render/html/utils/create-render-state.js +8 -0
- package/esm/node_modules/framer-motion/dist/es/render/html/utils/render.js +9 -0
- package/esm/node_modules/framer-motion/dist/es/render/html/utils/scrape-motion-values.js +17 -0
- package/esm/node_modules/framer-motion/dist/es/render/html/utils/transform.js +28 -0
- package/esm/node_modules/framer-motion/dist/es/render/store.js +3 -0
- package/esm/node_modules/framer-motion/dist/es/render/svg/SVGVisualElement.js +46 -0
- package/esm/node_modules/framer-motion/dist/es/render/svg/config-motion.js +40 -0
- package/esm/node_modules/framer-motion/dist/es/render/svg/lowercase-elements.js +33 -0
- package/esm/node_modules/framer-motion/dist/es/render/svg/use-props.js +24 -0
- package/esm/node_modules/framer-motion/dist/es/render/svg/utils/build-attrs.js +52 -0
- package/esm/node_modules/framer-motion/dist/es/render/svg/utils/camel-case-attrs.js +30 -0
- package/esm/node_modules/framer-motion/dist/es/render/svg/utils/create-render-state.js +8 -0
- package/esm/node_modules/framer-motion/dist/es/render/svg/utils/is-svg-tag.js +3 -0
- package/esm/node_modules/framer-motion/dist/es/render/svg/utils/path.js +32 -0
- package/esm/node_modules/framer-motion/dist/es/render/svg/utils/render.js +12 -0
- package/esm/node_modules/framer-motion/dist/es/render/svg/utils/scrape-motion-values.js +18 -0
- package/esm/node_modules/framer-motion/dist/es/render/svg/utils/transform-origin.js +18 -0
- package/esm/node_modules/framer-motion/dist/es/render/utils/animation-state.js +319 -0
- package/esm/node_modules/framer-motion/dist/es/render/utils/compare-by-depth.js +3 -0
- package/esm/node_modules/framer-motion/dist/es/render/utils/flat-tree.js +24 -0
- package/esm/node_modules/framer-motion/dist/es/render/utils/is-controlling-variants.js +13 -0
- package/esm/node_modules/framer-motion/dist/es/render/utils/is-variant-label.js +8 -0
- package/esm/node_modules/framer-motion/dist/es/render/utils/motion-values.js +63 -0
- package/esm/node_modules/framer-motion/dist/es/render/utils/resolve-dynamic-variants.js +24 -0
- package/esm/node_modules/framer-motion/dist/es/render/utils/resolve-variants.js +26 -0
- package/esm/node_modules/framer-motion/dist/es/render/utils/setters.js +101 -0
- package/esm/node_modules/framer-motion/dist/es/render/utils/variant-props.js +12 -0
- package/esm/node_modules/framer-motion/dist/es/utils/array.js +11 -0
- package/esm/node_modules/framer-motion/dist/es/utils/clamp.js +3 -0
- package/esm/node_modules/framer-motion/dist/es/utils/delay.js +19 -0
- package/esm/node_modules/framer-motion/dist/es/utils/distance.js +9 -0
- package/esm/node_modules/framer-motion/dist/es/utils/errors.js +18 -0
- package/esm/node_modules/framer-motion/dist/es/utils/hsla-to-rgba.js +42 -0
- package/esm/node_modules/framer-motion/dist/es/utils/interpolate.js +92 -0
- package/esm/node_modules/framer-motion/dist/es/utils/is-browser.js +3 -0
- package/esm/node_modules/framer-motion/dist/es/utils/is-numerical-string.js +6 -0
- package/esm/node_modules/framer-motion/dist/es/utils/is-ref-object.js +6 -0
- package/esm/node_modules/framer-motion/dist/es/utils/is-zero-value-string.js +6 -0
- package/esm/node_modules/framer-motion/dist/es/utils/memo.js +10 -0
- package/esm/node_modules/framer-motion/dist/es/utils/mix-color.js +40 -0
- package/esm/node_modules/framer-motion/dist/es/utils/mix-complex.js +64 -0
- package/esm/node_modules/framer-motion/dist/es/utils/mix.js +24 -0
- package/esm/node_modules/framer-motion/dist/es/utils/noop.js +3 -0
- package/esm/node_modules/framer-motion/dist/es/utils/offsets/default.js +9 -0
- package/esm/node_modules/framer-motion/dist/es/utils/offsets/fill.js +12 -0
- package/esm/node_modules/framer-motion/dist/es/utils/offsets/time.js +5 -0
- package/esm/node_modules/framer-motion/dist/es/utils/pipe.js +11 -0
- package/esm/node_modules/framer-motion/dist/es/utils/progress.js +18 -0
- package/esm/node_modules/framer-motion/dist/es/utils/reduced-motion/index.js +19 -0
- package/esm/node_modules/framer-motion/dist/es/utils/reduced-motion/state.js +5 -0
- package/esm/node_modules/framer-motion/dist/es/utils/resolve-value.js +11 -0
- package/esm/node_modules/framer-motion/dist/es/utils/shallow-compare.js +14 -0
- package/esm/node_modules/framer-motion/dist/es/utils/subscription-manager.js +40 -0
- package/esm/node_modules/framer-motion/dist/es/utils/time-conversion.js +10 -0
- package/esm/node_modules/framer-motion/dist/es/utils/use-constant.js +18 -0
- package/esm/node_modules/framer-motion/dist/es/utils/use-force-update.js +19 -0
- package/esm/node_modules/framer-motion/dist/es/utils/use-instant-transition-state.js +5 -0
- package/esm/node_modules/framer-motion/dist/es/utils/use-is-mounted.js +15 -0
- package/esm/node_modules/framer-motion/dist/es/utils/use-isomorphic-effect.js +6 -0
- package/esm/node_modules/framer-motion/dist/es/utils/use-unmount-effect.js +7 -0
- package/esm/node_modules/framer-motion/dist/es/utils/velocity-per-second.js +11 -0
- package/esm/node_modules/framer-motion/dist/es/utils/warn-once.js +11 -0
- package/esm/node_modules/framer-motion/dist/es/value/index.js +331 -0
- package/esm/node_modules/framer-motion/dist/es/value/types/color/hex.js +40 -0
- package/esm/node_modules/framer-motion/dist/es/value/types/color/hsla.js +22 -0
- package/esm/node_modules/framer-motion/dist/es/value/types/color/index.js +28 -0
- package/esm/node_modules/framer-motion/dist/es/value/types/color/rgba.js +25 -0
- package/esm/node_modules/framer-motion/dist/es/value/types/color/utils.js +23 -0
- package/esm/node_modules/framer-motion/dist/es/value/types/complex/filter.js +30 -0
- package/esm/node_modules/framer-motion/dist/es/value/types/complex/index.js +92 -0
- package/esm/node_modules/framer-motion/dist/es/value/types/numbers/index.js +17 -0
- package/esm/node_modules/framer-motion/dist/es/value/types/numbers/units.js +19 -0
- package/esm/node_modules/framer-motion/dist/es/value/types/utils.js +15 -0
- package/esm/node_modules/framer-motion/dist/es/value/use-will-change/is.js +7 -0
- package/esm/node_modules/framer-motion/dist/es/value/utils/is-motion-value.js +3 -0
- package/esm/node_modules/framer-motion/dist/es/value/utils/resolve-motion-value.js +16 -0
- package/esm/packages/icons/esm/Close.js +17 -0
- package/esm/packages/token-studio/esm/token/elevation/index.js +5 -1
- package/esm/utils/isFunction.js +3 -0
- package/package.json +3 -3
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import { animateStyle } from './index.js';
|
|
2
|
+
import { isWaapiSupportedEasing } from './easing.js';
|
|
3
|
+
import { getFinalKeyframe } from './utils/get-final-keyframe.js';
|
|
4
|
+
import { animateValue } from '../js/index.js';
|
|
5
|
+
import { millisecondsToSeconds, secondsToMilliseconds } from '../../../utils/time-conversion.js';
|
|
6
|
+
import { memo } from '../../../utils/memo.js';
|
|
7
|
+
import { noop } from '../../../utils/noop.js';
|
|
8
|
+
import { frameData, frame, cancelFrame } from '../../../frameloop/frame.js';
|
|
9
|
+
|
|
10
|
+
const supportsWaapi = memo(() => Object.hasOwnProperty.call(Element.prototype, "animate"));
|
|
11
|
+
/**
|
|
12
|
+
* A list of values that can be hardware-accelerated.
|
|
13
|
+
*/
|
|
14
|
+
const acceleratedValues = new Set([
|
|
15
|
+
"opacity",
|
|
16
|
+
"clipPath",
|
|
17
|
+
"filter",
|
|
18
|
+
"transform",
|
|
19
|
+
"backgroundColor",
|
|
20
|
+
]);
|
|
21
|
+
/**
|
|
22
|
+
* 10ms is chosen here as it strikes a balance between smooth
|
|
23
|
+
* results (more than one keyframe per frame at 60fps) and
|
|
24
|
+
* keyframe quantity.
|
|
25
|
+
*/
|
|
26
|
+
const sampleDelta = 10; //ms
|
|
27
|
+
/**
|
|
28
|
+
* Implement a practical max duration for keyframe generation
|
|
29
|
+
* to prevent infinite loops
|
|
30
|
+
*/
|
|
31
|
+
const maxDuration = 20000;
|
|
32
|
+
const requiresPregeneratedKeyframes = (valueName, options) => options.type === "spring" ||
|
|
33
|
+
valueName === "backgroundColor" ||
|
|
34
|
+
!isWaapiSupportedEasing(options.ease);
|
|
35
|
+
function createAcceleratedAnimation(value, valueName, { onUpdate, onComplete, ...options }) {
|
|
36
|
+
const canAccelerateAnimation = supportsWaapi() &&
|
|
37
|
+
acceleratedValues.has(valueName) &&
|
|
38
|
+
!options.repeatDelay &&
|
|
39
|
+
options.repeatType !== "mirror" &&
|
|
40
|
+
options.damping !== 0 &&
|
|
41
|
+
options.type !== "inertia";
|
|
42
|
+
if (!canAccelerateAnimation)
|
|
43
|
+
return false;
|
|
44
|
+
/**
|
|
45
|
+
* TODO: Unify with js/index
|
|
46
|
+
*/
|
|
47
|
+
let hasStopped = false;
|
|
48
|
+
let resolveFinishedPromise;
|
|
49
|
+
let currentFinishedPromise;
|
|
50
|
+
/**
|
|
51
|
+
* Resolve the current Promise every time we enter the
|
|
52
|
+
* finished state. This is WAAPI-compatible behaviour.
|
|
53
|
+
*/
|
|
54
|
+
const updateFinishedPromise = () => {
|
|
55
|
+
currentFinishedPromise = new Promise((resolve) => {
|
|
56
|
+
resolveFinishedPromise = resolve;
|
|
57
|
+
});
|
|
58
|
+
};
|
|
59
|
+
// Create the first finished promise
|
|
60
|
+
updateFinishedPromise();
|
|
61
|
+
let { keyframes, duration = 300, ease, times } = options;
|
|
62
|
+
/**
|
|
63
|
+
* If this animation needs pre-generated keyframes then generate.
|
|
64
|
+
*/
|
|
65
|
+
if (requiresPregeneratedKeyframes(valueName, options)) {
|
|
66
|
+
const sampleAnimation = animateValue({
|
|
67
|
+
...options,
|
|
68
|
+
repeat: 0,
|
|
69
|
+
delay: 0,
|
|
70
|
+
});
|
|
71
|
+
let state = { done: false, value: keyframes[0] };
|
|
72
|
+
const pregeneratedKeyframes = [];
|
|
73
|
+
/**
|
|
74
|
+
* Bail after 20 seconds of pre-generated keyframes as it's likely
|
|
75
|
+
* we're heading for an infinite loop.
|
|
76
|
+
*/
|
|
77
|
+
let t = 0;
|
|
78
|
+
while (!state.done && t < maxDuration) {
|
|
79
|
+
state = sampleAnimation.sample(t);
|
|
80
|
+
pregeneratedKeyframes.push(state.value);
|
|
81
|
+
t += sampleDelta;
|
|
82
|
+
}
|
|
83
|
+
times = undefined;
|
|
84
|
+
keyframes = pregeneratedKeyframes;
|
|
85
|
+
duration = t - sampleDelta;
|
|
86
|
+
ease = "linear";
|
|
87
|
+
}
|
|
88
|
+
const animation = animateStyle(value.owner.current, valueName, keyframes, {
|
|
89
|
+
...options,
|
|
90
|
+
duration,
|
|
91
|
+
/**
|
|
92
|
+
* This function is currently not called if ease is provided
|
|
93
|
+
* as a function so the cast is safe.
|
|
94
|
+
*
|
|
95
|
+
* However it would be possible for a future refinement to port
|
|
96
|
+
* in easing pregeneration from Motion One for browsers that
|
|
97
|
+
* support the upcoming `linear()` easing function.
|
|
98
|
+
*/
|
|
99
|
+
ease: ease,
|
|
100
|
+
times,
|
|
101
|
+
});
|
|
102
|
+
/**
|
|
103
|
+
* WAAPI animations don't resolve startTime synchronously. But a blocked
|
|
104
|
+
* thread could delay the startTime resolution by a noticeable amount.
|
|
105
|
+
* For synching handoff animations with the new Motion animation we want
|
|
106
|
+
* to ensure startTime is synchronously set.
|
|
107
|
+
*/
|
|
108
|
+
if (options.syncStart) {
|
|
109
|
+
animation.startTime = frameData.isProcessing
|
|
110
|
+
? frameData.timestamp
|
|
111
|
+
: document.timeline
|
|
112
|
+
? document.timeline.currentTime
|
|
113
|
+
: performance.now();
|
|
114
|
+
}
|
|
115
|
+
const cancelAnimation = () => animation.cancel();
|
|
116
|
+
const safeCancel = () => {
|
|
117
|
+
frame.update(cancelAnimation);
|
|
118
|
+
resolveFinishedPromise();
|
|
119
|
+
updateFinishedPromise();
|
|
120
|
+
};
|
|
121
|
+
/**
|
|
122
|
+
* Prefer the `onfinish` prop as it's more widely supported than
|
|
123
|
+
* the `finished` promise.
|
|
124
|
+
*
|
|
125
|
+
* Here, we synchronously set the provided MotionValue to the end
|
|
126
|
+
* keyframe. If we didn't, when the WAAPI animation is finished it would
|
|
127
|
+
* be removed from the element which would then revert to its old styles.
|
|
128
|
+
*/
|
|
129
|
+
animation.onfinish = () => {
|
|
130
|
+
value.set(getFinalKeyframe(keyframes, options));
|
|
131
|
+
onComplete && onComplete();
|
|
132
|
+
safeCancel();
|
|
133
|
+
};
|
|
134
|
+
/**
|
|
135
|
+
* Animation interrupt callback.
|
|
136
|
+
*/
|
|
137
|
+
const controls = {
|
|
138
|
+
then(resolve, reject) {
|
|
139
|
+
return currentFinishedPromise.then(resolve, reject);
|
|
140
|
+
},
|
|
141
|
+
attachTimeline(timeline) {
|
|
142
|
+
animation.timeline = timeline;
|
|
143
|
+
animation.onfinish = null;
|
|
144
|
+
return noop;
|
|
145
|
+
},
|
|
146
|
+
get time() {
|
|
147
|
+
return millisecondsToSeconds(animation.currentTime || 0);
|
|
148
|
+
},
|
|
149
|
+
set time(newTime) {
|
|
150
|
+
animation.currentTime = secondsToMilliseconds(newTime);
|
|
151
|
+
},
|
|
152
|
+
get speed() {
|
|
153
|
+
return animation.playbackRate;
|
|
154
|
+
},
|
|
155
|
+
set speed(newSpeed) {
|
|
156
|
+
animation.playbackRate = newSpeed;
|
|
157
|
+
},
|
|
158
|
+
get duration() {
|
|
159
|
+
return millisecondsToSeconds(duration);
|
|
160
|
+
},
|
|
161
|
+
play: () => {
|
|
162
|
+
if (hasStopped)
|
|
163
|
+
return;
|
|
164
|
+
animation.play();
|
|
165
|
+
/**
|
|
166
|
+
* Cancel any pending cancel tasks
|
|
167
|
+
*/
|
|
168
|
+
cancelFrame(cancelAnimation);
|
|
169
|
+
},
|
|
170
|
+
pause: () => animation.pause(),
|
|
171
|
+
stop: () => {
|
|
172
|
+
hasStopped = true;
|
|
173
|
+
if (animation.playState === "idle")
|
|
174
|
+
return;
|
|
175
|
+
/**
|
|
176
|
+
* WAAPI doesn't natively have any interruption capabilities.
|
|
177
|
+
*
|
|
178
|
+
* Rather than read commited styles back out of the DOM, we can
|
|
179
|
+
* create a renderless JS animation and sample it twice to calculate
|
|
180
|
+
* its current value, "previous" value, and therefore allow
|
|
181
|
+
* Motion to calculate velocity for any subsequent animation.
|
|
182
|
+
*/
|
|
183
|
+
const { currentTime } = animation;
|
|
184
|
+
if (currentTime) {
|
|
185
|
+
const sampleAnimation = animateValue({
|
|
186
|
+
...options,
|
|
187
|
+
autoplay: false,
|
|
188
|
+
});
|
|
189
|
+
value.setWithVelocity(sampleAnimation.sample(currentTime - sampleDelta).value, sampleAnimation.sample(currentTime).value, sampleDelta);
|
|
190
|
+
}
|
|
191
|
+
safeCancel();
|
|
192
|
+
},
|
|
193
|
+
complete: () => animation.finish(),
|
|
194
|
+
cancel: safeCancel,
|
|
195
|
+
};
|
|
196
|
+
return controls;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
export { createAcceleratedAnimation };
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { isBezierDefinition } from '../../../easing/utils/is-bezier-definition.js';
|
|
2
|
+
|
|
3
|
+
function isWaapiSupportedEasing(easing) {
|
|
4
|
+
return Boolean(!easing ||
|
|
5
|
+
(typeof easing === "string" && supportedWaapiEasing[easing]) ||
|
|
6
|
+
isBezierDefinition(easing) ||
|
|
7
|
+
(Array.isArray(easing) && easing.every(isWaapiSupportedEasing)));
|
|
8
|
+
}
|
|
9
|
+
const cubicBezierAsString = ([a, b, c, d]) => `cubic-bezier(${a}, ${b}, ${c}, ${d})`;
|
|
10
|
+
const supportedWaapiEasing = {
|
|
11
|
+
linear: "linear",
|
|
12
|
+
ease: "ease",
|
|
13
|
+
easeIn: "ease-in",
|
|
14
|
+
easeOut: "ease-out",
|
|
15
|
+
easeInOut: "ease-in-out",
|
|
16
|
+
circIn: cubicBezierAsString([0, 0.65, 0.55, 1]),
|
|
17
|
+
circOut: cubicBezierAsString([0.55, 0, 1, 0.45]),
|
|
18
|
+
backIn: cubicBezierAsString([0.31, 0.01, 0.66, -0.59]),
|
|
19
|
+
backOut: cubicBezierAsString([0.33, 1.53, 0.69, 0.99]),
|
|
20
|
+
};
|
|
21
|
+
function mapEasingToNativeEasing(easing) {
|
|
22
|
+
if (!easing)
|
|
23
|
+
return undefined;
|
|
24
|
+
return isBezierDefinition(easing)
|
|
25
|
+
? cubicBezierAsString(easing)
|
|
26
|
+
: Array.isArray(easing)
|
|
27
|
+
? easing.map(mapEasingToNativeEasing)
|
|
28
|
+
: supportedWaapiEasing[easing];
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export { cubicBezierAsString, isWaapiSupportedEasing, mapEasingToNativeEasing, supportedWaapiEasing };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { mapEasingToNativeEasing } from './easing.js';
|
|
2
|
+
|
|
3
|
+
function animateStyle(element, valueName, keyframes, { delay = 0, duration, repeat = 0, repeatType = "loop", ease, times, } = {}) {
|
|
4
|
+
const keyframeOptions = { [valueName]: keyframes };
|
|
5
|
+
if (times)
|
|
6
|
+
keyframeOptions.offset = times;
|
|
7
|
+
const easing = mapEasingToNativeEasing(ease);
|
|
8
|
+
/**
|
|
9
|
+
* If this is an easing array, apply to keyframes, not animation as a whole
|
|
10
|
+
*/
|
|
11
|
+
if (Array.isArray(easing))
|
|
12
|
+
keyframeOptions.easing = easing;
|
|
13
|
+
return element.animate(keyframeOptions, {
|
|
14
|
+
delay,
|
|
15
|
+
duration,
|
|
16
|
+
easing: !Array.isArray(easing) ? easing : "linear",
|
|
17
|
+
fill: "both",
|
|
18
|
+
iterations: repeat + 1,
|
|
19
|
+
direction: repeatType === "reverse" ? "alternate" : "normal",
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export { animateStyle };
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { spring } from './spring/index.js';
|
|
2
|
+
import { calcGeneratorVelocity } from './utils/velocity.js';
|
|
3
|
+
|
|
4
|
+
function inertia({ keyframes, velocity = 0.0, power = 0.8, timeConstant = 325, bounceDamping = 10, bounceStiffness = 500, modifyTarget, min, max, restDelta = 0.5, restSpeed, }) {
|
|
5
|
+
const origin = keyframes[0];
|
|
6
|
+
const state = {
|
|
7
|
+
done: false,
|
|
8
|
+
value: origin,
|
|
9
|
+
};
|
|
10
|
+
const isOutOfBounds = (v) => (min !== undefined && v < min) || (max !== undefined && v > max);
|
|
11
|
+
const nearestBoundary = (v) => {
|
|
12
|
+
if (min === undefined)
|
|
13
|
+
return max;
|
|
14
|
+
if (max === undefined)
|
|
15
|
+
return min;
|
|
16
|
+
return Math.abs(min - v) < Math.abs(max - v) ? min : max;
|
|
17
|
+
};
|
|
18
|
+
let amplitude = power * velocity;
|
|
19
|
+
const ideal = origin + amplitude;
|
|
20
|
+
const target = modifyTarget === undefined ? ideal : modifyTarget(ideal);
|
|
21
|
+
/**
|
|
22
|
+
* If the target has changed we need to re-calculate the amplitude, otherwise
|
|
23
|
+
* the animation will start from the wrong position.
|
|
24
|
+
*/
|
|
25
|
+
if (target !== ideal)
|
|
26
|
+
amplitude = target - origin;
|
|
27
|
+
const calcDelta = (t) => -amplitude * Math.exp(-t / timeConstant);
|
|
28
|
+
const calcLatest = (t) => target + calcDelta(t);
|
|
29
|
+
const applyFriction = (t) => {
|
|
30
|
+
const delta = calcDelta(t);
|
|
31
|
+
const latest = calcLatest(t);
|
|
32
|
+
state.done = Math.abs(delta) <= restDelta;
|
|
33
|
+
state.value = state.done ? target : latest;
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Ideally this would resolve for t in a stateless way, we could
|
|
37
|
+
* do that by always precalculating the animation but as we know
|
|
38
|
+
* this will be done anyway we can assume that spring will
|
|
39
|
+
* be discovered during that.
|
|
40
|
+
*/
|
|
41
|
+
let timeReachedBoundary;
|
|
42
|
+
let spring$1;
|
|
43
|
+
const checkCatchBoundary = (t) => {
|
|
44
|
+
if (!isOutOfBounds(state.value))
|
|
45
|
+
return;
|
|
46
|
+
timeReachedBoundary = t;
|
|
47
|
+
spring$1 = spring({
|
|
48
|
+
keyframes: [state.value, nearestBoundary(state.value)],
|
|
49
|
+
velocity: calcGeneratorVelocity(calcLatest, t, state.value),
|
|
50
|
+
damping: bounceDamping,
|
|
51
|
+
stiffness: bounceStiffness,
|
|
52
|
+
restDelta,
|
|
53
|
+
restSpeed,
|
|
54
|
+
});
|
|
55
|
+
};
|
|
56
|
+
checkCatchBoundary(0);
|
|
57
|
+
return {
|
|
58
|
+
calculatedDuration: null,
|
|
59
|
+
next: (t) => {
|
|
60
|
+
/**
|
|
61
|
+
* We need to resolve the friction to figure out if we need a
|
|
62
|
+
* spring but we don't want to do this twice per frame. So here
|
|
63
|
+
* we flag if we updated for this frame and later if we did
|
|
64
|
+
* we can skip doing it again.
|
|
65
|
+
*/
|
|
66
|
+
let hasUpdatedFrame = false;
|
|
67
|
+
if (!spring$1 && timeReachedBoundary === undefined) {
|
|
68
|
+
hasUpdatedFrame = true;
|
|
69
|
+
applyFriction(t);
|
|
70
|
+
checkCatchBoundary(t);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* If we have a spring and the provided t is beyond the moment the friction
|
|
74
|
+
* animation crossed the min/max boundary, use the spring.
|
|
75
|
+
*/
|
|
76
|
+
if (timeReachedBoundary !== undefined && t > timeReachedBoundary) {
|
|
77
|
+
return spring$1.next(t - timeReachedBoundary);
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
!hasUpdatedFrame && applyFriction(t);
|
|
81
|
+
return state;
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export { inertia };
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { easeInOut } from '../../easing/ease.js';
|
|
2
|
+
import { isEasingArray } from '../../easing/utils/is-easing-array.js';
|
|
3
|
+
import { easingDefinitionToFunction } from '../../easing/utils/map.js';
|
|
4
|
+
import { interpolate } from '../../utils/interpolate.js';
|
|
5
|
+
import { defaultOffset } from '../../utils/offsets/default.js';
|
|
6
|
+
import { convertOffsetToTimes } from '../../utils/offsets/time.js';
|
|
7
|
+
|
|
8
|
+
function defaultEasing(values, easing) {
|
|
9
|
+
return values.map(() => easing || easeInOut).splice(0, values.length - 1);
|
|
10
|
+
}
|
|
11
|
+
function keyframes({ duration = 300, keyframes: keyframeValues, times, ease = "easeInOut", }) {
|
|
12
|
+
/**
|
|
13
|
+
* Easing functions can be externally defined as strings. Here we convert them
|
|
14
|
+
* into actual functions.
|
|
15
|
+
*/
|
|
16
|
+
const easingFunctions = isEasingArray(ease)
|
|
17
|
+
? ease.map(easingDefinitionToFunction)
|
|
18
|
+
: easingDefinitionToFunction(ease);
|
|
19
|
+
/**
|
|
20
|
+
* This is the Iterator-spec return value. We ensure it's mutable rather than using a generator
|
|
21
|
+
* to reduce GC during animation.
|
|
22
|
+
*/
|
|
23
|
+
const state = {
|
|
24
|
+
done: false,
|
|
25
|
+
value: keyframeValues[0],
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Create a times array based on the provided 0-1 offsets
|
|
29
|
+
*/
|
|
30
|
+
const absoluteTimes = convertOffsetToTimes(
|
|
31
|
+
// Only use the provided offsets if they're the correct length
|
|
32
|
+
// TODO Maybe we should warn here if there's a length mismatch
|
|
33
|
+
times && times.length === keyframeValues.length
|
|
34
|
+
? times
|
|
35
|
+
: defaultOffset(keyframeValues), duration);
|
|
36
|
+
const mapTimeToKeyframe = interpolate(absoluteTimes, keyframeValues, {
|
|
37
|
+
ease: Array.isArray(easingFunctions)
|
|
38
|
+
? easingFunctions
|
|
39
|
+
: defaultEasing(keyframeValues, easingFunctions),
|
|
40
|
+
});
|
|
41
|
+
return {
|
|
42
|
+
calculatedDuration: duration,
|
|
43
|
+
next: (t) => {
|
|
44
|
+
state.value = mapTimeToKeyframe(t);
|
|
45
|
+
state.done = t >= duration;
|
|
46
|
+
return state;
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export { defaultEasing, keyframes };
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { warning } from '../../../utils/errors.js';
|
|
2
|
+
import { clamp } from '../../../utils/clamp.js';
|
|
3
|
+
import { secondsToMilliseconds, millisecondsToSeconds } from '../../../utils/time-conversion.js';
|
|
4
|
+
|
|
5
|
+
const safeMin = 0.001;
|
|
6
|
+
const minDuration = 0.01;
|
|
7
|
+
const maxDuration = 10.0;
|
|
8
|
+
const minDamping = 0.05;
|
|
9
|
+
const maxDamping = 1;
|
|
10
|
+
function findSpring({ duration = 800, bounce = 0.25, velocity = 0, mass = 1, }) {
|
|
11
|
+
let envelope;
|
|
12
|
+
let derivative;
|
|
13
|
+
warning(duration <= secondsToMilliseconds(maxDuration), "Spring duration must be 10 seconds or less");
|
|
14
|
+
let dampingRatio = 1 - bounce;
|
|
15
|
+
/**
|
|
16
|
+
* Restrict dampingRatio and duration to within acceptable ranges.
|
|
17
|
+
*/
|
|
18
|
+
dampingRatio = clamp(minDamping, maxDamping, dampingRatio);
|
|
19
|
+
duration = clamp(minDuration, maxDuration, millisecondsToSeconds(duration));
|
|
20
|
+
if (dampingRatio < 1) {
|
|
21
|
+
/**
|
|
22
|
+
* Underdamped spring
|
|
23
|
+
*/
|
|
24
|
+
envelope = (undampedFreq) => {
|
|
25
|
+
const exponentialDecay = undampedFreq * dampingRatio;
|
|
26
|
+
const delta = exponentialDecay * duration;
|
|
27
|
+
const a = exponentialDecay - velocity;
|
|
28
|
+
const b = calcAngularFreq(undampedFreq, dampingRatio);
|
|
29
|
+
const c = Math.exp(-delta);
|
|
30
|
+
return safeMin - (a / b) * c;
|
|
31
|
+
};
|
|
32
|
+
derivative = (undampedFreq) => {
|
|
33
|
+
const exponentialDecay = undampedFreq * dampingRatio;
|
|
34
|
+
const delta = exponentialDecay * duration;
|
|
35
|
+
const d = delta * velocity + velocity;
|
|
36
|
+
const e = Math.pow(dampingRatio, 2) * Math.pow(undampedFreq, 2) * duration;
|
|
37
|
+
const f = Math.exp(-delta);
|
|
38
|
+
const g = calcAngularFreq(Math.pow(undampedFreq, 2), dampingRatio);
|
|
39
|
+
const factor = -envelope(undampedFreq) + safeMin > 0 ? -1 : 1;
|
|
40
|
+
return (factor * ((d - e) * f)) / g;
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
/**
|
|
45
|
+
* Critically-damped spring
|
|
46
|
+
*/
|
|
47
|
+
envelope = (undampedFreq) => {
|
|
48
|
+
const a = Math.exp(-undampedFreq * duration);
|
|
49
|
+
const b = (undampedFreq - velocity) * duration + 1;
|
|
50
|
+
return -safeMin + a * b;
|
|
51
|
+
};
|
|
52
|
+
derivative = (undampedFreq) => {
|
|
53
|
+
const a = Math.exp(-undampedFreq * duration);
|
|
54
|
+
const b = (velocity - undampedFreq) * (duration * duration);
|
|
55
|
+
return a * b;
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
const initialGuess = 5 / duration;
|
|
59
|
+
const undampedFreq = approximateRoot(envelope, derivative, initialGuess);
|
|
60
|
+
duration = secondsToMilliseconds(duration);
|
|
61
|
+
if (isNaN(undampedFreq)) {
|
|
62
|
+
return {
|
|
63
|
+
stiffness: 100,
|
|
64
|
+
damping: 10,
|
|
65
|
+
duration,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
const stiffness = Math.pow(undampedFreq, 2) * mass;
|
|
70
|
+
return {
|
|
71
|
+
stiffness,
|
|
72
|
+
damping: dampingRatio * 2 * Math.sqrt(mass * stiffness),
|
|
73
|
+
duration,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
const rootIterations = 12;
|
|
78
|
+
function approximateRoot(envelope, derivative, initialGuess) {
|
|
79
|
+
let result = initialGuess;
|
|
80
|
+
for (let i = 1; i < rootIterations; i++) {
|
|
81
|
+
result = result - envelope(result) / derivative(result);
|
|
82
|
+
}
|
|
83
|
+
return result;
|
|
84
|
+
}
|
|
85
|
+
function calcAngularFreq(undampedFreq, dampingRatio) {
|
|
86
|
+
return undampedFreq * Math.sqrt(1 - dampingRatio * dampingRatio);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export { calcAngularFreq, findSpring, maxDamping, maxDuration, minDamping, minDuration };
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { millisecondsToSeconds } from '../../../utils/time-conversion.js';
|
|
2
|
+
import { calcGeneratorVelocity } from '../utils/velocity.js';
|
|
3
|
+
import { findSpring, calcAngularFreq } from './find.js';
|
|
4
|
+
|
|
5
|
+
const durationKeys = ["duration", "bounce"];
|
|
6
|
+
const physicsKeys = ["stiffness", "damping", "mass"];
|
|
7
|
+
function isSpringType(options, keys) {
|
|
8
|
+
return keys.some((key) => options[key] !== undefined);
|
|
9
|
+
}
|
|
10
|
+
function getSpringOptions(options) {
|
|
11
|
+
let springOptions = {
|
|
12
|
+
velocity: 0.0,
|
|
13
|
+
stiffness: 100,
|
|
14
|
+
damping: 10,
|
|
15
|
+
mass: 1.0,
|
|
16
|
+
isResolvedFromDuration: false,
|
|
17
|
+
...options,
|
|
18
|
+
};
|
|
19
|
+
// stiffness/damping/mass overrides duration/bounce
|
|
20
|
+
if (!isSpringType(options, physicsKeys) &&
|
|
21
|
+
isSpringType(options, durationKeys)) {
|
|
22
|
+
const derived = findSpring(options);
|
|
23
|
+
springOptions = {
|
|
24
|
+
...springOptions,
|
|
25
|
+
...derived,
|
|
26
|
+
velocity: 0.0,
|
|
27
|
+
mass: 1.0,
|
|
28
|
+
};
|
|
29
|
+
springOptions.isResolvedFromDuration = true;
|
|
30
|
+
}
|
|
31
|
+
return springOptions;
|
|
32
|
+
}
|
|
33
|
+
function spring({ keyframes, restDelta, restSpeed, ...options }) {
|
|
34
|
+
const origin = keyframes[0];
|
|
35
|
+
const target = keyframes[keyframes.length - 1];
|
|
36
|
+
/**
|
|
37
|
+
* This is the Iterator-spec return value. We ensure it's mutable rather than using a generator
|
|
38
|
+
* to reduce GC during animation.
|
|
39
|
+
*/
|
|
40
|
+
const state = { done: false, value: origin };
|
|
41
|
+
const { stiffness, damping, mass, velocity, duration, isResolvedFromDuration, } = getSpringOptions(options);
|
|
42
|
+
const initialVelocity = velocity ? -millisecondsToSeconds(velocity) : 0.0;
|
|
43
|
+
const dampingRatio = damping / (2 * Math.sqrt(stiffness * mass));
|
|
44
|
+
const initialDelta = target - origin;
|
|
45
|
+
const undampedAngularFreq = millisecondsToSeconds(Math.sqrt(stiffness / mass));
|
|
46
|
+
/**
|
|
47
|
+
* If we're working on a granular scale, use smaller defaults for determining
|
|
48
|
+
* when the spring is finished.
|
|
49
|
+
*
|
|
50
|
+
* These defaults have been selected emprically based on what strikes a good
|
|
51
|
+
* ratio between feeling good and finishing as soon as changes are imperceptible.
|
|
52
|
+
*/
|
|
53
|
+
const isGranularScale = Math.abs(initialDelta) < 5;
|
|
54
|
+
restSpeed || (restSpeed = isGranularScale ? 0.01 : 2);
|
|
55
|
+
restDelta || (restDelta = isGranularScale ? 0.005 : 0.5);
|
|
56
|
+
let resolveSpring;
|
|
57
|
+
if (dampingRatio < 1) {
|
|
58
|
+
const angularFreq = calcAngularFreq(undampedAngularFreq, dampingRatio);
|
|
59
|
+
// Underdamped spring
|
|
60
|
+
resolveSpring = (t) => {
|
|
61
|
+
const envelope = Math.exp(-dampingRatio * undampedAngularFreq * t);
|
|
62
|
+
return (target -
|
|
63
|
+
envelope *
|
|
64
|
+
(((initialVelocity +
|
|
65
|
+
dampingRatio * undampedAngularFreq * initialDelta) /
|
|
66
|
+
angularFreq) *
|
|
67
|
+
Math.sin(angularFreq * t) +
|
|
68
|
+
initialDelta * Math.cos(angularFreq * t)));
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
else if (dampingRatio === 1) {
|
|
72
|
+
// Critically damped spring
|
|
73
|
+
resolveSpring = (t) => target -
|
|
74
|
+
Math.exp(-undampedAngularFreq * t) *
|
|
75
|
+
(initialDelta +
|
|
76
|
+
(initialVelocity + undampedAngularFreq * initialDelta) * t);
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
// Overdamped spring
|
|
80
|
+
const dampedAngularFreq = undampedAngularFreq * Math.sqrt(dampingRatio * dampingRatio - 1);
|
|
81
|
+
resolveSpring = (t) => {
|
|
82
|
+
const envelope = Math.exp(-dampingRatio * undampedAngularFreq * t);
|
|
83
|
+
// When performing sinh or cosh values can hit Infinity so we cap them here
|
|
84
|
+
const freqForT = Math.min(dampedAngularFreq * t, 300);
|
|
85
|
+
return (target -
|
|
86
|
+
(envelope *
|
|
87
|
+
((initialVelocity +
|
|
88
|
+
dampingRatio * undampedAngularFreq * initialDelta) *
|
|
89
|
+
Math.sinh(freqForT) +
|
|
90
|
+
dampedAngularFreq *
|
|
91
|
+
initialDelta *
|
|
92
|
+
Math.cosh(freqForT))) /
|
|
93
|
+
dampedAngularFreq);
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
return {
|
|
97
|
+
calculatedDuration: isResolvedFromDuration ? duration || null : null,
|
|
98
|
+
next: (t) => {
|
|
99
|
+
const current = resolveSpring(t);
|
|
100
|
+
if (!isResolvedFromDuration) {
|
|
101
|
+
let currentVelocity = initialVelocity;
|
|
102
|
+
if (t !== 0) {
|
|
103
|
+
/**
|
|
104
|
+
* We only need to calculate velocity for under-damped springs
|
|
105
|
+
* as over- and critically-damped springs can't overshoot, so
|
|
106
|
+
* checking only for displacement is enough.
|
|
107
|
+
*/
|
|
108
|
+
if (dampingRatio < 1) {
|
|
109
|
+
currentVelocity = calcGeneratorVelocity(resolveSpring, t, current);
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
currentVelocity = 0;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
const isBelowVelocityThreshold = Math.abs(currentVelocity) <= restSpeed;
|
|
116
|
+
const isBelowDisplacementThreshold = Math.abs(target - current) <= restDelta;
|
|
117
|
+
state.done =
|
|
118
|
+
isBelowVelocityThreshold && isBelowDisplacementThreshold;
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
state.done = t >= duration;
|
|
122
|
+
}
|
|
123
|
+
state.value = state.done ? target : current;
|
|
124
|
+
return state;
|
|
125
|
+
},
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export { spring };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Implement a practical max duration for keyframe generation
|
|
3
|
+
* to prevent infinite loops
|
|
4
|
+
*/
|
|
5
|
+
const maxGeneratorDuration = 20000;
|
|
6
|
+
function calcGeneratorDuration(generator) {
|
|
7
|
+
let duration = 0;
|
|
8
|
+
const timeStep = 50;
|
|
9
|
+
let state = generator.next(duration);
|
|
10
|
+
while (!state.done && duration < maxGeneratorDuration) {
|
|
11
|
+
duration += timeStep;
|
|
12
|
+
state = generator.next(duration);
|
|
13
|
+
}
|
|
14
|
+
return duration >= maxGeneratorDuration ? Infinity : duration;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export { calcGeneratorDuration, maxGeneratorDuration };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { velocityPerSecond } from '../../../utils/velocity-per-second.js';
|
|
2
|
+
|
|
3
|
+
const velocitySampleDuration = 5; // ms
|
|
4
|
+
function calcGeneratorVelocity(resolveValue, t, current) {
|
|
5
|
+
const prevT = Math.max(t - velocitySampleDuration, 0);
|
|
6
|
+
return velocityPerSecond(current - resolveValue(prevT), t - prevT);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export { calcGeneratorVelocity };
|