@humanspeak/svelte-motion 0.1.16 → 0.1.17

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.
@@ -1,6 +1,10 @@
1
1
  <script lang="ts">
2
2
  import type { Snippet } from 'svelte'
3
- import { createAnimatePresenceContext, setAnimatePresenceContext } from '../utils/presence'
3
+ import {
4
+ createAnimatePresenceContext,
5
+ setAnimatePresenceContext,
6
+ setPresenceDepth
7
+ } from '../utils/presence'
4
8
  import { pwLog } from '../utils/log'
5
9
 
6
10
  /**
@@ -27,6 +31,10 @@
27
31
  pwLog('[AnimatePresence] mounting', { initial, hasOnExitComplete: !!onExitComplete })
28
32
  const context = createAnimatePresenceContext({ initial, onExitComplete })
29
33
  setAnimatePresenceContext(context)
34
+
35
+ // Initialize presence depth to 0 for direct children
36
+ // Only direct children (depth 0) require explicit key props, matching Framer Motion behavior
37
+ setPresenceDepth(0)
30
38
  </script>
31
39
 
32
40
  <div class="animate-presence-container">
@@ -35,6 +43,6 @@
35
43
 
36
44
  <style>
37
45
  .animate-presence-container {
38
- position: relative;
46
+ display: contents;
39
47
  }
40
48
  </style>
@@ -36,7 +36,12 @@
36
36
  import type { SvelteHTMLElements } from 'svelte/elements'
37
37
  import { mergeInlineStyles } from '../utils/style'
38
38
  import { isNativelyFocusable } from '../utils/a11y'
39
- import { usePresence, getAnimatePresenceContext } from '../utils/presence'
39
+ import {
40
+ usePresence,
41
+ getAnimatePresenceContext,
42
+ getPresenceDepth,
43
+ setPresenceDepth
44
+ } from '../utils/presence'
40
45
  import { getInitialKeyframes } from '../utils/initial'
41
46
  import { attachDrag } from '../utils/drag'
42
47
  import { resolveInitial, resolveAnimate, resolveExit } from '../utils/variants'
@@ -47,7 +52,12 @@
47
52
  getInitialFalseContext
48
53
  } from '../components/variantContext.context'
49
54
  import { writable } from 'svelte/store'
50
- import { transformSVGPathProperties, computeNormalizedSVGInitialAttrs } from '../utils/svg'
55
+ import {
56
+ transformSVGPathProperties,
57
+ computeNormalizedSVGInitialAttrs,
58
+ isSVGTag,
59
+ SVG_NAMESPACE
60
+ } from '../utils/svg'
51
61
 
52
62
  type Props = MotionProps & {
53
63
  children?: Snippet
@@ -108,18 +118,33 @@
108
118
  // Get presence context to check if we're inside AnimatePresence
109
119
  const context = getAnimatePresenceContext()
110
120
 
111
- // Validate key prop when inside AnimatePresence
112
- if (context && !keyProp) {
121
+ // Get current presence depth (0 = direct child of AnimatePresence, undefined = not in AnimatePresence)
122
+ const presenceDepth = getPresenceDepth()
123
+
124
+ // Validate key prop only for direct children of AnimatePresence (depth 0)
125
+ // This matches Framer Motion behavior where only immediate children need keys
126
+ if (context && presenceDepth === 0 && !keyProp) {
113
127
  throw new Error(
114
- 'motion elements inside AnimatePresence must have a `key` prop. ' +
128
+ 'motion elements that are direct children of AnimatePresence must have a `key` prop. ' +
115
129
  'Example: <motion.div key="unique-id" />'
116
130
  )
117
131
  }
118
132
 
133
+ // Increment depth for descendants so nested motion elements don't require keys
134
+ if (presenceDepth !== undefined) {
135
+ setPresenceDepth(presenceDepth + 1)
136
+ }
137
+
119
138
  // Use the provided key for presence tracking
120
139
  // When not inside AnimatePresence, use a stable identifier based on component instance
121
140
  const presenceKey = keyProp ?? `motion-${++keyCounter}`
122
141
 
142
+ // Track previous key for key-change detection (simulates React's key-based remounting)
143
+ // Using $state for idiomatic Svelte 5 reactivity
144
+ let keyTrackerPrev = $state(keyProp)
145
+ let keyTrackerIsTransitioning = $state(false)
146
+ let keyTransitionStopped = $state(false)
147
+
123
148
  // Compute merged transition without mutating props to avoid effect write loops
124
149
  const mergedTransition = $derived<AnimationOptions>(
125
150
  mergeTransitions(
@@ -556,6 +581,92 @@
556
581
  )
557
582
  })
558
583
 
584
+ // Handle key prop changes inside AnimatePresence (simulates React's key-based remounting)
585
+ // When key changes, run exit → initial → animate sequence on the same element
586
+ $effect(() => {
587
+ // Access keyProp to create reactive dependency
588
+ const currentKey = keyProp
589
+
590
+ // Only handle key changes when:
591
+ // 1. We're inside AnimatePresence (context exists)
592
+ // 2. Element is ready (not during initial mount)
593
+ // 3. Key actually changed (not undefined → value on mount)
594
+ // 4. Not already transitioning
595
+ if (
596
+ !context ||
597
+ !element ||
598
+ isLoaded !== 'ready' ||
599
+ keyTrackerIsTransitioning ||
600
+ currentKey === keyTrackerPrev ||
601
+ keyTrackerPrev === undefined
602
+ ) {
603
+ // Update prev for next comparison
604
+ if (currentKey !== keyTrackerPrev) {
605
+ keyTrackerPrev = currentKey
606
+ }
607
+ return
608
+ }
609
+
610
+ pwLog('[motion] key changed, running exit→initial→animate', {
611
+ prevKey: keyTrackerPrev,
612
+ newKey: currentKey
613
+ })
614
+
615
+ // Mark as transitioning to prevent re-entry
616
+ keyTrackerIsTransitioning = true
617
+ keyTrackerPrev = currentKey
618
+
619
+ // Run the key transition sequence
620
+ const runKeyTransition = async () => {
621
+ try {
622
+ // 1. Run exit animation if defined
623
+ if (resolvedExit && element && !keyTransitionStopped) {
624
+ const exitKeyframes = { ...(resolvedExit as Record<string, unknown>) }
625
+ // Remove transition from keyframes (it's passed separately)
626
+ delete exitKeyframes.transition
627
+
628
+ pwLog('[motion] key transition: running exit', { exitKeyframes })
629
+ await animate(
630
+ element,
631
+ exitKeyframes as DOMKeyframesDefinition,
632
+ mergedTransition
633
+ ).finished
634
+ }
635
+
636
+ // Check if component was unmounted during exit animation
637
+ if (keyTransitionStopped || !element) return
638
+
639
+ // 2. Snap to initial state
640
+ if (initialKeyframes && element) {
641
+ const transformedInitial = transformSVGPathProperties(
642
+ element,
643
+ initialKeyframes as Record<string, unknown>
644
+ )
645
+ pwLog('[motion] key transition: snapping to initial', { transformedInitial })
646
+ animate(element, transformedInitial as DOMKeyframesDefinition, { duration: 0 })
647
+ }
648
+
649
+ // Check again before running enter animation
650
+ if (keyTransitionStopped || !element) return
651
+
652
+ // 3. Run enter animation
653
+ pwLog('[motion] key transition: running enter animation')
654
+ runAnimation()
655
+ } finally {
656
+ if (!keyTransitionStopped) {
657
+ keyTrackerIsTransitioning = false
658
+ }
659
+ }
660
+ }
661
+
662
+ runKeyTransition()
663
+
664
+ // Cleanup on unmount
665
+ return () => {
666
+ keyTransitionStopped = true
667
+ }
668
+ })
669
+
559
670
  // Re-run animate when animateProp changes while ready
560
671
  $effect(() => {
561
672
  if (!(element && isLoaded === 'ready')) return
@@ -765,7 +876,15 @@
765
876
  </script>
766
877
 
767
878
  {#if isVoidTag}
768
- <svelte:element this={tag} bind:this={element} {...derivedAttrs} />
879
+ {#if isSVGTag(String(tag))}
880
+ <svelte:element this={tag} bind:this={element} xmlns={SVG_NAMESPACE} {...derivedAttrs} />
881
+ {:else}
882
+ <svelte:element this={tag} bind:this={element} {...derivedAttrs} />
883
+ {/if}
884
+ {:else if isSVGTag(String(tag))}
885
+ <svelte:element this={tag} bind:this={element} xmlns={SVG_NAMESPACE} {...derivedAttrs}>
886
+ {@render children?.()}
887
+ </svelte:element>
769
888
  {:else}
770
889
  <svelte:element this={tag} bind:this={element} {...derivedAttrs}>
771
890
  {@render children?.()}
package/dist/index.d.ts CHANGED
@@ -7,7 +7,11 @@ export type { DragAxis, DragConstraints, DragControls, DragInfo, DragTransition,
7
7
  export { useAnimationFrame } from './utils/animationFrame';
8
8
  export { createDragControls } from './utils/dragControls';
9
9
  export { useSpring } from './utils/spring';
10
+ /**
11
+ * @deprecated Use `styleString` instead for reactive styles with automatic unit handling.
12
+ */
10
13
  export { stringifyStyleObject } from './utils/styleObject';
