@humanspeak/svelte-motion 0.5.2 → 0.5.4
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/components/LazyMotion.svelte +70 -0
- package/dist/components/LazyMotion.svelte.d.ts +16 -0
- package/dist/components/lazyMotion.context.d.ts +25 -0
- package/dist/components/lazyMotion.context.js +19 -0
- package/dist/components/projection.context.d.ts +22 -0
- package/dist/components/projection.context.js +56 -0
- package/dist/features/domAnimation.d.ts +6 -0
- package/dist/features/domAnimation.js +8 -0
- package/dist/features/domMax.d.ts +5 -0
- package/dist/features/domMax.js +9 -0
- package/dist/features/domMin.d.ts +5 -0
- package/dist/features/domMin.js +6 -0
- package/dist/features/index.d.ts +39 -0
- package/dist/features/index.js +18 -0
- package/dist/html/_MotionContainer.svelte +202 -31
- package/dist/index.d.ts +8 -2
- package/dist/index.js +6 -1
- package/dist/m.d.ts +9 -0
- package/dist/m.js +9 -0
- package/dist/types.d.ts +59 -0
- package/dist/utils/drag.d.ts +42 -11
- package/dist/utils/drag.js +103 -12
- package/dist/utils/layout.d.ts +26 -2
- package/dist/utils/layout.js +13 -2
- package/dist/utils/projection.d.ts +287 -0
- package/dist/utils/projection.js +392 -0
- package/dist/utils/style.d.ts +23 -0
- package/dist/utils/style.js +27 -0
- package/dist/utils/variants.d.ts +26 -0
- package/dist/utils/variants.js +42 -0
- package/package.json +2 -2
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { setLazyMotionContext } from './lazyMotion.context'
|
|
3
|
+
import { domMin } from '../features/domMin'
|
|
4
|
+
import {
|
|
5
|
+
isLazyFeatureBundle,
|
|
6
|
+
normalizeLazyFeatureBundle,
|
|
7
|
+
type FeatureBundle,
|
|
8
|
+
type LazyFeatureBundle
|
|
9
|
+
} from '../features'
|
|
10
|
+
import { untrack, type Snippet } from 'svelte'
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Props accepted by the LazyMotion component.
|
|
14
|
+
*/
|
|
15
|
+
type Props = {
|
|
16
|
+
/** Child content rendered inside the active LazyMotion context. */
|
|
17
|
+
children?: Snippet
|
|
18
|
+
/** Eager or async feature bundle used by descendant `m.*` components. */
|
|
19
|
+
features: FeatureBundle | LazyFeatureBundle
|
|
20
|
+
/** Enables strict LazyMotion usage checks. Defaults to false. */
|
|
21
|
+
strict?: boolean
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
let { children, features, strict = false }: Props = $props()
|
|
25
|
+
|
|
26
|
+
let loadedFeatures = $state<FeatureBundle>(
|
|
27
|
+
untrack(() => (isLazyFeatureBundle(features) ? domMin : features))
|
|
28
|
+
)
|
|
29
|
+
let isLoaded = $state(untrack(() => !isLazyFeatureBundle(features)))
|
|
30
|
+
|
|
31
|
+
setLazyMotionContext({
|
|
32
|
+
getFeatures: () => loadedFeatures,
|
|
33
|
+
getIsLoaded: () => isLoaded,
|
|
34
|
+
get strict() {
|
|
35
|
+
return strict
|
|
36
|
+
}
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
let loadId = 0
|
|
40
|
+
|
|
41
|
+
$effect(() => {
|
|
42
|
+
const currentLoadId = ++loadId
|
|
43
|
+
|
|
44
|
+
if (!isLazyFeatureBundle(features)) {
|
|
45
|
+
loadedFeatures = features
|
|
46
|
+
isLoaded = true
|
|
47
|
+
return
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
loadedFeatures = domMin
|
|
51
|
+
isLoaded = false
|
|
52
|
+
features()
|
|
53
|
+
.then((bundle) => {
|
|
54
|
+
if (currentLoadId !== loadId) return
|
|
55
|
+
loadedFeatures = normalizeLazyFeatureBundle(bundle)
|
|
56
|
+
isLoaded = true
|
|
57
|
+
})
|
|
58
|
+
.catch(() => {
|
|
59
|
+
if (currentLoadId !== loadId) return
|
|
60
|
+
loadedFeatures = domMin
|
|
61
|
+
isLoaded = false
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
return () => {
|
|
65
|
+
loadId += 1
|
|
66
|
+
}
|
|
67
|
+
})
|
|
68
|
+
</script>
|
|
69
|
+
|
|
70
|
+
{@render children?.()}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type FeatureBundle, type LazyFeatureBundle } from '../features';
|
|
2
|
+
import { type Snippet } from 'svelte';
|
|
3
|
+
/**
|
|
4
|
+
* Props accepted by the LazyMotion component.
|
|
5
|
+
*/
|
|
6
|
+
type Props = {
|
|
7
|
+
/** Child content rendered inside the active LazyMotion context. */
|
|
8
|
+
children?: Snippet;
|
|
9
|
+
/** Eager or async feature bundle used by descendant `m.*` components. */
|
|
10
|
+
features: FeatureBundle | LazyFeatureBundle;
|
|
11
|
+
/** Enables strict LazyMotion usage checks. Defaults to false. */
|
|
12
|
+
strict?: boolean;
|
|
13
|
+
};
|
|
14
|
+
declare const LazyMotion: import("svelte").Component<Props, {}, "">;
|
|
15
|
+
type LazyMotion = ReturnType<typeof LazyMotion>;
|
|
16
|
+
export default LazyMotion;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { FeatureBundle } from '../features';
|
|
2
|
+
/**
|
|
3
|
+
* Context value published by `<LazyMotion>` for descendant motion elements.
|
|
4
|
+
*/
|
|
5
|
+
export type LazyMotionContext = {
|
|
6
|
+
/** Returns the currently active feature bundle. */
|
|
7
|
+
getFeatures: () => FeatureBundle;
|
|
8
|
+
/** Returns whether an async bundle has finished loading. */
|
|
9
|
+
getIsLoaded: () => boolean;
|
|
10
|
+
/** Enables Framer Motion-style strict lazy usage checks. */
|
|
11
|
+
strict: boolean;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Reads the nearest LazyMotion context.
|
|
15
|
+
*
|
|
16
|
+
* @returns The active LazyMotion context, or undefined outside LazyMotion.
|
|
17
|
+
*/
|
|
18
|
+
export declare const getLazyMotionContext: () => LazyMotionContext | undefined;
|
|
19
|
+
/**
|
|
20
|
+
* Publishes a LazyMotion context for descendant motion elements.
|
|
21
|
+
*
|
|
22
|
+
* @param context - LazyMotion context to publish.
|
|
23
|
+
* @returns The same context value returned by Svelte's setContext.
|
|
24
|
+
*/
|
|
25
|
+
export declare const setLazyMotionContext: (context: LazyMotionContext) => LazyMotionContext;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { getContext, setContext } from 'svelte';
|
|
2
|
+
const key = Symbol('lazyMotion');
|
|
3
|
+
/**
|
|
4
|
+
* Reads the nearest LazyMotion context.
|
|
5
|
+
*
|
|
6
|
+
* @returns The active LazyMotion context, or undefined outside LazyMotion.
|
|
7
|
+
*/
|
|
8
|
+
export const getLazyMotionContext = () => {
|
|
9
|
+
return getContext(key);
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Publishes a LazyMotion context for descendant motion elements.
|
|
13
|
+
*
|
|
14
|
+
* @param context - LazyMotion context to publish.
|
|
15
|
+
* @returns The same context value returned by Svelte's setContext.
|
|
16
|
+
*/
|
|
17
|
+
export const setLazyMotionContext = (context) => {
|
|
18
|
+
return setContext(key, context);
|
|
19
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { ProjectionNode } from '../utils/projection';
|
|
2
|
+
/**
|
|
3
|
+
* Publish a `ProjectionNode` as the projection parent for descendant
|
|
4
|
+
* motion components.
|
|
5
|
+
*
|
|
6
|
+
* @param node The current component's ProjectionNode, or `null` to
|
|
7
|
+
* explicitly clear (rarely needed — Svelte context auto-clears on
|
|
8
|
+
* component unmount).
|
|
9
|
+
*/
|
|
10
|
+
export declare const setProjectionParent: (node: ProjectionNode | null) => void;
|
|
11
|
+
/**
|
|
12
|
+
* Read the ancestor `ProjectionNode` published by the nearest motion
|
|
13
|
+
* ancestor. Returns `null` when this component is at the root of the
|
|
14
|
+
* projection tree (or when no motion ancestor exists).
|
|
15
|
+
*
|
|
16
|
+
* Must be called BEFORE the current component publishes its own node
|
|
17
|
+
* via `setProjectionParent` — see the order-of-operations note in this
|
|
18
|
+
* file's header.
|
|
19
|
+
*
|
|
20
|
+
* @returns The parent ProjectionNode, or `null`.
|
|
21
|
+
*/
|
|
22
|
+
export declare const getProjectionParent: () => ProjectionNode | null;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { getContext, setContext } from 'svelte';
|
|
2
|
+
/**
|
|
3
|
+
* Svelte context plumbing for the projection tree.
|
|
4
|
+
*
|
|
5
|
+
* Every `motion.*` element creates a `ProjectionNode` at setup time and
|
|
6
|
+
* publishes it via `setProjectionParent(node)` so descendant motion
|
|
7
|
+
* elements can pick it up via `getProjectionParent()` and wire themselves
|
|
8
|
+
* as `node.parent` + register in `node.parent.children`. The tree shape
|
|
9
|
+
* mirrors the Svelte component tree exactly because Svelte's
|
|
10
|
+
* `setContext` propagates down through descendants in component-init
|
|
11
|
+
* order.
|
|
12
|
+
*
|
|
13
|
+
* This is the closest analog we have to framer-motion's depth-sorted
|
|
14
|
+
* FlatTree (`projection/node/create-projection-node.ts`), but without
|
|
15
|
+
* the global `root` registry — parent/child pointers are sufficient
|
|
16
|
+
* for the workflows this PR enables (drag↔swap origin compensation,
|
|
17
|
+
* ancestor-zeroing measure). A global root would only be needed once we
|
|
18
|
+
* port shared-element `layoutId` morphing onto projection nodes; the
|
|
19
|
+
* current `layoutId.ts` registry continues to handle that case
|
|
20
|
+
* independently.
|
|
21
|
+
*
|
|
22
|
+
* Order of operations inside a single `motion.*` component (CRITICAL):
|
|
23
|
+
* 1. Read parent via `getProjectionParent()` BEFORE creating own node.
|
|
24
|
+
* 2. Construct own node, set `node.parent = parent`.
|
|
25
|
+
* 3. Publish own node via `setProjectionParent(node)`.
|
|
26
|
+
* If steps 1 and 3 are reversed, the component sees ITS OWN node as
|
|
27
|
+
* the parent (because `setContext` shadows from the call site down)
|
|
28
|
+
* and the tree collapses to a chain of self-references. Same trap
|
|
29
|
+
* `layoutScroll.context.ts` documents — don't repeat it.
|
|
30
|
+
*/
|
|
31
|
+
const PROJECTION_CONTEXT_KEY = Symbol('svelte-motion:projection-parent');
|
|
32
|
+
/**
|
|
33
|
+
* Publish a `ProjectionNode` as the projection parent for descendant
|
|
34
|
+
* motion components.
|
|
35
|
+
*
|
|
36
|
+
* @param node The current component's ProjectionNode, or `null` to
|
|
37
|
+
* explicitly clear (rarely needed — Svelte context auto-clears on
|
|
38
|
+
* component unmount).
|
|
39
|
+
*/
|
|
40
|
+
export const setProjectionParent = (node) => {
|
|
41
|
+
setContext(PROJECTION_CONTEXT_KEY, node);
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Read the ancestor `ProjectionNode` published by the nearest motion
|
|
45
|
+
* ancestor. Returns `null` when this component is at the root of the
|
|
46
|
+
* projection tree (or when no motion ancestor exists).
|
|
47
|
+
*
|
|
48
|
+
* Must be called BEFORE the current component publishes its own node
|
|
49
|
+
* via `setProjectionParent` — see the order-of-operations note in this
|
|
50
|
+
* file's header.
|
|
51
|
+
*
|
|
52
|
+
* @returns The parent ProjectionNode, or `null`.
|
|
53
|
+
*/
|
|
54
|
+
export const getProjectionParent = () => {
|
|
55
|
+
return getContext(PROJECTION_CONTEXT_KEY) ?? null;
|
|
56
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime capabilities made available to motion components inside a
|
|
3
|
+
* `<LazyMotion>` subtree.
|
|
4
|
+
*/
|
|
5
|
+
export type FeatureBundle = {
|
|
6
|
+
/** Enables initial/animate/exit animation behavior. */
|
|
7
|
+
animations: true;
|
|
8
|
+
/** Enables hover, tap, focus, pan, and in-view gesture behavior. */
|
|
9
|
+
gestures?: true;
|
|
10
|
+
/** Enables drag gesture behavior. */
|
|
11
|
+
drag?: true;
|
|
12
|
+
/** Enables layout and shared-layout animation behavior. */
|
|
13
|
+
layout?: true;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Function form accepted by `<LazyMotion features>`.
|
|
17
|
+
*
|
|
18
|
+
* The function resolves to a feature bundle directly or to a module-like
|
|
19
|
+
* object with the bundle as its default export.
|
|
20
|
+
*/
|
|
21
|
+
export type LazyFeatureBundle = () => Promise<FeatureBundle | {
|
|
22
|
+
default: FeatureBundle;
|
|
23
|
+
}>;
|
|
24
|
+
/**
|
|
25
|
+
* Returns whether a LazyMotion `features` value is an async loader.
|
|
26
|
+
*
|
|
27
|
+
* @param features - Feature bundle or loader passed to `<LazyMotion>`.
|
|
28
|
+
* @returns True when the features value should be invoked asynchronously.
|
|
29
|
+
*/
|
|
30
|
+
export declare const isLazyFeatureBundle: (features: FeatureBundle | LazyFeatureBundle) => features is LazyFeatureBundle;
|
|
31
|
+
/**
|
|
32
|
+
* Normalizes an asynchronously loaded feature bundle.
|
|
33
|
+
*
|
|
34
|
+
* @param loaded - Resolved bundle or default-export module wrapper.
|
|
35
|
+
* @returns The concrete feature bundle.
|
|
36
|
+
*/
|
|
37
|
+
export declare const normalizeLazyFeatureBundle: (loaded: FeatureBundle | {
|
|
38
|
+
default: FeatureBundle;
|
|
39
|
+
}) => FeatureBundle;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns whether a LazyMotion `features` value is an async loader.
|
|
3
|
+
*
|
|
4
|
+
* @param features - Feature bundle or loader passed to `<LazyMotion>`.
|
|
5
|
+
* @returns True when the features value should be invoked asynchronously.
|
|
6
|
+
*/
|
|
7
|
+
export const isLazyFeatureBundle = (features) => typeof features === 'function';
|
|
8
|
+
/**
|
|
9
|
+
* Normalizes an asynchronously loaded feature bundle.
|
|
10
|
+
*
|
|
11
|
+
* @param loaded - Resolved bundle or default-export module wrapper.
|
|
12
|
+
* @returns The concrete feature bundle.
|
|
13
|
+
*/
|
|
14
|
+
export const normalizeLazyFeatureBundle = (loaded) => {
|
|
15
|
+
if ('default' in loaded)
|
|
16
|
+
return loaded.default;
|
|
17
|
+
return loaded;
|
|
18
|
+
};
|