solidjs-motion 0.1.3 → 0.1.5

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.
@@ -31,7 +31,7 @@ import { MotionOptions, MotionStyle } from './types';
31
31
  * AND `splitProps` at runtime break — the type check surfaces the
32
32
  * specific missing key by name.
33
33
  */
34
- export type MotionOptKey = "initial" | "animate" | "exit" | "hover" | "press" | "focus" | "inView" | "inViewOptions" | "drag" | "dragConstraints" | "dragElastic" | "dragMomentum" | "dragTransition" | "dragSnapToOrigin" | "dragControls" | "whileDrag" | "panThreshold" | "variants" | "custom" | "transition" | "onAnimationStart" | "onAnimationComplete" | "onAnimationCancel" | "onUpdate" | "onHoverStart" | "onHoverEnd" | "onPressStart" | "onPress" | "onPressCancel" | "onFocus" | "onBlur" | "onPanStart" | "onPan" | "onPanEnd" | "onViewportEnter" | "onViewportLeave" | "onDragStart" | "onDrag" | "onDragEnd" | "onDragTransitionEnd";
34
+ export type MotionOptKey = "initial" | "animate" | "exit" | "hover" | "press" | "focus" | "inView" | "inViewOptions" | "drag" | "dragConstraints" | "dragElastic" | "dragMomentum" | "dragTransition" | "dragSnapToOrigin" | "dragControls" | "dragListener" | "whileDrag" | "panThreshold" | "variants" | "custom" | "transition" | "onAnimationStart" | "onAnimationComplete" | "onAnimationCancel" | "onUpdate" | "onHoverStart" | "onHoverEnd" | "onPressStart" | "onPress" | "onPressCancel" | "onFocus" | "onBlur" | "onPanStart" | "onPan" | "onPanEnd" | "onViewportEnter" | "onViewportLeave" | "onDragStart" | "onDrag" | "onDragEnd" | "onDragTransitionEnd";
35
35
  /**
36
36
  * Frozen list of `MotionOptKey`s — fed to `splitProps` at every
37
37
  * tag-component render to separate motion options from element
@@ -146,6 +146,20 @@ export type DragOptions = {
146
146
  dragSnapToOrigin?: boolean;
147
147
  /** Imperatively-triggered drag (from createDragControls). */
148
148
  dragControls?: DragControls;
149
+ /**
150
+ * Whether drag listens for its OWN pointerdown events on the element.
151
+ * Defaults to `true`.
152
+ *
153
+ * Set to `false` when drag should only be started externally via a
154
+ * `dragControls.start(event)` call from a different element (typically
155
+ * a "drag handle"). The element itself remains non-draggable from
156
+ * direct pointer interaction — useful for drawers, sheets, and other
157
+ * surfaces where the body must stay scrollable and only a dedicated
158
+ * affordance should commit to a drag.
159
+ *
160
+ * Mirrors motion-react's `dragListener` prop.
161
+ */
162
+ dragListener?: boolean;
149
163
  };