14
+ export { styleString } from './utils/styleObject.svelte';
11
15
  export { useTime } from './utils/time';
12
16
  export { useTransform } from './utils/transform';
13
17
  export { AnimatePresence, MotionConfig };
package/dist/index.js CHANGED
@@ -8,7 +8,11 @@ export { animate, hover } from 'motion';
8
8
  export { useAnimationFrame } from './utils/animationFrame';
9
9
  export { createDragControls } from './utils/dragControls';
10
10
  export { useSpring } from './utils/spring';
11
+ /**
12
+ * @deprecated Use `styleString` instead for reactive styles with automatic unit handling.
13
+ */
11
14
  export { stringifyStyleObject } from './utils/styleObject';
15
+ export { styleString } from './utils/styleObject.svelte';
12
16
  export { useTime } from './utils/time';
13
17
  export { useTransform } from './utils/transform';
14
18
  export { AnimatePresence, MotionConfig };
@@ -58,6 +58,45 @@ export declare function getAnimatePresenceContext(): AnimatePresenceContext | un
58
58
  * Note: Trivial wrapper - ignored for coverage.
59
59
  */
60
60
  export declare function setAnimatePresenceContext(context: AnimatePresenceContext): void;
61
+ /**
62
+ * Get the current presence depth from Svelte component context.
63
+ *
64
+ * Returns undefined if not inside an AnimatePresence, or the depth level
65
+ * where 0 means direct child of AnimatePresence.
66
+ *
67
+ * @returns The current depth level (0 for direct children), or undefined if outside AnimatePresence.
68
+ * @example
69
+ * ```ts
70
+ * const depth = getPresenceDepth()
71
+ * if (depth === 0) {
72
+ * // Direct child of AnimatePresence - key prop required
73
+ * }
74
+ * ```
75
+ *
76
+ * Note: Trivial wrapper - ignored for coverage.
77
+ */
78
+ export declare const getPresenceDepth: () => number | undefined;
79
+ /**
80
+ * Set the presence depth in Svelte component context.
81
+ *
82
+ * AnimatePresence sets this to 0, and each motion element increments it
83
+ * for its descendants so only direct children (depth 0) require keys.
84
+ *
85
+ * @param depth - The nesting depth to set (0 for direct children of AnimatePresence).
86
+ * @returns void
87
+ * @example
88
+ * ```ts
89
+ * // In AnimatePresence component
90
+ * setPresenceDepth(0)
91
+ *
92
+ * // In nested motion element
93
+ * const currentDepth = getPresenceDepth() ?? 0
94
+ * setPresenceDepth(currentDepth + 1)
95
+ * ```
96
+ *
97
+ * Note: Trivial wrapper - ignored for coverage.
98
+ */
99
+ export declare const setPresenceDepth: (depth: number) => void;
61
100
  /**
62
101
  * Hook used by motion elements to participate in presence.
63
102
  * Registers the element and ensures its exit animation runs on teardown.
@@ -8,6 +8,13 @@ import { getContext, onDestroy, setContext } from 'svelte';
8
8
  * Used with Svelte's context API to provide/register presence management.
9
9
  */
