SolidJSS
SolidJSโ€ข11mo agoโ€ข
4 replies
Puru

useDraggable how to make second argument reactive

I am building a draggable library neodrag v3, writing the solidJS adapter for it.

I want the usage to look like this:
useDraggable(draggableRef, [
        positionPlugin({ current: position() }),
        events({
            onDrag({ offset }) {
                console.log(1);
                setPosition({ x: offset.x, y: offset.y });
            },
        }),
    ]);


I am expecting that when position() is updated, the entire second argument to useDraggable is recreated, and my logic can then call update cycle on it.

But that does not happen! Here is my internal code:

import { createDraggable } from '@neodrag/core';
import { DragEventData, unstable_definePlugin, type Plugin } from '@neodrag/core/plugins';
import { createSignal, onCleanup, onMount, createEffect, untrack } from 'solid-js';
import type { Accessor, Setter } from 'solid-js';

const draggable_factory = createDraggable();

interface DragState extends DragEventData {
    isDragging: boolean;
}

const default_drag_state: DragState = {
    offset: { x: 0, y: 0 },
    rootNode: null as unknown as HTMLElement,
    currentNode: null as unknown as HTMLElement,
    isDragging: false,
};

// Create the state sync plugin with the provided setter function
const state_sync = unstable_definePlugin<[Setter<DragState>]>({
    // Ommitted for brevity
});

type PluginOrFactory = Plugin | (() => Plugin);

function resolve_plugin(pluginOrFactory: PluginOrFactory): Plugin {
    return typeof pluginOrFactory === 'function' ? pluginOrFactory() : pluginOrFactory;
}

export function wrapper(draggableFactory: ReturnType<typeof createDraggable>) {
    return (
        element: Accessor<HTMLElement | SVGElement | null | undefined>,
        plugins: PluginOrFactory[] = [],
    ) => {
        const [drag_state, set_drag_state] = createSignal<DragState>(default_drag_state);
        let instance: ReturnType<typeof draggableFactory.draggable> | undefined;
        const state_sync_plugin = state_sync(set_drag_state);

        // Initialize draggable instance
        onMount(() => {
            const node = element();
            if (!node) return;

            // Initial plugin resolution
            const resolved_plugins = untrack(() => plugins.map(resolve_plugin).concat(state_sync_plugin));

            instance = draggableFactory.draggable(node, resolved_plugins);

            // Cleanup on unmount
            onCleanup(() => {
                instance?.destroy();
            });
        });

        // Handle plugin updates
        createEffect(() => {
            if (!instance) return;

            // Resolve all plugins, including reactive ones
            const resolved_plugins = plugins.map(resolve_plugin).concat(state_sync_plugin);

            instance.update(resolved_plugins);
        });

        return drag_state;
    };
}

export const useDraggable = wrapper(draggable_factory);

// Export necessary types and utilities
export * from '@neodrag/core/plugins';
export const instances = draggable_factory.instances;


What could be going wrong here?
Was this page helpful?