150
164
  export type MotionCallbacks = {
151
165
  onAnimationStart?: () => void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "solidjs-motion",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "An animation library for SolidJS — port of motion/react patterns built on the framework-agnostic motion package",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -75,6 +75,7 @@ export type MotionOptKey =
75
75
  | "dragTransition"
76
76
  | "dragSnapToOrigin"
77
77
  | "dragControls"
78
+ | "dragListener"
78
79
  | "whileDrag"
79
80
  // Pan
80
81
  | "panThreshold"
@@ -132,6 +133,7 @@ export const MOTION_OPT_KEYS: readonly MotionOptKey[] = [
132
133
  "dragTransition",
133
134
  "dragSnapToOrigin",
134
135
  "dragControls",
136
+ "dragListener",
135
137
  "whileDrag",
136
138
  // Pan
137
139
  "panThreshold",
@@ -647,15 +647,26 @@ export function createDrag(
647
647
  // Function-form options so createPan reads `panThreshold` reactively.
648
648
  // Handler references are stable — only the threshold (and the wrapping
649
649
  // object) is recreated per call from createPan.
650
- createPan(
651
- () => el,
652
- () => ({
653
- threshold: getOpts().panThreshold,
654
- onPanStart: handlePanStart,
655
- onPan: handlePan,
656
- onPanEnd: handlePanEnd,
657
- }),
658
- )
650
+ //
651
+ // `dragListener: false` opts out of motion's own pointerdown listener
652
+ // on `el`. Drag becomes external-only — triggered through
653
+ // `dragControls.start(event)` from another element. Pointer
654
+ // interaction on `el` itself stays inert, letting the surface remain
655
+ // scrollable (the canonical case: a drawer body with a dedicated drag
656
+ // handle). One-time read at construction matches motion-react's
657
+ // semantic — toggling `dragListener` reactively is intentionally not
658
+ // supported.
659
+ if (getOpts().dragListener !== false) {
660
+ createPan(
661
+ () => el,
662
+ () => ({
663
+ threshold: getOpts().panThreshold,
664
+ onPanStart: handlePanStart,
665
+ onPan: handlePan,
666
+ onPanEnd: handlePanEnd,
667
+ }),
668
+ )
669
+ }
659
670
 
660
671
  // ---------- External drag (Q9 — createDragControls integration) ----------
661
672
  // When the user wires `dragControls: someControls` into MotionOptions, an
package/src/types.ts CHANGED
@@ -219,6 +219,20 @@ export type DragOptions = {
219
219
  dragSnapToOrigin?: boolean
220
220
  /** Imperatively-triggered drag (from createDragControls). */
221
221
  dragControls?: DragControls
222
+ /**
223
+ * Whether drag listens for its OWN pointerdown events on the element.
224
+ * Defaults to `true`.
225
+ *
226
+ * Set to `false` when drag should only be started externally via a
227
+ * `dragControls.start(event)` call from a different element (typically
228
+ * a "drag handle"). The element itself remains non-draggable from
229
+ * direct pointer interaction — useful for drawers, sheets, and other
230
+ * surfaces where the body must stay scrollable and only a dedicated
231
+ * affordance should commit to a drag.
232
+ *
233
+ * Mirrors motion-react's `dragListener` prop.
234
+ */
235
+ dragListener?: boolean
222
236
  }
223
237
 
224
238
  // ---------------------------------------------------------------------------
@@ -309,9 +309,37 @@ export function useMotion(opts: MotionOptions | (() => MotionOptions)): UseMotio
309
309
  return mergeProps(userProps ?? {}, {
310
310
  get style() {
311
311
  const cleaned = stripStyleEntriesOwnedByRegistry(userProps?.style)
312
- if (renderedOnce) return cleaned
312
+
313
+ // Drag-friendly `touch-action` default for any drag-configured
314
+ // element. Without this, the mobile browser arbitrates the
315
+ // gesture as native scroll/zoom and may fire `pointercancel`
316
+ // before motion's own `touch-action` write (inside
317
+ // handlePanStart) can take effect — which would manifest as
318
+ // either a missed drag or a panEnd dispatched with stale
319
+ // offset data. Setting it at render time, before the browser
320
+ // ever sees a pointer event, closes that race.
321
+ //
322
+ // axis "x" → "pan-y" (browser may still scroll the page
323
+ // vertically), axis "y" → "pan-x", otherwise → "none".
324
+ //
325
+ // Goes FIRST in the spread order so user-supplied
326
+ // `style: { touchAction: "auto" }` overrides this default.
327
+ const dragOpts = getOpts().drag
328
+ const dragTouchAction = dragOpts
329
+ ? dragOpts === "x"
330
+ ? "pan-y"
331
+ : dragOpts === "y"
332
+ ? "pan-x"
333
+ : "none"
334
+ : undefined
335
+
336
+ const baseWithDefaults = dragTouchAction
337
+ ? { "touch-action": dragTouchAction, ...cleaned }
338
+ : cleaned
339
+
340
+ if (renderedOnce) return baseWithDefaults
313
341
  const composed = composeFirstPaintStyle(userProps?.style)
314
- return composed ? { ...cleaned, ...composed } : cleaned
342
+ return composed ? { ...baseWithDefaults, ...composed } : baseWithDefaults
315
343
  },
316
344
  ref: mergeRefs(userProps?.ref, motionRef),
317
345
  ...(wroteFirstPaintStyle ? { "data-motion-hydrated": "" } : {}),