10
10
  const ANIMATE_PRESENCE_CONTEXT = Symbol('animate-presence-context');
11
+ /**
12
+ * Context key for tracking nesting depth within AnimatePresence.
13
+ *
14
+ * Used to enforce key requirements only on direct children (depth 0),
15
+ * matching Framer Motion behavior where only immediate children need keys.
16
+ */
17
+ const PRESENCE_DEPTH_CONTEXT = Symbol('presence-depth-context');
11
18
  /**
12
19
  * Reset any CSS transforms on the element's inline style.
13
20
  *
@@ -331,6 +338,49 @@ export function getAnimatePresenceContext() {
331
338
  export function setAnimatePresenceContext(context) {
332
339
  setContext(ANIMATE_PRESENCE_CONTEXT, context);
333
340
  }
341
+ /**
342
+ * Get the current presence depth from Svelte component context.
343
+ *
344
+ * Returns undefined if not inside an AnimatePresence, or the depth level
345
+ * where 0 means direct child of AnimatePresence.
346
+ *
347
+ * @returns The current depth level (0 for direct children), or undefined if outside AnimatePresence.
348
+ * @example
349
+ * ```ts
350
+ * const depth = getPresenceDepth()
351
+ * if (depth === 0) {
352
+ * // Direct child of AnimatePresence - key prop required
353
+ * }
354
+ * ```
355
+ *
356
+ * Note: Trivial wrapper - ignored for coverage.
357
+ */
358
+ /* c8 ignore next */
359
+ export const getPresenceDepth = () => getContext(PRESENCE_DEPTH_CONTEXT);
360
+ /**
361
+ * Set the presence depth in Svelte component context.
362
+ *
363
+ * AnimatePresence sets this to 0, and each motion element increments it
364
+ * for its descendants so only direct children (depth 0) require keys.
365
+ *
366
+ * @param depth - The nesting depth to set (0 for direct children of AnimatePresence).
367
+ * @returns void
368
+ * @example
369
+ * ```ts
370
+ * // In AnimatePresence component
371
+ * setPresenceDepth(0)
372
+ *
373
+ * // In nested motion element
374
+ * const currentDepth = getPresenceDepth() ?? 0
375
+ * setPresenceDepth(currentDepth + 1)
376
+ * ```
377
+ *
378
+ * Note: Trivial wrapper - ignored for coverage.
379
+ */
380
+ /* c8 ignore next */
381
+ export const setPresenceDepth = (depth) => {
382
+ setContext(PRESENCE_DEPTH_CONTEXT, depth);
383
+ };
334
384
  /**
335
385
  * Hook used by motion elements to participate in presence.
336
386
  * Registers the element and ensures its exit animation runs on teardown.
@@ -1 +1,20 @@
1
- export declare function stringifyStyleObject(obj: Record<string, string | number>): string;
1
+ /**
2
+ * Converts a style object to a CSS style string.
3
+ *
4
+ * @deprecated Use `styleString` from `@humanspeak/svelte-motion` instead for reactive styles.
5
+ * This function is non-reactive and will not update when values change.
6
+ *
7
+ * @param obj - Style object with camelCase keys and string/number values
8
+ * @returns CSS style string with kebab-case properties and appropriate units
9
+ * @example
10
+ * ```ts
11
+ * // Old (deprecated, non-reactive):
12
+ * import { stringifyStyleObject } from '..'
13
+ * const style = stringifyStyleObject({ rotate: 45, opacity: 0.5 })
14
+ *
15
+ * // New (reactive):
16
+ * import { styleString } from '@humanspeak/svelte-motion'
17
+ * const style = styleString(() => ({ rotate, opacity }))
18
+ * ```
19
+ */
20
+ export declare const stringifyStyleObject: (obj: Record<string, string | number>) => string;
@@ -10,15 +10,63 @@ const UNITLESS_PROPERTIES = new Set([
10
10
  'order',
11
11
  'grid-column',
12
12
  'grid-row',
13
- 'column-count'
13
+ 'column-count',
14
+ 'scale',
15
+ 'scale-x',
16
+ 'scale-y',
17
+ 'scale-z'
14
18
  ]);
