@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.
Files changed (135) hide show
  1. package/LICENSE +48 -0
  2. package/README.md +54 -0
  3. package/dist/animation/animate/index.d.ts +23 -0
  4. package/dist/animation/animate/resolve-subjects.d.ts +3 -0
  5. package/dist/animation/animate/sequence.d.ts +3 -0
  6. package/dist/animation/animate/subject.d.ts +7 -0
  7. package/dist/animation/sequence/create.d.ts +6 -0
  8. package/dist/animation/sequence/types.d.ts +51 -0
  9. package/dist/animation/sequence/utils/calc-repeat-duration.d.ts +1 -0
  10. package/dist/animation/sequence/utils/calc-time.d.ts +2 -0
  11. package/dist/animation/sequence/utils/edit.d.ts +5 -0
  12. package/dist/animation/sequence/utils/normalize-times.d.ts +1 -0
  13. package/dist/animation/sequence/utils/sort.d.ts +2 -0
  14. package/dist/animation/utils/create-visual-element.d.ts +2 -0
  15. package/dist/animation/utils/is-dom-keyframes.d.ts +2 -0
  16. package/dist/components/AnimatePresence.d.ts +27 -0
  17. package/dist/components/AnimatePresenceContext.d.ts +23 -0
  18. package/dist/components/AnimatePresenceTypes.d.ts +57 -0
  19. package/dist/components/MotionConfig.d.ts +16 -0
  20. package/dist/context/MotionContext/create.d.ts +3 -0
  21. package/dist/context/MotionContext/utils.d.ts +3 -0
  22. package/dist/context/MotionContext.d.ts +7 -0
  23. package/dist/context/PresenceContext.d.ts +13 -0
  24. package/dist/events/add-pointer-event.d.ts +2 -0
  25. package/dist/events/event-info.d.ts +4 -0
  26. package/dist/gestures/drag/VisualElementDragControls.d.ts +86 -0
  27. package/dist/gestures/drag/index.d.ts +11 -0
  28. package/dist/gestures/drag/utils/constraints.d.ts +77 -0
  29. package/dist/gestures/focus.d.ts +8 -0
  30. package/dist/gestures/hover.d.ts +5 -0
  31. package/dist/gestures/pan/PanSession.d.ts +102 -0
  32. package/dist/gestures/pan/index.d.ts +15 -0
  33. package/dist/gestures/press.d.ts +5 -0
  34. package/dist/index.d.ts +13 -0
  35. package/dist/index.js +2466 -0
  36. package/dist/index.js.map +1 -0
  37. package/dist/motion/features/animation/exit.d.ts +7 -0
  38. package/dist/motion/features/animation/index.d.ts +9 -0
  39. package/dist/motion/features/animations.d.ts +10 -0
  40. package/dist/motion/features/definitions.d.ts +3 -0
  41. package/dist/motion/features/feature-bundle.d.ts +34 -0
  42. package/dist/motion/features/gestures.d.ts +26 -0
  43. package/dist/motion/features/load-features.d.ts +1 -0
  44. package/dist/motion/index.d.ts +22 -0
  45. package/dist/motion/types.d.ts +27 -0
  46. package/dist/motion/utils/drag-projection.d.ts +3 -0
  47. package/dist/motion/utils/use-visual-state.d.ts +14 -0
  48. package/dist/motion/utils/valid-prop.d.ts +1 -0
  49. package/dist/render/dom/create-visual-element.d.ts +2 -0
  50. package/dist/render/dom/filter-props.d.ts +2 -0
  51. package/dist/render/dom/is-svg-component.d.ts +1 -0
  52. package/dist/render/dom/style.d.ts +1 -0
  53. package/dist/render/html/use-props.d.ts +7 -0
  54. package/dist/render/html/utils/create-render-state.d.ts +2 -0
  55. package/dist/render/svg/lowercase-elements.d.ts +1 -0
  56. package/dist/render/svg/use-props.d.ts +3 -0
  57. package/dist/render/svg/utils/create-render-state.d.ts +2 -0
  58. package/dist/render/types.d.ts +3 -0
  59. package/dist/server.js +2407 -0
  60. package/dist/server.js.map +1 -0
  61. package/dist/source/animation/animate/index.js +39 -0
  62. package/dist/source/animation/animate/resolve-subjects.js +19 -0
  63. package/dist/source/animation/animate/sequence.js +11 -0
  64. package/dist/source/animation/animate/subject.js +37 -0
  65. package/dist/source/animation/sequence/create.js +171 -0
  66. package/dist/source/animation/sequence/types.js +1 -0
  67. package/dist/source/animation/sequence/utils/calc-repeat-duration.js +3 -0
  68. package/dist/source/animation/sequence/utils/calc-time.js +17 -0
  69. package/dist/source/animation/sequence/utils/edit.js +21 -0
  70. package/dist/source/animation/sequence/utils/normalize-times.js +5 -0
  71. package/dist/source/animation/sequence/utils/sort.js +12 -0
  72. package/dist/source/animation/utils/create-visual-element.js +37 -0
  73. package/dist/source/animation/utils/is-dom-keyframes.js +3 -0
  74. package/dist/source/components/AnimatePresence.jsx +444 -0
  75. package/dist/source/components/AnimatePresenceContext.jsx +20 -0
  76. package/dist/source/components/AnimatePresenceTypes.js +1 -0
  77. package/dist/source/components/MotionConfig.jsx +13 -0
  78. package/dist/source/context/MotionContext/create.js +19 -0
  79. package/dist/source/context/MotionContext/utils.js +11 -0
  80. package/dist/source/context/MotionContext.js +2 -0
  81. package/dist/source/context/PresenceContext.js +2 -0
  82. package/dist/source/events/add-pointer-event.js +5 -0
  83. package/dist/source/events/event-info.js +16 -0
  84. package/dist/source/gestures/drag/VisualElementDragControls.js +531 -0
  85. package/dist/source/gestures/drag/index.js +47 -0
  86. package/dist/source/gestures/drag/utils/constraints.js +160 -0
  87. package/dist/source/gestures/focus.js +37 -0
  88. package/dist/source/gestures/hover.js +25 -0
  89. package/dist/source/gestures/pan/PanSession.js +273 -0
  90. package/dist/source/gestures/pan/index.js +46 -0
  91. package/dist/source/gestures/press.js +28 -0
  92. package/dist/source/index.js +11 -0
  93. package/dist/source/motion/features/animation/exit.js +33 -0
  94. package/dist/source/motion/features/animation/index.js +27 -0
  95. package/dist/source/motion/features/animations.js +10 -0
  96. package/dist/source/motion/features/definitions.js +29 -0
  97. package/dist/source/motion/features/feature-bundle.js +6 -0
  98. package/dist/source/motion/features/gestures.js +20 -0
  99. package/dist/source/motion/features/load-features.js +12 -0
  100. package/dist/source/motion/index.jsx +176 -0
  101. package/dist/source/motion/types.js +1 -0
  102. package/dist/source/motion/utils/drag-projection.js +16 -0
  103. package/dist/source/motion/utils/use-visual-state.js +53 -0
  104. package/dist/source/motion/utils/valid-prop.js +40 -0
  105. package/dist/source/render/dom/create-visual-element.js +10 -0
  106. package/dist/source/render/dom/filter-props.js +15 -0
  107. package/dist/source/render/dom/is-svg-component.js +10 -0
  108. package/dist/source/render/dom/style.js +12 -0
  109. package/dist/source/render/html/use-props.js +39 -0
  110. package/dist/source/render/html/utils/create-render-state.js +6 -0
  111. package/dist/source/render/svg/lowercase-elements.js +27 -0
  112. package/dist/source/render/svg/use-props.js +28 -0
  113. package/dist/source/render/svg/utils/create-render-state.js +5 -0
  114. package/dist/source/render/types.js +1 -0
  115. package/dist/source/utils/distance.js +7 -0
  116. package/dist/source/utils/get-context-window.js +4 -0
  117. package/dist/source/utils/is-ref-object.js +5 -0
  118. package/dist/source/utils/safe-react-types.js +1 -0
  119. package/dist/source/utils/use-reduced-motion.js +15 -0
  120. package/dist/source/value/use-motion-value-event.js +5 -0
  121. package/dist/source/value/use-motion-value.js +16 -0
  122. package/dist/source/value/use-spring.js +59 -0
  123. package/dist/source/value/use-transform.js +25 -0
  124. package/dist/source/value/use-velocity.js +17 -0
  125. package/dist/utils/distance.d.ts +3 -0
  126. package/dist/utils/get-context-window.d.ts +2 -0
  127. package/dist/utils/is-ref-object.d.ts +2 -0
  128. package/dist/utils/safe-react-types.d.ts +3 -0
  129. package/dist/utils/use-reduced-motion.d.ts +6 -0
  130. package/dist/value/use-motion-value-event.d.ts +3 -0
  131. package/dist/value/use-motion-value.d.ts +5 -0
  132. package/dist/value/use-spring.d.ts +5 -0
  133. package/dist/value/use-transform.d.ts +9 -0
  134. package/dist/value/use-velocity.d.ts +3 -0
  135. package/package.json +61 -0
