@kitlangton/solid-motion 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +48 -0
- package/README.md +54 -0
- package/dist/animation/animate/index.d.ts +23 -0
- package/dist/animation/animate/resolve-subjects.d.ts +3 -0
- package/dist/animation/animate/sequence.d.ts +3 -0
- package/dist/animation/animate/subject.d.ts +7 -0
- package/dist/animation/sequence/create.d.ts +6 -0
- package/dist/animation/sequence/types.d.ts +51 -0
- package/dist/animation/sequence/utils/calc-repeat-duration.d.ts +1 -0
- package/dist/animation/sequence/utils/calc-time.d.ts +2 -0
- package/dist/animation/sequence/utils/edit.d.ts +5 -0
- package/dist/animation/sequence/utils/normalize-times.d.ts +1 -0
- package/dist/animation/sequence/utils/sort.d.ts +2 -0
- package/dist/animation/utils/create-visual-element.d.ts +2 -0
- package/dist/animation/utils/is-dom-keyframes.d.ts +2 -0
- package/dist/components/AnimatePresence.d.ts +27 -0
- package/dist/components/AnimatePresenceContext.d.ts +23 -0
- package/dist/components/AnimatePresenceTypes.d.ts +57 -0
- package/dist/components/MotionConfig.d.ts +16 -0
- package/dist/context/MotionContext/create.d.ts +3 -0
- package/dist/context/MotionContext/utils.d.ts +3 -0
- package/dist/context/MotionContext.d.ts +7 -0
- package/dist/context/PresenceContext.d.ts +13 -0
- package/dist/events/add-pointer-event.d.ts +2 -0
- package/dist/events/event-info.d.ts +4 -0
- package/dist/gestures/drag/VisualElementDragControls.d.ts +86 -0
- package/dist/gestures/drag/index.d.ts +11 -0
- package/dist/gestures/drag/utils/constraints.d.ts +77 -0
- package/dist/gestures/focus.d.ts +8 -0
- package/dist/gestures/hover.d.ts +5 -0
- package/dist/gestures/pan/PanSession.d.ts +102 -0
- package/dist/gestures/pan/index.d.ts +15 -0
- package/dist/gestures/press.d.ts +5 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +2466 -0
- package/dist/index.js.map +1 -0
- package/dist/motion/features/animation/exit.d.ts +7 -0
- package/dist/motion/features/animation/index.d.ts +9 -0
- package/dist/motion/features/animations.d.ts +10 -0
- package/dist/motion/features/definitions.d.ts +3 -0
- package/dist/motion/features/feature-bundle.d.ts +34 -0
- package/dist/motion/features/gestures.d.ts +26 -0
- package/dist/motion/features/load-features.d.ts +1 -0
- package/dist/motion/index.d.ts +22 -0
- package/dist/motion/types.d.ts +27 -0
- package/dist/motion/utils/drag-projection.d.ts +3 -0
- package/dist/motion/utils/use-visual-state.d.ts +14 -0
- package/dist/motion/utils/valid-prop.d.ts +1 -0
- package/dist/render/dom/create-visual-element.d.ts +2 -0
- package/dist/render/dom/filter-props.d.ts +2 -0
- package/dist/render/dom/is-svg-component.d.ts +1 -0
- package/dist/render/dom/style.d.ts +1 -0
- package/dist/render/html/use-props.d.ts +7 -0
- package/dist/render/html/utils/create-render-state.d.ts +2 -0
- package/dist/render/svg/lowercase-elements.d.ts +1 -0
- package/dist/render/svg/use-props.d.ts +3 -0
- package/dist/render/svg/utils/create-render-state.d.ts +2 -0
- package/dist/render/types.d.ts +3 -0
- package/dist/server.js +2407 -0
- package/dist/server.js.map +1 -0
- package/dist/source/animation/animate/index.js +39 -0
- package/dist/source/animation/animate/resolve-subjects.js +19 -0
- package/dist/source/animation/animate/sequence.js +11 -0
- package/dist/source/animation/animate/subject.js +37 -0
- package/dist/source/animation/sequence/create.js +171 -0
- package/dist/source/animation/sequence/types.js +1 -0
- package/dist/source/animation/sequence/utils/calc-repeat-duration.js +3 -0
- package/dist/source/animation/sequence/utils/calc-time.js +17 -0
- package/dist/source/animation/sequence/utils/edit.js +21 -0
- package/dist/source/animation/sequence/utils/normalize-times.js +5 -0
- package/dist/source/animation/sequence/utils/sort.js +12 -0
- package/dist/source/animation/utils/create-visual-element.js +37 -0
- package/dist/source/animation/utils/is-dom-keyframes.js +3 -0
- package/dist/source/components/AnimatePresence.jsx +444 -0
- package/dist/source/components/AnimatePresenceContext.jsx +20 -0
- package/dist/source/components/AnimatePresenceTypes.js +1 -0
- package/dist/source/components/MotionConfig.jsx +13 -0
- package/dist/source/context/MotionContext/create.js +19 -0
- package/dist/source/context/MotionContext/utils.js +11 -0
- package/dist/source/context/MotionContext.js +2 -0
- package/dist/source/context/PresenceContext.js +2 -0
- package/dist/source/events/add-pointer-event.js +5 -0
- package/dist/source/events/event-info.js +16 -0
- package/dist/source/gestures/drag/VisualElementDragControls.js +531 -0
- package/dist/source/gestures/drag/index.js +47 -0
- package/dist/source/gestures/drag/utils/constraints.js +160 -0
- package/dist/source/gestures/focus.js +37 -0
- package/dist/source/gestures/hover.js +25 -0
- package/dist/source/gestures/pan/PanSession.js +273 -0
- package/dist/source/gestures/pan/index.js +46 -0
- package/dist/source/gestures/press.js +28 -0
- package/dist/source/index.js +11 -0
- package/dist/source/motion/features/animation/exit.js +33 -0
- package/dist/source/motion/features/animation/index.js +27 -0
- package/dist/source/motion/features/animations.js +10 -0
- package/dist/source/motion/features/definitions.js +29 -0
- package/dist/source/motion/features/feature-bundle.js +6 -0
- package/dist/source/motion/features/gestures.js +20 -0
- package/dist/source/motion/features/load-features.js +12 -0
- package/dist/source/motion/index.jsx +176 -0
- package/dist/source/motion/types.js +1 -0
- package/dist/source/motion/utils/drag-projection.js +16 -0
- package/dist/source/motion/utils/use-visual-state.js +53 -0
- package/dist/source/motion/utils/valid-prop.js +40 -0
- package/dist/source/render/dom/create-visual-element.js +10 -0
- package/dist/source/render/dom/filter-props.js +15 -0
- package/dist/source/render/dom/is-svg-component.js +10 -0
- package/dist/source/render/dom/style.js +12 -0
- package/dist/source/render/html/use-props.js +39 -0
- package/dist/source/render/html/utils/create-render-state.js +6 -0
- package/dist/source/render/svg/lowercase-elements.js +27 -0
- package/dist/source/render/svg/use-props.js +28 -0
- package/dist/source/render/svg/utils/create-render-state.js +5 -0
- package/dist/source/render/types.js +1 -0
- package/dist/source/utils/distance.js +7 -0
- package/dist/source/utils/get-context-window.js +4 -0
- package/dist/source/utils/is-ref-object.js +5 -0
- package/dist/source/utils/safe-react-types.js +1 -0
- package/dist/source/utils/use-reduced-motion.js +15 -0
- package/dist/source/value/use-motion-value-event.js +5 -0
- package/dist/source/value/use-motion-value.js +16 -0
- package/dist/source/value/use-spring.js +59 -0
- package/dist/source/value/use-transform.js +25 -0
- package/dist/source/value/use-velocity.js +17 -0
- package/dist/utils/distance.d.ts +3 -0
- package/dist/utils/get-context-window.d.ts +2 -0
- package/dist/utils/is-ref-object.d.ts +2 -0
- package/dist/utils/safe-react-types.d.ts +3 -0
- package/dist/utils/use-reduced-motion.d.ts +6 -0
- package/dist/value/use-motion-value-event.d.ts +3 -0
- package/dist/value/use-motion-value.d.ts +5 -0
- package/dist/value/use-spring.d.ts +5 -0
- package/dist/value/use-transform.d.ts +9 -0
- package/dist/value/use-velocity.d.ts +3 -0
- package/package.json +61 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { DragGesture as UpstreamDragGesture } from "../../gestures/drag";
|
|
2
|
+
import { PanGesture } from "../../gestures/pan";
|
|
3
|
+
import { HoverGesture } from "../../gestures/hover";
|
|
4
|
+
import { PressGesture } from "../../gestures/press";
|
|
5
|
+
import { FocusGesture } from "../../gestures/focus";
|
|
6
|
+
class DragGesture extends UpstreamDragGesture {
|
|
7
|
+
unmount() {
|
|
8
|
+
// Solid disposal is final. Always release the window listeners and global
|
|
9
|
+
// drag lock, including when an element is removed in the middle of a drag.
|
|
10
|
+
this.controls.dispose();
|
|
11
|
+
super.unmount();
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export const gestures = {
|
|
15
|
+
drag: { Feature: DragGesture },
|
|
16
|
+
pan: { Feature: PanGesture },
|
|
17
|
+
hover: { Feature: HoverGesture },
|
|
18
|
+
tap: { Feature: PressGesture },
|
|
19
|
+
focus: { Feature: FocusGesture },
|
|
20
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { setFeatureDefinitions } from "motion-dom";
|
|
2
|
+
import { getInitializedFeatureDefinitions } from "./definitions";
|
|
3
|
+
export function loadFeatures(features) {
|
|
4
|
+
const featureDefinitions = getInitializedFeatureDefinitions();
|
|
5
|
+
for (const key in features) {
|
|
6
|
+
featureDefinitions[key] = {
|
|
7
|
+
...featureDefinitions[key],
|
|
8
|
+
...features[key],
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
setFeatureDefinitions(featureDefinitions);
|
|
12
|
+
}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { createEffect, createMemo, onCleanup, onMount, splitProps, useContext } from "solid-js";
|
|
2
|
+
import { Dynamic } from "solid-js/web";
|
|
3
|
+
import { scrapeHTMLMotionValuesFromProps, scrapeSVGMotionValuesFromProps } from "motion-dom";
|
|
4
|
+
import { MotionConfigContext } from "../components/MotionConfig";
|
|
5
|
+
import { MotionContext } from "../context/MotionContext";
|
|
6
|
+
import { PresenceContext } from "../context/PresenceContext";
|
|
7
|
+
import { createMotionContext } from "../context/MotionContext/create";
|
|
8
|
+
import { isSVGComponent } from "../render/dom/is-svg-component";
|
|
9
|
+
import { filterProps } from "../render/dom/filter-props";
|
|
10
|
+
import { createDomVisualElement } from "../render/dom/create-visual-element";
|
|
11
|
+
import { resolveHTMLProps } from "../render/html/use-props";
|
|
12
|
+
import { resolveSVGProps } from "../render/svg/use-props";
|
|
13
|
+
import { createHtmlRenderState } from "../render/html/utils/create-render-state";
|
|
14
|
+
import { createSvgRenderState } from "../render/svg/utils/create-render-state";
|
|
15
|
+
import { makeVisualState } from "./utils/use-visual-state";
|
|
16
|
+
import { loadFeatures } from "./features/load-features";
|
|
17
|
+
import { featureBundle } from "./features/feature-bundle";
|
|
18
|
+
import { prepareDragProjection } from "./utils/drag-projection";
|
|
19
|
+
const isBrowser = typeof window !== "undefined";
|
|
20
|
+
function useVisualState(isSVG, props, context, presenceContext) {
|
|
21
|
+
const config = isSVG
|
|
22
|
+
? {
|
|
23
|
+
scrapeMotionValuesFromProps: scrapeSVGMotionValuesFromProps,
|
|
24
|
+
createRenderState: createSvgRenderState,
|
|
25
|
+
}
|
|
26
|
+
: {
|
|
27
|
+
scrapeMotionValuesFromProps: scrapeHTMLMotionValuesFromProps,
|
|
28
|
+
createRenderState: createHtmlRenderState,
|
|
29
|
+
};
|
|
30
|
+
return makeVisualState(config, props, context, presenceContext);
|
|
31
|
+
}
|
|
32
|
+
export function createMotionComponent(Component, { forwardMotionProps = false, type } = {}, preloadedFeatures, createVisualElement) {
|
|
33
|
+
if (preloadedFeatures) {
|
|
34
|
+
loadFeatures(preloadedFeatures);
|
|
35
|
+
}
|
|
36
|
+
const isSVG = type ? type === "svg" : isSVGComponent(Component);
|
|
37
|
+
return function MotionDOMComponent(props) {
|
|
38
|
+
const motionConfig = useContext(MotionConfigContext);
|
|
39
|
+
const parentContext = useContext(MotionContext);
|
|
40
|
+
const rawPresenceContext = useContext(PresenceContext);
|
|
41
|
+
const presenceContext = createMemo(() => {
|
|
42
|
+
if (!rawPresenceContext)
|
|
43
|
+
return null;
|
|
44
|
+
const resolved = {
|
|
45
|
+
id: rawPresenceContext.id(),
|
|
46
|
+
isPresent: rawPresenceContext.isPresent(),
|
|
47
|
+
initial: rawPresenceContext.initial(),
|
|
48
|
+
custom: rawPresenceContext.custom(),
|
|
49
|
+
onExitComplete: rawPresenceContext.onExitComplete,
|
|
50
|
+
register: rawPresenceContext.register ?? (() => () => { }),
|
|
51
|
+
};
|
|
52
|
+
return resolved;
|
|
53
|
+
});
|
|
54
|
+
const ownProps = createMemo(() => {
|
|
55
|
+
const nextProps = {};
|
|
56
|
+
for (const key in props) {
|
|
57
|
+
// Solid children are lazy factories, not inert React element values.
|
|
58
|
+
// Reading them here creates a second subtree on each animation update,
|
|
59
|
+
// overwriting refs with detached nodes. Resolve them only in the provider.
|
|
60
|
+
if (key === "children")
|
|
61
|
+
continue;
|
|
62
|
+
nextProps[key] = props[key];
|
|
63
|
+
}
|
|
64
|
+
return nextProps;
|
|
65
|
+
});
|
|
66
|
+
// Config feeds the visual element, but must not render as DOM attributes.
|
|
67
|
+
const getLatestProps = createMemo(() => ({ ...motionConfig, ...ownProps() }));
|
|
68
|
+
const isStatic = createMemo(() => Boolean(getLatestProps().isStatic));
|
|
69
|
+
const context = createMotionContext(props, parentContext);
|
|
70
|
+
const visualState = useVisualState(isSVG, props, context, presenceContext());
|
|
71
|
+
let visualElement;
|
|
72
|
+
const initialPresenceContext = presenceContext();
|
|
73
|
+
if (!isStatic() && isBrowser) {
|
|
74
|
+
visualElement = (createVisualElement || createDomVisualElement)(Component, {
|
|
75
|
+
visualState,
|
|
76
|
+
parent: parentContext.visualElement,
|
|
77
|
+
props: getLatestProps(),
|
|
78
|
+
presenceContext: initialPresenceContext,
|
|
79
|
+
blockInitialAnimation: initialPresenceContext ? initialPresenceContext.initial === false : false,
|
|
80
|
+
reducedMotionConfig: motionConfig.reducedMotion,
|
|
81
|
+
skipAnimations: motionConfig.skipAnimations,
|
|
82
|
+
isSVG,
|
|
83
|
+
});
|
|
84
|
+
if (visualElement)
|
|
85
|
+
prepareDragProjection(visualElement, getLatestProps());
|
|
86
|
+
}
|
|
87
|
+
context.visualElement = visualElement;
|
|
88
|
+
const [local, rest] = splitProps(props, ["ref", "children"]);
|
|
89
|
+
const elementProps = createMemo(() => {
|
|
90
|
+
const latestProps = getLatestProps();
|
|
91
|
+
const filtered = filterProps(ownProps(), typeof Component === "string", forwardMotionProps);
|
|
92
|
+
delete filtered.children;
|
|
93
|
+
delete filtered.ref;
|
|
94
|
+
const componentTag = typeof Component === "string" ? Component : "svg";
|
|
95
|
+
const visualProps = isSVG
|
|
96
|
+
? resolveSVGProps(latestProps, visualState.latestValues, componentTag)
|
|
97
|
+
: resolveHTMLProps(latestProps, visualState.latestValues);
|
|
98
|
+
return { ...filtered, ...visualProps };
|
|
99
|
+
});
|
|
100
|
+
onMount(() => {
|
|
101
|
+
if (!visualElement)
|
|
102
|
+
return;
|
|
103
|
+
visualElement.scheduleRenderMicrotask();
|
|
104
|
+
});
|
|
105
|
+
createEffect(() => {
|
|
106
|
+
if (!visualElement)
|
|
107
|
+
return;
|
|
108
|
+
const nextProps = getLatestProps();
|
|
109
|
+
const nextPresenceContext = presenceContext();
|
|
110
|
+
visualElement.update(nextProps, nextPresenceContext);
|
|
111
|
+
prepareDragProjection(visualElement, nextProps);
|
|
112
|
+
visualElement.updateFeatures();
|
|
113
|
+
if (visualElement.current && visualElement.animationState) {
|
|
114
|
+
visualElement.animationState.animateChanges();
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
onCleanup(() => {
|
|
118
|
+
visualElement?.unmount();
|
|
119
|
+
});
|
|
120
|
+
const setRef = (instance) => {
|
|
121
|
+
if (!instance)
|
|
122
|
+
return;
|
|
123
|
+
visualElement?.mount(instance);
|
|
124
|
+
if (visualElement && parentContext.visualElement) {
|
|
125
|
+
const parent = parentContext.visualElement;
|
|
126
|
+
visualElement.parent = parent;
|
|
127
|
+
if (typeof parent.depth === "number") {
|
|
128
|
+
;
|
|
129
|
+
visualElement.depth = parent.depth + 1;
|
|
130
|
+
}
|
|
131
|
+
if (visualElement.isVariantNode && !visualElement.isControllingVariants) {
|
|
132
|
+
;
|
|
133
|
+
visualElement.removeFromVariantTree?.();
|
|
134
|
+
if (typeof parent.addVariantChild === "function") {
|
|
135
|
+
;
|
|
136
|
+
visualElement.removeFromVariantTree = parent.addVariantChild(visualElement);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
visualState.onMount?.(instance);
|
|
141
|
+
const externalRef = local.ref;
|
|
142
|
+
if (typeof externalRef === "function") {
|
|
143
|
+
externalRef(instance);
|
|
144
|
+
}
|
|
145
|
+
else if (externalRef && typeof externalRef === "object") {
|
|
146
|
+
;
|
|
147
|
+
externalRef.current = instance;
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
return (<MotionContext.Provider value={context}>
|
|
151
|
+
<Dynamic component={Component} {...elementProps()} ref={setRef}>
|
|
152
|
+
{local.children}
|
|
153
|
+
</Dynamic>
|
|
154
|
+
</MotionContext.Provider>);
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
export function createMotionComponentWithFeatures(Component, options) {
|
|
158
|
+
return createMotionComponent(Component, options, featureBundle, createDomVisualElement);
|
|
159
|
+
}
|
|
160
|
+
const componentCache = new Map();
|
|
161
|
+
const motionProxy = new Proxy(createMotionComponentWithFeatures, {
|
|
162
|
+
get: (target, key) => {
|
|
163
|
+
if (key === "create")
|
|
164
|
+
return createMotionComponentWithFeatures;
|
|
165
|
+
if (typeof key !== "string")
|
|
166
|
+
return Reflect.get(target, key);
|
|
167
|
+
let component = componentCache.get(key);
|
|
168
|
+
if (!component) {
|
|
169
|
+
component = createMotionComponentWithFeatures(key);
|
|
170
|
+
componentCache.set(key, component);
|
|
171
|
+
}
|
|
172
|
+
return component;
|
|
173
|
+
},
|
|
174
|
+
});
|
|
175
|
+
export const motion = motionProxy;
|
|
176
|
+
export const m = motionProxy;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { HTMLProjectionNode } from "motion-dom";
|
|
2
|
+
export function prepareDragProjection(node, props) {
|
|
3
|
+
if (node.projection || !(props.drag || props.dragControls))
|
|
4
|
+
return;
|
|
5
|
+
// Drag constraints use Motion's geometry measurement, without enabling layout
|
|
6
|
+
// animation or shared layout IDs. Non-draggable elements pay no projection cost.
|
|
7
|
+
node.projection = new HTMLProjectionNode(node.latestValues, node.parent?.projection);
|
|
8
|
+
node.projection.setOptions({
|
|
9
|
+
visualElement: node,
|
|
10
|
+
alwaysMeasureLayout: true,
|
|
11
|
+
layout: false,
|
|
12
|
+
animationType: "both",
|
|
13
|
+
});
|
|
14
|
+
if (node.current)
|
|
15
|
+
node.projection.mount(node.current);
|
|
16
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { isAnimationControls, isControllingVariants as checkIsControllingVariants, isVariantNode as checkIsVariantNode, resolveVariantFromProps, resolveMotionValue, } from "motion-dom";
|
|
2
|
+
function makeState({ scrapeMotionValuesFromProps, createRenderState }, props, context, presenceContext) {
|
|
3
|
+
const state = {
|
|
4
|
+
latestValues: makeLatestValues(props, context, presenceContext, scrapeMotionValuesFromProps),
|
|
5
|
+
renderState: createRenderState(),
|
|
6
|
+
};
|
|
7
|
+
return state;
|
|
8
|
+
}
|
|
9
|
+
function makeLatestValues(props, context, presenceContext, scrapeMotionValues) {
|
|
10
|
+
const values = {};
|
|
11
|
+
const motionValues = scrapeMotionValues(props, {});
|
|
12
|
+
for (const key in motionValues) {
|
|
13
|
+
values[key] = resolveMotionValue(motionValues[key]);
|
|
14
|
+
}
|
|
15
|
+
let { initial, animate } = props;
|
|
16
|
+
const isControllingVariants = checkIsControllingVariants(props);
|
|
17
|
+
const isVariantNode = checkIsVariantNode(props);
|
|
18
|
+
if (context && isVariantNode && !isControllingVariants && props.inherit !== false) {
|
|
19
|
+
if (initial === undefined)
|
|
20
|
+
initial = context.initial;
|
|
21
|
+
if (animate === undefined)
|
|
22
|
+
animate = context.animate;
|
|
23
|
+
}
|
|
24
|
+
let isInitialAnimationBlocked = presenceContext ? presenceContext.initial === false : false;
|
|
25
|
+
isInitialAnimationBlocked = isInitialAnimationBlocked || initial === false;
|
|
26
|
+
const variantToSet = isInitialAnimationBlocked ? animate : initial;
|
|
27
|
+
if (variantToSet && typeof variantToSet !== "boolean" && !isAnimationControls(variantToSet)) {
|
|
28
|
+
const list = Array.isArray(variantToSet) ? variantToSet : [variantToSet];
|
|
29
|
+
for (let i = 0; i < list.length; i++) {
|
|
30
|
+
const resolved = resolveVariantFromProps(props, list[i]);
|
|
31
|
+
if (resolved) {
|
|
32
|
+
const { transitionEnd, transition, ...target } = resolved;
|
|
33
|
+
for (const key in target) {
|
|
34
|
+
let valueTarget = target[key];
|
|
35
|
+
if (Array.isArray(valueTarget)) {
|
|
36
|
+
const index = isInitialAnimationBlocked ? valueTarget.length - 1 : 0;
|
|
37
|
+
valueTarget = valueTarget[index];
|
|
38
|
+
}
|
|
39
|
+
if (valueTarget !== null) {
|
|
40
|
+
values[key] = valueTarget;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
for (const key in transitionEnd) {
|
|
44
|
+
values[key] = transitionEnd[key];
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return values;
|
|
50
|
+
}
|
|
51
|
+
export function makeVisualState(config, props, context, presenceContext) {
|
|
52
|
+
return makeState(config, props, context, presenceContext);
|
|
53
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
const validMotionProps = new Set([
|
|
2
|
+
"animate",
|
|
3
|
+
"exit",
|
|
4
|
+
"variants",
|
|
5
|
+
"initial",
|
|
6
|
+
"style",
|
|
7
|
+
"values",
|
|
8
|
+
"transition",
|
|
9
|
+
"transformTemplate",
|
|
10
|
+
"custom",
|
|
11
|
+
"inherit",
|
|
12
|
+
"onBeforeLayoutMeasure",
|
|
13
|
+
"onAnimationStart",
|
|
14
|
+
"onAnimationComplete",
|
|
15
|
+
"onUpdate",
|
|
16
|
+
"onDragStart",
|
|
17
|
+
"onDrag",
|
|
18
|
+
"onDragEnd",
|
|
19
|
+
"onMeasureDragConstraints",
|
|
20
|
+
"onDirectionLock",
|
|
21
|
+
"onDragTransitionEnd",
|
|
22
|
+
"_dragX",
|
|
23
|
+
"_dragY",
|
|
24
|
+
"onHoverStart",
|
|
25
|
+
"onHoverEnd",
|
|
26
|
+
"onViewportEnter",
|
|
27
|
+
"onViewportLeave",
|
|
28
|
+
"globalTapTarget",
|
|
29
|
+
"ignoreStrict",
|
|
30
|
+
"viewport",
|
|
31
|
+
]);
|
|
32
|
+
export function isValidMotionProp(key) {
|
|
33
|
+
return (key.startsWith("while") ||
|
|
34
|
+
(key.startsWith("drag") && key !== "draggable") ||
|
|
35
|
+
key.startsWith("layout") ||
|
|
36
|
+
key.startsWith("onTap") ||
|
|
37
|
+
key.startsWith("onPan") ||
|
|
38
|
+
key.startsWith("onLayout") ||
|
|
39
|
+
validMotionProps.has(key));
|
|
40
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { HTMLVisualElement, SVGVisualElement } from "motion-dom";
|
|
2
|
+
import { isSVGComponent } from "./is-svg-component";
|
|
3
|
+
export const createDomVisualElement = (Component, options) => {
|
|
4
|
+
const isSVG = options.isSVG ?? isSVGComponent(Component);
|
|
5
|
+
return isSVG
|
|
6
|
+
? new SVGVisualElement(options)
|
|
7
|
+
: new HTMLVisualElement(options, {
|
|
8
|
+
allowProjection: Component !== "svg",
|
|
9
|
+
});
|
|
10
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { isValidMotionProp } from "../../motion/utils/valid-prop";
|
|
2
|
+
export function filterProps(props, isDom, forwardMotionProps) {
|
|
3
|
+
const filteredProps = {};
|
|
4
|
+
for (const key in props) {
|
|
5
|
+
if (key === "values" && typeof props.values === "object")
|
|
6
|
+
continue;
|
|
7
|
+
if (!isValidMotionProp(key) ||
|
|
8
|
+
(forwardMotionProps === true && isValidMotionProp(key)) ||
|
|
9
|
+
(!isDom && !isValidMotionProp(key)) ||
|
|
10
|
+
(props.draggable && key.startsWith("onDrag"))) {
|
|
11
|
+
filteredProps[key] = props[key];
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
return filteredProps;
|
|
15
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { lowercaseSVGElements } from "../svg/lowercase-elements";
|
|
2
|
+
export function isSVGComponent(Component) {
|
|
3
|
+
if (typeof Component !== "string" || Component.includes("-")) {
|
|
4
|
+
return false;
|
|
5
|
+
}
|
|
6
|
+
if (lowercaseSVGElements.indexOf(Component) > -1 || /[A-Z]/u.test(Component)) {
|
|
7
|
+
return true;
|
|
8
|
+
}
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// Motion builds CSSStyleDeclaration-shaped objects. Solid applies style objects
|
|
2
|
+
// with setProperty(), which requires CSS property names (including vendor prefixes).
|
|
3
|
+
export function toSolidStyle(style) {
|
|
4
|
+
const result = {};
|
|
5
|
+
for (const key in style) {
|
|
6
|
+
const name = key.startsWith("--")
|
|
7
|
+
? key
|
|
8
|
+
: key.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`).replace(/^ms-/, "-ms-");
|
|
9
|
+
result[name] = style[key];
|
|
10
|
+
}
|
|
11
|
+
return result;
|
|
12
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { buildHTMLStyles, isForcedMotionValue, isMotionValue } from "motion-dom";
|
|
2
|
+
import { createHtmlRenderState } from "./utils/create-render-state";
|
|
3
|
+
import { toSolidStyle } from "../dom/style";
|
|
4
|
+
export function copyRawValuesOnly(target, source, props) {
|
|
5
|
+
for (const key in source) {
|
|
6
|
+
if (!isMotionValue(source[key]) && !isForcedMotionValue(key, props)) {
|
|
7
|
+
target[key] = source[key];
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
function resolveInitialMotionValues({ transformTemplate }, visualState) {
|
|
12
|
+
const state = createHtmlRenderState();
|
|
13
|
+
buildHTMLStyles(state, visualState, transformTemplate);
|
|
14
|
+
return { ...state.vars, ...state.style };
|
|
15
|
+
}
|
|
16
|
+
function resolveStyle(props, visualState) {
|
|
17
|
+
const styleProp = props.style || {};
|
|
18
|
+
const style = {};
|
|
19
|
+
copyRawValuesOnly(style, styleProp, props);
|
|
20
|
+
Object.assign(style, resolveInitialMotionValues(props, visualState));
|
|
21
|
+
return style;
|
|
22
|
+
}
|
|
23
|
+
export function resolveHTMLProps(props, visualState) {
|
|
24
|
+
const htmlProps = {};
|
|
25
|
+
const style = resolveStyle(props, visualState);
|
|
26
|
+
if (props.drag && props.dragListener !== false) {
|
|
27
|
+
;
|
|
28
|
+
htmlProps.draggable = false;
|
|
29
|
+
style.userSelect = style.WebkitUserSelect = style.WebkitTouchCallout = "none";
|
|
30
|
+
style.touchAction = props.drag === true ? "none" : `pan-${props.drag === "x" ? "y" : "x"}`;
|
|
31
|
+
}
|
|
32
|
+
if (props.tabIndex === undefined && (props.onTap || props.onTapStart || props.whileTap)) {
|
|
33
|
+
;
|
|
34
|
+
htmlProps.tabIndex = 0;
|
|
35
|
+
}
|
|
36
|
+
;
|
|
37
|
+
htmlProps.style = toSolidStyle(style);
|
|
38
|
+
return htmlProps;
|
|
39
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export const lowercaseSVGElements = [
|
|
2
|
+
"animate",
|
|
3
|
+
"circle",
|
|
4
|
+
"defs",
|
|
5
|
+
"desc",
|
|
6
|
+
"ellipse",
|
|
7
|
+
"g",
|
|
8
|
+
"image",
|
|
9
|
+
"line",
|
|
10
|
+
"filter",
|
|
11
|
+
"marker",
|
|
12
|
+
"mask",
|
|
13
|
+
"metadata",
|
|
14
|
+
"path",
|
|
15
|
+
"pattern",
|
|
16
|
+
"polygon",
|
|
17
|
+
"polyline",
|
|
18
|
+
"rect",
|
|
19
|
+
"stop",
|
|
20
|
+
"switch",
|
|
21
|
+
"symbol",
|
|
22
|
+
"svg",
|
|
23
|
+
"text",
|
|
24
|
+
"tspan",
|
|
25
|
+
"use",
|
|
26
|
+
"view",
|
|
27
|
+
];
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { buildSVGAttrs, isSVGTag } from "motion-dom";
|
|
2
|
+
import { copyRawValuesOnly } from "../html/use-props";
|
|
3
|
+
import { createSvgRenderState } from "./utils/create-render-state";
|
|
4
|
+
import { toSolidStyle } from "../dom/style";
|
|
5
|
+
export function resolveSVGProps(props, visualState, Component) {
|
|
6
|
+
const state = createSvgRenderState();
|
|
7
|
+
buildSVGAttrs(state, visualState, isSVGTag(Component), props.transformTemplate, props.style);
|
|
8
|
+
const visualProps = {
|
|
9
|
+
...state.attrs,
|
|
10
|
+
style: { ...state.style },
|
|
11
|
+
};
|
|
12
|
+
if (props.style) {
|
|
13
|
+
const rawStyles = {};
|
|
14
|
+
copyRawValuesOnly(rawStyles, props.style, props);
|
|
15
|
+
visualProps.style = { ...rawStyles, ...visualProps.style };
|
|
16
|
+
}
|
|
17
|
+
const pathLength = visualState.pathLength;
|
|
18
|
+
const pathSpacing = visualState.pathSpacing;
|
|
19
|
+
const pathOffset = visualState.pathOffset;
|
|
20
|
+
if (pathLength !== undefined) {
|
|
21
|
+
const spacing = pathSpacing ?? 1 - Number(pathLength);
|
|
22
|
+
visualProps.pathLength = 1;
|
|
23
|
+
visualProps["stroke-dasharray"] = `${pathLength} ${spacing}`;
|
|
24
|
+
visualProps["stroke-dashoffset"] = `${-Number(pathOffset ?? 0)}`;
|
|
25
|
+
}
|
|
26
|
+
visualProps.style = toSolidStyle(visualProps.style);
|
|
27
|
+
return visualProps;
|
|
28
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { createSignal, onCleanup } from "solid-js";
|
|
2
|
+
/**
|
|
3
|
+
* Reactive device preference. Read as `shouldReduceMotion()` in tracked code.
|
|
4
|
+
* Returns null on the server or when matchMedia is unavailable.
|
|
5
|
+
*/
|
|
6
|
+
export function useReducedMotion() {
|
|
7
|
+
if (typeof window === "undefined" || !window.matchMedia)
|
|
8
|
+
return () => null;
|
|
9
|
+
const media = window.matchMedia("(prefers-reduced-motion: reduce)");
|
|
10
|
+
const [reduced, setReduced] = createSignal(media.matches);
|
|
11
|
+
const update = () => setReduced(media.matches);
|
|
12
|
+
media.addEventListener("change", update);
|
|
13
|
+
onCleanup(() => media.removeEventListener("change", update));
|
|
14
|
+
return reduced;
|
|
15
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { motionValue } from "motion-dom";
|
|
2
|
+
import { onCleanup, useContext } from "solid-js";
|
|
3
|
+
import { MotionConfigContext } from "../components/MotionConfig";
|
|
4
|
+
/**
|
|
5
|
+
* Creates a MotionValue to track state and velocity.
|
|
6
|
+
*/
|
|
7
|
+
export function useMotionValue(initial) {
|
|
8
|
+
const value = motionValue(initial);
|
|
9
|
+
const { isStatic } = useContext(MotionConfigContext);
|
|
10
|
+
if (isStatic) {
|
|
11
|
+
const unsubscribe = value.on("change", () => { });
|
|
12
|
+
onCleanup(() => unsubscribe());
|
|
13
|
+
}
|
|
14
|
+
onCleanup(() => value.destroy());
|
|
15
|
+
return value;
|
|
16
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { isMotionValue, cancelFrame, frame, JSAnimation, motionValue, } from "motion-dom";
|
|
2
|
+
import { useContext } from "solid-js";
|
|
3
|
+
import { MotionConfigContext } from "../components/MotionConfig";
|
|
4
|
+
import { useTransform } from "./use-transform";
|
|
5
|
+
import { onCleanup } from "solid-js";
|
|
6
|
+
export function useSpring(source, options = {}) {
|
|
7
|
+
const { isStatic } = useContext(MotionConfigContext);
|
|
8
|
+
const getFromSource = () => (isMotionValue(source) ? source.get() : source);
|
|
9
|
+
if (isStatic) {
|
|
10
|
+
return useTransform(getFromSource);
|
|
11
|
+
}
|
|
12
|
+
const initial = getFromSource();
|
|
13
|
+
const value = motionValue(initial);
|
|
14
|
+
const unit = typeof initial === "string" ? initial.replace(/[\d.-]/g, "") : "";
|
|
15
|
+
const parse = (latest) => unit ? `${parseFloat(String(latest))}${unit}` : parseFloat(String(latest));
|
|
16
|
+
let target = initial;
|
|
17
|
+
let setter;
|
|
18
|
+
let disposed = false;
|
|
19
|
+
const stop = () => {
|
|
20
|
+
cancelFrame(start);
|
|
21
|
+
value.stop();
|
|
22
|
+
};
|
|
23
|
+
// motion-dom 12.30's springValue queues an anonymous callback that survives
|
|
24
|
+
// destroy(). Keep the scheduled work owned and cancellable by this Solid scope.
|
|
25
|
+
const start = () => {
|
|
26
|
+
if (disposed)
|
|
27
|
+
return;
|
|
28
|
+
value.stop();
|
|
29
|
+
const from = parseFloat(String(value.get()));
|
|
30
|
+
const to = parseFloat(String(target));
|
|
31
|
+
if (from === to)
|
|
32
|
+
return;
|
|
33
|
+
value.start((onComplete) => new JSAnimation({
|
|
34
|
+
keyframes: [from, to],
|
|
35
|
+
velocity: value.getVelocity(),
|
|
36
|
+
type: "spring",
|
|
37
|
+
restDelta: 0.001,
|
|
38
|
+
restSpeed: 0.01,
|
|
39
|
+
...options,
|
|
40
|
+
onUpdate: (latest) => setter(parse(latest)),
|
|
41
|
+
onComplete,
|
|
42
|
+
}));
|
|
43
|
+
};
|
|
44
|
+
value.attach((latest, set) => {
|
|
45
|
+
target = latest;
|
|
46
|
+
setter = set;
|
|
47
|
+
frame.postRender(start);
|
|
48
|
+
}, stop);
|
|
49
|
+
const unsubscribe = isMotionValue(source)
|
|
50
|
+
? source.on("change", (latest) => value.set(parse(latest)))
|
|
51
|
+
: undefined;
|
|
52
|
+
value.on("destroy", () => {
|
|
53
|
+
disposed = true;
|
|
54
|
+
unsubscribe?.();
|
|
55
|
+
stop();
|
|
56
|
+
});
|
|
57
|
+
onCleanup(() => value.destroy());
|
|
58
|
+
return value;
|
|
59
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { mapValue, transform, transformValue, } from "motion-dom";
|
|
2
|
+
import { onCleanup } from "solid-js";
|
|
3
|
+
export function useTransform(input, inputRangeOrTransformer, outputRange, options) {
|
|
4
|
+
if (typeof input === "function") {
|
|
5
|
+
const value = transformValue(input);
|
|
6
|
+
onCleanup(() => value.destroy());
|
|
7
|
+
return value;
|
|
8
|
+
}
|
|
9
|
+
let value;
|
|
10
|
+
if (Array.isArray(input)) {
|
|
11
|
+
const transformer = typeof inputRangeOrTransformer === "function"
|
|
12
|
+
? inputRangeOrTransformer
|
|
13
|
+
: transform(inputRangeOrTransformer, outputRange, options);
|
|
14
|
+
value = transformValue(() => transformer(input.map((item) => item.get())));
|
|
15
|
+
}
|
|
16
|
+
else if (typeof inputRangeOrTransformer === "function") {
|
|
17
|
+
const transformer = inputRangeOrTransformer;
|
|
18
|
+
value = transformValue(() => transformer(input.get()));
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
value = mapValue(input, inputRangeOrTransformer, outputRange, options);
|
|
22
|
+
}
|
|
23
|
+
onCleanup(() => value.destroy());
|
|
24
|
+
return value;
|
|
25
|
+
}
|