15
- export function stringifyStyleObject(obj) {
19
+ // CSS properties that need 'deg' unit instead of 'px'
20
+ const DEGREE_PROPERTIES = new Set([
21
+ 'rotate',
22
+ 'rotate-x',
23
+ 'rotate-y',
24
+ 'rotate-z',
25
+ 'skew',
26
+ 'skew-x',
27
+ 'skew-y'
28
+ ]);
29
+ /**
30
+ * Converts a style object to a CSS style string.
31
+ *
32
+ * @deprecated Use `styleString` from `@humanspeak/svelte-motion` instead for reactive styles.
33
+ * This function is non-reactive and will not update when values change.
34
+ *
35
+ * @param obj - Style object with camelCase keys and string/number values
36
+ * @returns CSS style string with kebab-case properties and appropriate units
37
+ * @example
38
+ * ```ts
39
+ * // Old (deprecated, non-reactive):
40
+ * import { stringifyStyleObject } from '..'
41
+ * const style = stringifyStyleObject({ rotate: 45, opacity: 0.5 })
42
+ *
43
+ * // New (reactive):
44
+ * import { styleString } from '@humanspeak/svelte-motion'
45
+ * const style = styleString(() => ({ rotate, opacity }))
46
+ * ```
47
+ */
48
+ export const stringifyStyleObject = (obj) => {
16
49
  return Object.entries(obj)
17
50
  .map(([key, value]) => {
18
51
  const cssKey = key.replace(/([A-Z])/g, '-$1').toLowerCase();
19
52
  const isUnitless = UNITLESS_PROPERTIES.has(cssKey);
20
- const cssValue = typeof value === 'number' && !isUnitless ? `${value}px` : String(value);
53
+ const isDegree = DEGREE_PROPERTIES.has(cssKey);
54
+ let cssValue;
55
+ if (typeof value === 'number') {
56
+ if (isUnitless) {
57
+ cssValue = String(value);
58
+ }
59
+ else if (isDegree) {
60
+ cssValue = `${value}deg`;
61
+ }
62
+ else {
63
+ cssValue = `${value}px`;
64
+ }
65
+ }
66
+ else {
67
+ cssValue = String(value);
68
+ }
21
69
  return `${cssKey}: ${cssValue}`;
22
70
  })
23
71
  .join('; ');
24
- }
72
+ };
@@ -0,0 +1,27 @@
1
+ export type StyleObject = Record<string, string | number>;
2
+ /**
3
+ * Creates a CSS style string from a style object or factory function.
4
+ *
5
+ * In Svelte 5, template expressions are reactive - when you use `$state` variables
6
+ * in a template, the expression re-evaluates when those values change. This means
7
+ * you can use `styleString` directly in templates and it will update reactively.
8
+ *
9
+ * @example
10
+ * ```svelte
11
+ * <script>
12
+ * import { styleString } from '@humanspeak/svelte-motion'
13
+ *
14
+ * let rotate = $state(0)
15
+ * let opacity = $state(1)
16
+ * </script>
17
+ *
18
+ * <!-- Both forms are reactive in Svelte 5 templates -->
19
+ * <div style={styleString({ rotate, opacity })}>Object form</div>
20
+ * <div style={styleString(() => ({ rotate, opacity }))}>Factory form</div>
21
+ * ```
22
+ *
23
+ * @param input - A style object or a function returning a style object
24
+ * @returns A CSS style string
25
+ */
26
+ export declare const styleString: (input: StyleObject | (() => StyleObject)) => string;
27
+ export { stringifyStyleObject } from './styleObject.js';
@@ -0,0 +1,31 @@
1
+ import { stringifyStyleObject } from './styleObject.js';
2
+ /**
3
+ * Creates a CSS style string from a style object or factory function.
4
+ *
5
+ * In Svelte 5, template expressions are reactive - when you use `$state` variables
6
+ * in a template, the expression re-evaluates when those values change. This means
7
+ * you can use `styleString` directly in templates and it will update reactively.
8
+ *
9
+ * @example
10
+ * ```svelte
11
+ * <script>
12
+ * import { styleString } from '@humanspeak/svelte-motion'
13
+ *
14
+ * let rotate = $state(0)
15
+ * let opacity = $state(1)
16
+ * </script>
17
+ *
18
+ * <!-- Both forms are reactive in Svelte 5 templates -->
19
+ * <div style={styleString({ rotate, opacity })}>Object form</div>
20
+ * <div style={styleString(() => ({ rotate, opacity }))}>Factory form</div>
21
+ * ```
22
+ *
23
+ * @param input - A style object or a function returning a style object
24
+ * @returns A CSS style string
25
+ */
26
+ export const styleString = (input) => {
27
+ const obj = typeof input === 'function' ? input() : input;
28
+ return stringifyStyleObject(obj);
29
+ };
30
+ // Re-export the pure function for backwards compatibility
31
+ export { stringifyStyleObject } from './styleObject.js';
@@ -3,6 +3,25 @@
3
3
  * These properties are not standard CSS properties and need to be transformed.