@@ -0,0 +1,444 @@
1
+ import { batch, children, createEffect, createMemo, createSignal, For, Index, mergeProps, on, onMount, splitProps, untrack, useContext } from "solid-js";
2
+ import { PresenceContext } from "../context/PresenceContext";
3
+ let presenceCounter = 0;
4
+ let autoKeyIndex = 0;
5
+ const autoKeyMap = new WeakMap();
6
+ /**
7
+ * AnimatePresence for Solid.js
8
+ *
9
+ * Enables exit animations by keeping elements in the DOM
10
+ * until their exit animations complete.
11
+ *
12
+ * @example
13
+ * ```solid
14
+ * <AnimatePresence>
15
+ * {show() && (
16
+ * <motion.div
17
+ * exit={{ opacity: 0 }}
18
+ * />
19
+ * )}
20
+ * </AnimatePresence>
21
+ * ```
22
+ */
23
+ export function AnimatePresence(props) {
24
+ const merged = mergeProps({
25
+ initial: true,
26
+ mode: "sync",
27
+ presenceAffectsLayout: true,
28
+ }, props);
29
+ const [local, others] = splitProps(merged, [
30
+ "children",
31
+ "when",
32
+ "presenceKey",
33
+ "initial",
34
+ "onExitComplete",
35
+ "mode",
36
+ "presenceAffectsLayout",
37
+ "custom",
38
+ "anchorX",
39
+ "root",
40
+ ]);
41
+ // Track if this is the initial render
42
+ let isInitialRender = true;
43
+ let didWarn = false;
44
+ const warnNonFactory = () => {
45
+ if (didWarn)
46
+ return;
47
+ didWarn = true;
48
+ console.warn("[AnimatePresence] Solid requires children to be a function for exit animations to work reliably. " +
49
+ "Use <AnimatePresence when={condition}>{() => <motion.div .../>}</AnimatePresence>.");
50
+ };
51
+ if (local.when !== undefined) {
52
+ const currentChild = createMemo(() => {
53
+ if (!local.when)
54
+ return undefined;
55
+ const childrenValue = local.children;
56
+ const getChild = () => {
57
+ let value = typeof childrenValue === "function" ? childrenValue() : childrenValue;
58
+ if (typeof value === "function" && value.length === 0) {
59
+ value = value();
60
+ }
61
+ return value;
62
+ };
63
+ if (typeof childrenValue !== "function") {
64
+ warnNonFactory();
65
+ }
66
+ return { key: local.presenceKey ?? "index-0", getChild };
67
+ });
68
+ const initialChild = currentChild();
69
+ const [rendered, setRendered] = createSignal(initialChild ? [initialChild] : []);
70
+ createEffect(on(currentChild, (next) => {
71
+ const previous = untrack(rendered);
72
+ const exiting = previous.filter((child) => child.key !== next?.key);
73
+ // Reuse the mounted record on reentry, so its exit can reverse in place.
74
+ const present = next && (previous.find((child) => child.key === next.key) ?? next);
75
+ setRendered(local.mode === "wait" && exiting.length
76
+ ? exiting
77
+ : present ? [present, ...exiting] : exiting);
78
+ }, { defer: true }));
79
+ onMount(() => { isInitialRender = false; });
80
+ return (<For each={rendered()}>
81
+ {(child) => {
82
+ const isPresent = () => currentChild()?.key === child.key;
83
+ const onExitComplete = () => {
84
+ const next = untrack(currentChild);
85
+ const previous = untrack(rendered);
86
+ if (next?.key === child.key || !previous.includes(child))
87
+ return;
88
+ const remaining = previous.filter((item) => item !== child);
89
+ const hasExits = remaining.some((item) => item.key !== next?.key);
90
+ setRendered(!hasExits && next
91
+ ? [remaining.find((item) => item.key === next.key) ?? next]
92
+ : remaining);
93
+ if (!hasExits)
94
+ local.onExitComplete?.();
95
+ };
96
+ return (<PresenceChild key={child.key} isPresent={isPresent} onExitComplete={isPresent() ? undefined : onExitComplete} initial={isInitialRender && !local.initial ? false : undefined} custom={local.custom} presenceAffectsLayout={local.presenceAffectsLayout} getChild={child.getChild} childKey={child.key} mode={local.mode} anchorX={local.anchorX} root={local.root}/>);
97
+ }}
98
+ </For>);
99
+ }
100
+ const resolveChildrenList = () => {
101
+ const childrenValue = local.children;
102
+ if (local.when !== undefined) {
103
+ if (!local.when)
104
+ return [];
105
+ if (typeof childrenValue !== "function") {
106
+ warnNonFactory();
107
+ }
108
+ const getChild = typeof childrenValue === "function" ? childrenValue : () => childrenValue;
109
+ const key = local.presenceKey ?? "index-0";
110
+ return [{ key, getChild }];
111
+ }
112
+ const child = typeof childrenValue === "function" ? childrenValue() : childrenValue;
113
+ if (!child || child === true)
114
+ return [];
115
+ const list = Array.isArray(child) ? child : [child];
116
+ return list
117
+ .filter((item) => item !== false && item != null)
118
+ .map((item, index) => ({
119
+ key: getChildKey(item, index),
120
+ getChild: () => item,
121
+ }));
122
+ };
123
+ // Track present children (filtered to elements only)
124
+ const presentChildren = createMemo(() => resolveChildrenList());
125
+ // Track which keys are currently present
126
+ const presentKeys = createMemo(() => {
127
+ return presentChildren().map((child) => child.key);
128
+ });
129
+ // Track all children that should be rendered (including exiting ones)
130
+ const [allChildren, setAllChildren] = createSignal([], { equals: false });
131
+ // Track exit completion status per key
132
+ const [exitStatus, setExitStatus] = createSignal(new Map(), { equals: false });
133
+ // Handle child changes
134
+ createEffect(() => {
135
+ const current = presentChildren();
136
+ const currentKeys = presentKeys();
137
+ const prev = untrack(allChildren);
138
+ const prevExitStatus = untrack(exitStatus);
139
+ let nextExitStatus = prevExitStatus;
140
+ let exitStatusChanged = false;
141
+ // Identify exiting children
142
+ const exitingChildren = prev.filter((child) => !currentKeys.includes(child.key));
143
+ // Clear exit tracking for children that re-entered
144
+ prevExitStatus.forEach((_, key) => {
145
+ if (currentKeys.includes(key)) {
146
+ if (!exitStatusChanged) {
147
+ nextExitStatus = new Map(prevExitStatus);
148
+ exitStatusChanged = true;
149
+ }
150
+ nextExitStatus.delete(key);
151
+ }
152
+ });
153
+ // Mark exiting children
154
+ exitingChildren.forEach((child) => {
155
+ if (!prevExitStatus.has(child.key)) {
156
+ if (!exitStatusChanged) {
157
+ nextExitStatus = new Map(prevExitStatus);
158
+ exitStatusChanged = true;
159
+ }
160
+ nextExitStatus.set(child.key, false);
161
+ }
162
+ });
163
+ if (exitStatusChanged) {
164
+ setExitStatus(nextExitStatus);
165
+ }
166
+ // Build new allChildren array
167
+ const nextChildren = [];
168
+ // Add all current children
169
+ for (let i = 0; i < current.length; i++) {
170
+ const child = current[i];
171
+ nextChildren.push({
172
+ key: child.key,
173
+ getChild: child.getChild,
174
+ isPresent: true,
175
+ index: i,
176
+ });
177
+ }
178
+ // In "wait" mode, only show exiting children until they're all done
179
+ if (local.mode === "wait" && exitingChildren.length > 0) {
180
+ nextChildren.length = 0;
181
+ exitingChildren.forEach((child) => {
182
+ nextChildren.push({
183
+ ...child,
184
+ isPresent: false,
185
+ });
186
+ });
187
+ }
188
+ else {
189
+ // In "sync" and "popLayout" modes, include exiting children alongside present ones
190
+ exitingChildren.forEach((child) => {
191
+ nextChildren.push({
192
+ ...child,
193
+ isPresent: false,
194
+ });
195
+ });
196
+ }
197
+ const isSame = prev.length === nextChildren.length &&
198
+ prev.every((child, index) => {
199
+ const next = nextChildren[index];
200
+ return child.key === next.key && child.getChild === next.getChild && child.isPresent === next.isPresent;
201
+ });
202
+ if (!isSame) {
203
+ setAllChildren(nextChildren);
204
+ }
205
+ });
206
+ // Check if all exits are complete
207
+ const allExitsComplete = createMemo(() => {
208
+ const status = exitStatus();
209
+ if (!status.size)
210
+ return false;
211
+ for (const isComplete of status.values()) {
212
+ if (!isComplete)
213
+ return false;
214
+ }
215
+ return true;
216
+ });
217
+ // Handle completion
218
+ createEffect(() => {
219
+ if (allExitsComplete()) {
220
+ // All exits done, clean up and notify
221
+ batch(() => {
222
+ setExitStatus(new Map());
223
+ // Filter to only present children
224
+ const current = presentChildren();
225
+ const keys = presentKeys();
226
+ setAllChildren(current.map((child, i) => ({
227
+ key: child.key,
228
+ getChild: child.getChild,
229
+ isPresent: true,
230
+ index: i,
231
+ })));
232
+ });
233
+ local.onExitComplete?.();
234
+ }
235
+ });
236
+ // Mark initial render complete after first mount
237
+ onMount(() => {
238
+ isInitialRender = false;
239
+ });
240
+ return (<Index each={allChildren()}>
241
+ {(childState) => {
242
+ const state = childState;
243
+ const isPresent = () => state().isPresent;
244
+ const onExitComplete = () => {
245
+ const status = untrack(exitStatus);
246
+ const key = state().key;
247
+ if (!status.has(key))
248
+ return;
249
+ batch(() => {
250
+ setExitStatus((map) => {
251
+ const newMap = new Map(map);
252
+ if (!newMap.has(key))
253
+ return newMap;
254
+ newMap.set(key, true);
255
+ return newMap;
256
+ });
257
+ });
258
+ };
259
+ return (<PresenceChild key={state().key} isPresent={isPresent} onExitComplete={isPresent() ? undefined : onExitComplete} initial={isInitialRender && !local.initial ? false : undefined} custom={local.custom} presenceAffectsLayout={local.presenceAffectsLayout} getChild={state().getChild} childKey={state().key} mode={local.mode} anchorX={local.anchorX} root={local.root}/>);
260
+ }}
261
+ </Index>);
262
+ }
263
+ function PopChild(props) {
264
+ let container;
265
+ let wasPresent = props.isPresent;
266
+ const [style, setStyle] = createSignal({ display: "contents" });
267
+ createEffect(() => {
268
+ const now = props.isPresent;
269
+ if (wasPresent && !now) {
270
+ const target = container?.firstElementChild ?? container;
271
+ if (target) {
272
+ const rect = target.getBoundingClientRect();
273
+ const parent = target.offsetParent;
274
+ const parentRect = parent ? parent.getBoundingClientRect() : { left: 0, top: 0, width: 0 };
275
+ const top = rect.top - parentRect.top;
276
+ const left = rect.left - parentRect.left;
277
+ const right = parent ? parentRect.width - rect.width - left : 0;
278
+ const x = props.anchorX === "right"
279
+ ? { right: `${right}px`, left: "auto" }
280
+ : { left: `${left}px`, right: "auto" };
281
+ setStyle({
282
+ position: "absolute",
283
+ top: `${top}px`,
284
+ width: `${rect.width}px`,
285
+ height: `${rect.height}px`,
286
+ ...x,
287
+ });
288
+ }
289
+ }
290
+ else if (now) {
291
+ setStyle({ display: "contents" });
292
+ }
293
+ wasPresent = now;
294
+ });
295
+ return (<div ref={(el) => (container = el)} style={style()}>
296
+ {props.children}
297
+ </div>);
298
+ }
299
+ /**
300
+ * Individual presence child wrapper
301
+ */
302
+ function PresenceChild(props) {
303
+ const presenceId = String(presenceCounter++);
304
+ const [local, others] = splitProps(props, [
305
+ "isPresent",
306
+ "getChild",
307
+ "childKey",
308
+ "onExitComplete",
309
+ "initial",
310
+ "custom",
311
+ "presenceAffectsLayout",
312
+ "mode",
313
+ "anchorX",
314
+ "root",
315
+ ]);
316
+ // Track registered exit handlers from child motion components
317
+ const [registeredChildren, setRegisteredChildren] = createSignal(new Map());
318
+ // Create presence context for this child
319
+ const register = (childId) => {
320
+ const key = String(childId);
321
+ batch(() => {
322
+ setRegisteredChildren((map) => {
323
+ const newMap = new Map(map);
324
+ newMap.set(key, false);
325
+ return newMap;
326
+ });
327
+ });
328
+ return () => {
329
+ batch(() => {
330
+ setRegisteredChildren((map) => {
331
+ const newMap = new Map(map);
332
+ newMap.delete(key);
333
+ return newMap;
334
+ });
335
+ });
336
+ };
337
+ };
338
+ const onExitComplete = (childId) => {
339
+ if (!local.onExitComplete)
340
+ return;
341
+ const key = String(childId);
342
+ batch(() => {
343
+ setRegisteredChildren((map) => {
344
+ const newMap = new Map(map);
345
+ newMap.set(key, true);
346
+ return newMap;
347
+ });
348
+ });
349
+ const allComplete = Array.from(registeredChildren().values()).every(Boolean);
350
+ if (allComplete) {
351
+ local.onExitComplete?.();
352
+ }
353
+ };
354
+ createEffect(on(local.isPresent, (present) => {
355
+ const current = untrack(registeredChildren);
356
+ if (current.size) {
357
+ setRegisteredChildren((map) => {
358
+ const newMap = new Map(map);
359
+ newMap.forEach((_, key) => newMap.set(key, false));
360
+ return newMap;
361
+ });
362
+ }
363
+ if (!present && current.size === 0) {
364
+ local.onExitComplete?.();
365
+ }
366
+ }, { defer: true }));
367
+ const resolvedInitial = () => {
368
+ if (local.initial === false)
369
+ return false;
370
+ if (typeof local.initial === "string" || Array.isArray(local.initial))
371
+ return local.initial;
372
+ return undefined;
373
+ };
374
+ const presenceContext = createMemo(() => ({
375
+ id: () => presenceId,
376
+ isPresent: local.isPresent,
377
+ initial: () => resolvedInitial(),
378
+ custom: () => local.custom,
379
+ onExitComplete,
380
+ register,
381
+ }));
382
+ return (<PresenceContext.Provider value={presenceContext()}>
383
+ <PresenceChildContent getChild={local.getChild} childKey={local.childKey} isPresent={local.isPresent} mode={local.mode} anchorX={local.anchorX} root={local.root}/>
384
+ </PresenceContext.Provider>);
385
+ }
386
+ function PresenceChildContent(props) {
387
+ const resolved = children(() => {
388
+ props.childKey;
389
+ return untrack(() => props.getChild());
390
+ });
391
+ if (props.mode === "popLayout") {
392
+ return (<PopChild isPresent={props.isPresent()} anchorX={props.anchorX} root={props.root}>
393
+ {resolved()}
394
+ </PopChild>);
395
+ }
396
+ return resolved();
397
+ }
398
+ /**
399
+ * Get a unique key for a child element
400
+ */
401
+ function getChildKey(child, index) {
402
+ if (!child)
403
+ return "";
404
+ const directKey = child.key ?? child.id ?? child?.props?.key;
405
+ if (directKey != null && directKey !== "")
406
+ return directKey;
407
+ if (typeof child === "string" || typeof child === "number")
408
+ return child;
409
+ if (typeof child === "object" || typeof child === "function") {
410
+ const cached = autoKeyMap.get(child);
411
+ if (cached)
412
+ return cached;
413
+ }
414
+ const nextKey = `index-${index}`;
415
+ if (typeof child === "object" || typeof child === "function") {
416
+ autoKeyMap.set(child, nextKey);
417
+ }
418
+ return nextKey;
419
+ }
420
+ /**
421
+ * Hook to access presence state and signal safe removal
422
+ */
423
+ export function usePresence() {
424
+ const context = useContext(PresenceContext);
425
+ if (!context) {
426
+ return [true, null];
427
+ }
428
+ const isPresent = context.isPresent();
429
+ const safeToRemove = () => {
430
+ if (context.onExitComplete) {
431
+ context.onExitComplete(context.id());
432
+ }
433
+ };
434
+ return [!isPresent ? false : true, !isPresent ? safeToRemove : null];
435
+ }
436
+ /**
437
+ * Simple hook to check if component is present
438
+ */
439
+ export function useIsPresent() {
440
+ const context = useContext(PresenceContext);
441
+ if (!context)
442
+ return true;
443
+ return context.isPresent();
444
+ }
@@ -0,0 +1,20 @@
1
+ import { createContext, useContext } from "solid-js";
2
+ export const AnimatePresenceContext = createContext(null);
3
+ export function AnimatePresenceProvider(props) {
4
+ return (<AnimatePresenceContext.Provider value={props.value}>
5
+ {props.children}
6
+ </AnimatePresenceContext.Provider>);
7
+ }
8
+ export function createPresenceState(config) {
9
+ return {
10
+ id: config.id,
11
+ isPresent: config.isPresent,
12
+ initial: config.initial,
13
+ custom: config.custom || (() => undefined),
14
+ onExitComplete: config.onExitComplete,
15
+ register: config.register || (() => () => { }),
16
+ };
17
+ }
18
+ export function usePresenceInternal() {
19
+ return useContext(AnimatePresenceContext);
20
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,13 @@
1
+ import { createContext, splitProps, useContext } from "solid-js";
2
+ const defaultContext = {
3
+ transformPagePoint: ((p) => p),
4
+ isStatic: false,
5
+ reducedMotion: "never",
6
+ };
7
+ export const MotionConfigContext = createContext(defaultContext);
8
+ export function MotionConfig(props) {
9
+ const parent = useContext(MotionConfigContext);
10
+ const [local, contextProps] = splitProps(props, ["children"]);
11
+ const value = { ...parent, ...contextProps };
12
+ return <MotionConfigContext.Provider value={value}>{local.children}</MotionConfigContext.Provider>;
13
+ }
@@ -0,0 +1,19 @@
1
+ import { createEffect, createSignal } from "solid-js";
2
+ import { getCurrentTreeVariants } from "./utils";
3
+ export function createMotionContext(props, parentContext) {
4
+ const [initial, setInitial] = createSignal();
5
+ const [animate, setAnimate] = createSignal();
6
+ createEffect(() => {
7
+ const variants = getCurrentTreeVariants(props, parentContext);
8
+ setInitial(variants.initial);
9
+ setAnimate(variants.animate);
10
+ });
11
+ return {
12
+ get initial() {
13
+ return initial();
14
+ },
15
+ get animate() {
16
+ return animate();
17
+ },
18
+ };
19
+ }
@@ -0,0 +1,11 @@
1
+ import { isControllingVariants, isVariantLabel } from "motion-dom";
2
+ export function getCurrentTreeVariants(props, context) {
3
+ if (isControllingVariants(props)) {
4
+ const { initial, animate } = props;
5
+ return {
6
+ initial: initial === false || isVariantLabel(initial) ? initial : undefined,
7
+ animate: isVariantLabel(animate) ? animate : undefined,
8
+ };
9
+ }
10
+ return props.inherit !== false ? context : {};
11
+ }
@@ -0,0 +1,2 @@
1
+ import { createContext } from "solid-js";
2
+ export const MotionContext = createContext({});
@@ -0,0 +1,2 @@
1
+ import { createContext } from "solid-js";
2
+ export const PresenceContext = createContext(null);
@@ -0,0 +1,5 @@
1
+ import { addDomEvent } from "motion-dom";
2
+ import { addPointerInfo } from "./event-info";
3
+ export function addPointerEvent(target, eventName, handler, options) {
4
+ return addDomEvent(target, eventName, addPointerInfo(handler), options);
5
+ }
@@ -0,0 +1,16 @@
1
+ import { isPrimaryPointer } from "motion-dom";
2
+ export function extractEventInfo(event) {
3
+ return {
4
+ point: {
5
+ x: event.pageX,
6
+ y: event.pageY,
7
+ },
8
+ };
9
+ }
10
+ export const addPointerInfo = (handler) => {
11
+ return (event) => {
12
+ const pointer = event;
13
+ if (isPrimaryPointer(pointer))
14
+ handler(pointer, extractEventInfo(pointer));
15
+ };
16
+ };