4
4
  */
5
5
  export declare const SVG_PATH_PROPERTIES: Set<string>;
6
+ /**
7
+ * The SVG namespace URI.
8
+ */
9
+ export declare const SVG_NAMESPACE = "http://www.w3.org/2000/svg";
10
+ /**
11
+ * Set of SVG tag names that should be created in the SVG namespace.
12
+ * This list covers all standard SVG elements.
13
+ */
14
+ export declare const SVG_TAGS: Set<string>;
15
+ /**
16
+ * Determines whether the provided tag name is an SVG element tag.
17
+ *
18
+ * @param {string} tag The tag name to test.
19
+ * @returns {boolean} True when the tag is an SVG element.
20
+ * @example
21
+ * isSVGTag('path') // true
22
+ * isSVGTag('div') // false
23
+ */
24
+ export declare const isSVGTag: (tag: string) => boolean;
6
25
  /**
7
26
  * Check if an element is an SVG path element.
8
27
  */
package/dist/utils/svg.js CHANGED
@@ -3,6 +3,89 @@
3
3
  * These properties are not standard CSS properties and need to be transformed.
4
4
  */
5
5
  export const SVG_PATH_PROPERTIES = new Set(['pathLength', 'pathOffset', 'pathSpacing']);
6
+ /**
7
+ * The SVG namespace URI.
8
+ */
9
+ export const SVG_NAMESPACE = 'http://www.w3.org/2000/svg';
10
+ /**
11
+ * Set of SVG tag names that should be created in the SVG namespace.
12
+ * This list covers all standard SVG elements.
13
+ */
14
+ export const SVG_TAGS = new Set([
15
+ 'svg',
16
+ 'animate',
17
+ 'animatemotion',
18
+ 'animatetransform',
19
+ 'circle',
20
+ 'clippath',
21
+ 'defs',
22
+ 'desc',
23
+ 'ellipse',
24
+ 'feblend',
25
+ 'fecolormatrix',
26
+ 'fecomponenttransfer',
27
+ 'fecomposite',
28
+ 'feconvolvematrix',
29
+ 'fediffuselighting',
30
+ 'fedisplacementmap',
31
+ 'fedistantlight',
32
+ 'fedropshadow',
33
+ 'feflood',
34
+ 'fefunca',
35
+ 'fefuncb',
36
+ 'fefuncg',
37
+ 'fefuncr',
38
+ 'fegaussianblur',
39
+ 'feimage',
40
+ 'femerge',
41
+ 'femergenode',
42
+ 'femorphology',
43
+ 'feoffset',
44
+ 'fepointlight',
45
+ 'fespecularlighting',
46
+ 'fespotlight',
47
+ 'fetile',
48
+ 'feturbulence',
49
+ 'filter',
50
+ 'foreignobject',
51
+ 'g',
52
+ 'image',
53
+ 'line',
54
+ 'lineargradient',
55
+ 'marker',
56
+ 'mask',
57
+ 'metadata',
58
+ 'mpath',
59
+ 'path',
60
+ 'pattern',
61
+ 'polygon',
62
+ 'polyline',
63
+ 'radialgradient',
64
+ 'rect',
65
+ 'set',
66
+ 'stop',
67
+ 'switch',
68
+ 'symbol',
69
+ 'text',
70
+ 'textpath',
71
+ 'title',
72
+ 'tref',
73
+ 'tspan',
74
+ 'use',
75
+ 'view'
76
+ ]);
77
+ /**
78
+ * Determines whether the provided tag name is an SVG element tag.
79
+ *
80
+ * @param {string} tag The tag name to test.
81
+ * @returns {boolean} True when the tag is an SVG element.
82
+ * @example
83
+ * isSVGTag('path') // true
84
+ * isSVGTag('div') // false
85
+ */
86
+ export const isSVGTag = (tag) => {
87
+ return SVG_TAGS.has(tag.toLowerCase());
88
+ };
6
89
  /**
7
90
  * Check if an element is an SVG path element.
8
91
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@humanspeak/svelte-motion",
3
- "version": "0.1.16",
3
+ "version": "0.1.17",
4
4
  "description": "A lightweight animation library for Svelte 5 that provides smooth, hardware-accelerated animations. Features include spring physics, custom easing, and fluid transitions. Built on top of the motion library, it offers a simple API for creating complex animations with minimal code. Perfect for interactive UIs, micro-interactions, and engaging user experiences.",
5
5
  "keywords": [
6
6
  "svelte",
@@ -53,8 +53,8 @@
53
53
  }
54
54
  },
55
55
  "dependencies": {
56
- "motion": "^12.29.2",
57
- "motion-dom": "^12.29.2"
56
+ "motion": "^12.31.0",
57
+ "motion-dom": "^12.30.1"
58
58
  },
59
59
  "devDependencies": {
60
60
  "@changesets/cli": "^2.29.8",
@@ -62,7 +62,7 @@
62
62
  "@eslint/js": "^9.39.2",
63
63
  "@playwright/test": "^1.58.1",
64
64
  "@sveltejs/adapter-auto": "^7.0.0",
65
- "@sveltejs/kit": "^2.50.1",
65
+ "@sveltejs/kit": "^2.50.2",
66
66
  "@sveltejs/package": "^2.5.7",
67
67
  "@sveltejs/vite-plugin-svelte": "^6.2.4",
68
68
  "@tailwindcss/aspect-ratio": "^0.4.2",
@@ -72,7 +72,7 @@
72
72
  "@tailwindcss/typography": "^0.5.19",
73
73
  "@testing-library/jest-dom": "^6.9.1",
74
74
  "@testing-library/svelte": "^5.3.1",
75
- "@types/node": "^25.1.0",
75
+ "@types/node": "^25.2.0",
76
76
  "@vitest/coverage-v8": "^4.0.18",
77
77
  "concurrently": "^9.2.1",
78
78
  "eslint": "^9.39.2",
@@ -81,11 +81,11 @@
81
81
  "eslint-plugin-svelte": "3.14.0",
82
82
  "eslint-plugin-unused-imports": "4.3.0",
83
83
  "esm-env": "^1.2.2",
84
- "globals": "^17.2.0",
84
+ "globals": "^17.3.0",
85
85
  "html-tags": "^5.1.0",
86
86
  "html-void-elements": "^3.0.0",
87
87
  "husky": "^9.1.7",
88
- "jsdom": "^27.4.0",
88
+ "jsdom": "^28.0.0",
89
89
  "prettier": "^3.8.1",
90
90
  "prettier-plugin-organize-imports": "^4.3.0",
91
91
  "prettier-plugin-sort-json": "^4.2.0",
@@ -93,7 +93,7 @@
93
93
  "prettier-plugin-tailwindcss": "^0.7.2",
94
94
  "publint": "^0.3.17",
95
95
  "runed": "0.37.1",
96
- "svelte": "^5.49.1",
96
+ "svelte": "^5.49.2",
97
97
  "svelte-check": "^4.3.6",
98
98
  "svg-tags": "^1.0.0",
99
99
  "tailwind-merge": "^3.4.0",