### Stateful Plugin Example Source: https://next.neodrag.dev/docs/solid/plugin/introduction Demonstrates how to create a stateful plugin in Neodrag. This example shows how to initialize state in `setup`, update it during `start`, `drag`, and `end` lifecycle hooks, and log relevant information. ```javascript const statefulPlugin = { name: 'stateful:example', setup(ctx) { return { startTime: null, moveCount: 0, }; }, start(ctx, state, event) { state.startTime = Date.now(); state.moveCount = 0; }, drag(ctx, state, event) { state.moveCount++; console.log(`Move #${state.moveCount}`); }, end(ctx, state, event) { const duration = Date.now() - state.startTime; console.log( `Dragged for ${duration}ms with ${state.moveCount} moves`, ); }, }; ``` -------------------------------- ### Add Debugging Logs to Plugins with JavaScript Source: https://next.neodrag.dev/docs/react/plugin/introduction Provides an example of a debugging plugin that logs messages at various lifecycle stages (setup, shouldStart, start, drag, end). This helps in understanding the flow of plugin execution and inspecting context data. ```javascript const debugPlugin = { name: 'debug:execution', priority: 999, // Run early setup(ctx) { console.log('🔧 Plugin setup'); return {}; }, shouldStart(ctx, state, event) { console.log('🤔 Should start?', event.type); return true; }, start(ctx, state, event) { console.log('🚀 Drag started'); }, drag(ctx, state, event) { console.log('🏃 Dragging:', ctx.offset); }, end(ctx, state, event) { console.log('🛑 Drag ended'); }, }; ``` -------------------------------- ### Basic Neodrag Controls Setup (Vanilla JS) Source: https://next.neodrag.dev/docs/vanilla/plugin/controls This example demonstrates the basic integration of the `controls` plugin with Neodrag in vanilla JavaScript. It initializes a `Draggable` instance and applies controls to specify which elements can initiate dragging and which cannot. ```javascript import { controls, ControlFrom, Draggable } from '@neodrag/vanilla'; const allowElement = document.getElementById('allow-example'); const blockElement = document.getElementById('block-example'); new Draggable(allowElement, [ controls({ allow: ControlFrom.selector('.header') }), ]); new Draggable(blockElement, [ controls({ block: ControlFrom.selector('button') }), ]); ``` -------------------------------- ### Install Neodrag React v3 Source: https://next.neodrag.dev/docs/react/migration/v2-v3 Installs the next version of the Neodrag React library, which includes the v3 plugin-based architecture. This is the first step in migrating your project. ```bash npm install @neodrag/react@next ``` -------------------------------- ### Use a Third-Party Plugin (JavaScript) Source: https://next.neodrag.dev/docs/svelte/plugin/introduction Shows how to install and import a third-party Neodrag plugin and then include it in the `plugins` array when initializing Neodrag. This example uses the `awesomePlugin` with custom options. ```javascript import { awesomePlugin } from 'neodrag-plugin-awesome'; const plugins = [awesomePlugin({ speed: 2, color: 'blue' })]; ``` -------------------------------- ### Real-World Examples Source: https://next.neodrag.dev/docs/vue/plugin/grid Provides practical examples of how the grid plugin can be used in various applications like editors and layout systems. ```APIDOC ## Real-World Examples ### Description See how the `grid` plugin can be applied to create specific UI behaviors in different contexts. ### Usage Examples #### Pixel Art Editor ```javascript // Precise 1px grid for pixel-perfect editing const pixelGrid = [grid([1, 1]), bounds(BoundsFrom.element(canvas))]; ``` #### Card Layout System ```javascript // Cards snap to a 12-column grid system const containerWidth = 1200; const columnWidth = containerWidth / 12; const cardGrid = [ grid([columnWidth, 40]), // 12-column, 40px row height bounds(BoundsFrom.parent()), ]; ``` #### Timeline Editor ```javascript // Timeline with 15-minute intervals const minutesPerPixel = 0.25; // 15 minutes = 60 pixels const timelineGrid = [ grid([60, null]), // 15-minute intervals horizontally bounds(BoundsFrom.element(timelineContainer)), ]; ``` #### Icon Grid Layout ```javascript // Desktop-style icon grid const iconSize = 64; const iconSpacing = 80; const iconGrid = [ grid([iconSpacing, iconSpacing]), bounds(BoundsFrom.viewport({ top: 100, bottom: 50 })), ]; ``` ### Response #### Success Response (200) - N/A - These are code snippets demonstrating usage. #### Response Example N/A ``` -------------------------------- ### Install @neodrag/vanilla Source: https://next.neodrag.dev/docs/vanilla Installs the next version of the @neodrag/vanilla library using npm. This is the first step to using the library in your project. ```bash npm i @neodrag/vanilla@next ``` -------------------------------- ### Neodrag Controls: Dynamic Zone Recomputation Logic Source: https://next.neodrag.dev/docs/solid/plugin/controls Demonstrates how to configure the Neodrag controls plugin to recompute control zones dynamically during different stages of a drag operation. It shows examples for recomputing on every drag event, only at drag start, or during setup and start. ```javascript // Recompute zones on every drag event (for dynamic UIs) controls( { allow: ControlFrom.selector('.handle'), block: ControlFrom.selector('.disabled'), }, (ctx) => ctx.hook === 'drag', ); // Only recompute at drag start (better performance) controls( { allow: ControlFrom.selector('.handle'), }, (ctx) => ctx.hook === 'start', ); // Recompute during setup and start controls( { allow: ControlFrom.selector('.handle'), }, (ctx) => ctx.hook === 'setup' || ctx.hook === 'start', ); ``` -------------------------------- ### Position Plugin Setup Function Source: https://next.neodrag.dev/docs/react/plugin/position Illustrates the `setup` function within the position plugin, showing how it handles initial positioning when not interacting. ```APIDOC ## Position Plugin Setup ### Description This section details the `setup` function of the position plugin, which is responsible for setting the initial or forced position of an element. ### Method `setup(ctx)` ### Parameters #### Path Parameters - **ctx** (object) - The context object provided to the setup function, containing methods like `isInteracting` and `setForcedPosition`, and properties like `offset`. ### Logic 1. Checks if the element is currently being interacted with (`!ctx.isInteracting`). 2. Determines the target `x` and `y` coordinates using `options?.current` or `options?.default`, falling back to `ctx.offset` if not provided. 3. If the determined coordinates differ from the current offset (`ctx.offset.x`, `ctx.offset.y`), it calls `ctx.setForcedPosition(x, y)` to update the element's position. ### Request Example ```javascript setup(ctx) { if (!ctx.isInteracting) { const x = options?.current?.x ?? options?.default?.x ?? ctx.offset.x; const y = options?.current?.y ?? options?.default?.y ?? ctx.offset.y; if (x !== ctx.offset.x || y !== ctx.offset.y) { ctx.setForcedPosition(x, y); } } } ``` ``` -------------------------------- ### Maintain Plugin State with JavaScript Source: https://next.neodrag.dev/docs/react/plugin/introduction Demonstrates how a plugin can maintain its internal state between different lifecycle hooks (setup, start, drag, end). The state object is returned from `setup` and passed to subsequent hooks. ```javascript const statefulPlugin = { name: 'stateful:example', setup(ctx) { return { startTime: null, moveCount: 0, }; }, start(ctx, state, event) { state.startTime = Date.now(); state.moveCount = 0; }, drag(ctx, state, event) { state.moveCount++; console.log(`Move #${state.moveCount}`); }, end(ctx, state, event) { const duration = Date.now() - state.startTime; console.log( `Dragged for ${duration}ms with ${state.moveCount} moves`, ); }, }; ``` -------------------------------- ### Grid Snap Configuration Examples Source: https://next.neodrag.dev/docs/svelte/plugin/grid Provides practical examples of configuring the grid plugin for various real-world scenarios, such as pixel art editors, card layouts, timelines, and icon grids. ```javascript // Precise 1px grid for pixel-perfect editing const pixelGrid = [grid([1, 1]), bounds(BoundsFrom.element(canvas))]; // Cards snap to a 12-column grid system const containerWidth = 1200; const columnWidth = containerWidth / 12; const cardGrid = [ grid([columnWidth, 40]), // 12-column, 40px row height bounds(BoundsFrom.parent()), ]; // Timeline with 15-minute intervals const minutesPerPixel = 0.25; // 15 minutes = 60 pixels const timelineGrid = [ grid([60, null]), // 15-minute intervals horizontally bounds(BoundsFrom.element(timelineContainer)), ]; // Desktop-style icon grid const iconSize = 64; const iconSpacing = 80; const iconGrid = [ grid([iconSpacing, iconSpacing]), bounds(BoundsFrom.viewport({ top: 100, bottom: 50 })), ]; ``` -------------------------------- ### Neodrag Threshold Plugin Configuration Examples Source: https://next.neodrag.dev/docs/solid/plugin/threshold Provides examples of configuring the Neodrag threshold plugin for various use cases, including touch-friendly buttons, clickable cards, precision drawing tools, and long-press drag interactions. These examples showcase different combinations of distance and delay settings. ```javascript // Distinguish between taps and drags on touch devices threshold({ distance: 10, // Allow some finger movement delay: 0, // Start immediately once threshold met }); ``` ```javascript // Prevent accidental drags when clicking links/buttons threshold({ distance: 8, // Require intentional movement delay: 100, // Brief hold period }); ``` ```javascript // High precision for drawing/design apps threshold({ distance: 2, // Very sensitive delay: 0, // Immediate response }); ``` ```javascript // Require long press before dragging (like mobile context menus) threshold({ distance: 5, // Small movement tolerance delay: 500, // Half-second hold required }); ``` -------------------------------- ### Split Pane Resizer Example Source: https://next.neodrag.dev/docs/vue/plugin/axis An example demonstrating the use of the axis plugin for a split pane resizer. ```APIDOC ## Split Pane Resizer ### Description This example shows how to use the axis plugin to create a vertical divider for a horizontal split pane, allowing only horizontal resizing. ### Method JavaScript Configuration with Plugins ### Endpoint N/A (Client-side JavaScript) ### Parameters #### Query Parameters N/A #### Request Body N/A ### Request Example ```javascript // Vertical divider for horizontal split const plugins = [ axis('x'), bounds( BoundsFrom.parent({ left: 100, // Min pane width right: 100, // Min pane width }), ), ]; ``` ### Response #### Success Response (200) N/A (Client-side behavior) #### Response Example N/A ``` -------------------------------- ### Threshold Plugin Configuration Examples Source: https://next.neodrag.dev/docs/react/plugin/threshold Demonstrates various ways to configure the threshold plugin, including setting minimum distance, delay, both, or disabling it entirely. These examples show the core API for controlling drag initiation. ```javascript threshold({ distance: 10 }); // Move 10px before dragging starts threshold({ delay: 200 }); // Wait 200ms before dragging starts threshold({ distance: 5, delay: 100 }); // Both conditions required threshold(null); // Disable threshold completely ``` -------------------------------- ### Use a Third-Party Plugin with JavaScript Source: https://next.neodrag.dev/docs/react/plugin/introduction Illustrates how to install and use a published third-party Neodrag plugin. It shows the npm installation command and how to import and instantiate the plugin with custom options. ```bash npm install neodrag-plugin-awesome ``` ```javascript import { awesomePlugin } from 'neodrag-plugin-awesome'; const plugins = [awesomePlugin({ speed: 2, color: 'blue' })]; ``` -------------------------------- ### Grid Plugin Usage Examples Source: https://next.neodrag.dev/docs/react/plugin/grid Illustrates various ways to use the grid plugin with different size configurations. These examples demonstrate square, rectangular, and single-axis snapping. ```javascript grid([20, 20]) // Square 20px grid grid([50, 30]) // Rectangular 50x30px grid grid([25, null]) // Horizontal snapping only grid([null, 15]) // Vertical snapping only grid([null, null]) // No snapping (effectively disabled) ``` -------------------------------- ### Real-World Grid Examples (JavaScript) Source: https://next.neodrag.dev/docs/vue/plugin/grid Provides examples of using the grid plugin in various real-world scenarios, including pixel art editors, card layout systems, timeline editors, and icon grids. These examples showcase combining grid snapping with other Neodrag features like bounds. ```javascript // Precise 1px grid for pixel-perfect editing const pixelGrid = [grid([1, 1]), bounds(BoundsFrom.element(canvas))]; ``` ```javascript // Cards snap to a 12-column grid system const containerWidth = 1200; const columnWidth = containerWidth / 12; const cardGrid = [ grid([columnWidth, 40]), // 12-column, 40px row height bounds(BoundsFrom.parent()), ]; ``` ```javascript // Timeline with 15-minute intervals const minutesPerPixel = 0.25; // 15 minutes = 60 pixels const timelineGrid = [ grid([60, null]), // 15-minute intervals horizontally bounds(BoundsFrom.element(timelineContainer)), ]; ``` ```javascript // Desktop-style icon grid const iconSize = 64; const iconSpacing = 80; const iconGrid = [ grid([iconSpacing, iconSpacing]), bounds(BoundsFrom.viewport({ top: 100, bottom: 50 })), ]; ``` -------------------------------- ### Install @neodrag/svelte Source: https://next.neodrag.dev/docs/svelte Installs the next version of the @neodrag/svelte package using npm. This is the recommended installation command. ```bash npm i @neodrag/svelte@next ``` -------------------------------- ### Install Neodrag v3 for Solid Source: https://next.neodrag.dev/docs/solid/migration/v2-v3 Installs the next version of Neodrag for Solid.js. This command fetches the latest package from npm. ```bash npm install @neodrag/solid@next ``` -------------------------------- ### Compartment Usage Examples: Good vs. Bad in SolidJS Source: https://next.neodrag.dev/docs/solid/plugin/compartment Provides examples in SolidJS comparing effective and ineffective uses of `createCompartment`. It highlights scenarios for dynamic values versus static configurations and simple booleans. ```javascript // ✅ Good - dynamic values const [userChoice, setUserChoice] = createSignal('x'); const [gridSize, setGridSize] = createSignal(20); const axisComp = createCompartment(() => axis(userChoice())); const gridComp = createCompartment(() => grid([gridSize(), gridSize()]), ); // ❌ Bad - static values const staticComp = createCompartment(() => bounds(BoundsFrom.parent()), ); // ✅ Better - direct usage const staticPlugins = [bounds(BoundsFrom.parent())]; // ❌ Bad - simple boolean const [showGrid, setShowGrid] = createSignal(false); const simpleComp = createCompartment(() => showGrid() ? grid([10, 10]) : null, ); // ✅ Better - direct conditional const plugins = [axis('x'), ...(showGrid() ? [grid([10, 10])] : [])]; ``` -------------------------------- ### Monitoring Drag State Changes with SolidJS Source: https://next.neodrag.dev/docs/solid/plugin/statemarker This SolidJS example demonstrates how to monitor drag state changes and display them as notifications. It uses the `stateMarker` plugin and event listeners to trigger notifications on drag start and end, providing real-time feedback on drag events. ```javascript import { createSignal } from 'solid-js'; import { stateMarker, events, useDraggable, For, } from '@neodrag/solid'; interface Notification { id: number; message: string; timestamp: string; } function StateMonitor() { const [element, setElement] = createSignal( null, ); const [notifications, setNotifications] = createSignal< Notification[] >([]); const addNotification = (message: string) => { const notification = { id: Date.now(), message, timestamp: new Date().toLocaleTimeString(), }; setNotifications((prev) => [...prev, notification]); // Remove after 3 seconds setTimeout(() => { setNotifications((prev) => prev.filter((n) => n.id !== notification.id), ); }, 3000); }; useDraggable(element, [ stateMarker(), events({ onDragStart: () => addNotification('Drag started'), onDragEnd: (data) => { const count = data.rootNode.getAttribute( 'data-neodrag-count', ); addNotification(`Drag ended (Total: ${count})`); }, }), ]); return (
Drag me for notifications
{(notification) => (
{notification.timestamp}: {notification.message}
)}
); } ``` -------------------------------- ### Context-Aware Setup with touch-action and conditional plugins Source: https://next.neodrag.dev/docs/react/plugin/touchaction A context-aware setup that dynamically adjusts touch-action and threshold plugins based on whether the device is in full-screen mode or is a mobile device. This provides a tailored touch experience. ```javascript const isMobile = /Mobi|Android/i.test(navigator.userAgent); const isFullScreen = document.fullscreenElement !== null; const plugins = [ touchAction(isFullScreen ? 'none' : 'manipulation'), isMobile ? threshold({ distance: 10, delay: 100 }) : threshold({ distance: 3, delay: 0 }), ]; ``` -------------------------------- ### Install @neodrag/solid Source: https://next.neodrag.dev/docs/solid Installs the next version of the @neodrag/solid package using npm. This is the first step to using the draggable directive. ```bash npm i @neodrag/solid@next ``` -------------------------------- ### CSS Applied by touch-action plugin Source: https://next.neodrag.dev/docs/react/plugin/touchaction Provides examples of CSS classes and their corresponding `touch-action` property values as applied by the plugin. These examples illustrate how different touch behaviors are controlled. ```css /* Example results */ .draggable { touch-action: manipulation; } .no-gestures { touch-action: none; } .vertical-scroll { touch-action: pan-y; } ``` -------------------------------- ### Install Neodrag v3 Vanilla Package Source: https://next.neodrag.dev/docs/vanilla/migration/v2-v3 Installs the next version of the Neodrag vanilla JavaScript package using npm. This is the first step in migrating to v3. ```bash npm install @neodrag/vanilla@next ``` -------------------------------- ### Install Neodrag v3 Svelte Package Source: https://next.neodrag.dev/docs/svelte/migration/v2-v3 Installs the next version of the Neodrag Svelte package. This is the initial step before migrating to v3's plugin-based API. ```bash npm install @neodrag/svelte@next ``` -------------------------------- ### Install @neodrag/core Source: https://next.neodrag.dev/docs/core Installs the next version of the @neodrag/core package using npm. This is the initial step to integrate the core drag-and-drop functionality into your project. ```bash npm i @neodrag/core@next ``` -------------------------------- ### Vue Compartment Usage Examples (Good vs. Bad) Source: https://next.neodrag.dev/docs/vue/plugin/compartment Provides examples in Vue.js demonstrating when to use compartments for dynamic values and conditional logic, and when to avoid them for static values or simple booleans, favoring direct plugin usage instead. ```vue ``` -------------------------------- ### Manage Plugin State Between Lifecycle Calls (JavaScript) Source: https://next.neodrag.dev/docs/svelte/plugin/introduction Demonstrates how a plugin can maintain and update its internal state across different lifecycle hooks like `setup`, `start`, `drag`, and `end`. The state is initialized in `setup` and modified in subsequent hooks. ```javascript const statefulPlugin = { name: 'stateful:example', setup(ctx) { return { startTime: null, moveCount: 0, }; }, start(ctx, state, event) { state.startTime = Date.now(); state.moveCount = 0; }, drag(ctx, state, event) { state.moveCount++; console.log(`Move #${state.moveCount}`); }, end(ctx, state, event) { const duration = Date.now() - state.startTime; console.log( `Dragged for ${duration}ms with ${state.moveCount} moves` ); }, }; ``` -------------------------------- ### React: Basic Usage - v3 Plugins API Source: https://next.neodrag.dev/docs/react/migration/v2-v3 Shows the basic usage of Neodrag's `useDraggable` hook in v3, utilizing a plugin array for configuration. This example mirrors the v2 example but uses v3 plugins for axis, bounds, grid, and events. ```javascript import { useRef } from 'react'; import { useDraggable, axis, bounds, BoundsFrom, grid, events, } from '@neodrag/react'; function App() { const ref = useRef(null); useDraggable(ref, [ axis('x'), bounds(BoundsFrom.parent()), grid([10, 10]), events({ onDrag: (data) => console.log(data) }), ]); return
Drag me
; } ``` -------------------------------- ### Vue Integration with Neodrag Source: https://next.neodrag.dev/docs/core Provides an example of integrating Neodrag with Vue using the '@neodrag/vue' wrapper. This allows for directive-based usage within Vue templates. Requires installation of '@neodrag/vue@next'. ```javascript npm i @neodrag/vue@next ``` ```html ``` -------------------------------- ### Using a Third-Party Plugin Source: https://next.neodrag.dev/docs/solid/plugin/introduction Illustrates how to install and use a third-party Neodrag plugin. It demonstrates importing the plugin and passing configuration options when initializing it within the Neodrag instance. ```javascript import { awesomePlugin } from 'neodrag-plugin-awesome'; const plugins = [awesomePlugin({ speed: 2, color: 'blue' })]; ``` -------------------------------- ### Vue Event Handling: Neodrag v3 Source: https://next.neodrag.dev/docs/vue/migration/v2-v3 Demonstrates handling drag events in Neodrag v3 using the events plugin. This example logs drag start, drag, and drag end events with their offset properties. ```javascript ``` -------------------------------- ### Vue Event Handling: Neodrag v2 Source: https://next.neodrag.dev/docs/vue/migration/v2-v3 Shows how to handle drag events in Neodrag v2 using the options object. This example logs drag start, drag, and drag end events with their respective offsets. ```javascript ``` -------------------------------- ### Basic Dragging Example: v2 Options vs v3 Plugins (Vanilla JS) Source: https://next.neodrag.dev/docs/vanilla/migration/v2-v3 Demonstrates the difference in basic usage for Neodrag's vanilla JavaScript package between v2 and v3. V2 uses a single options object, while v3 utilizes an array of plugins for configuration. ```javascript import { draggable } from '@neodrag/vanilla'; const element = document.getElementById('drag-me'); const { destroy } = draggable(element, { axis: 'x', bounds: 'parent', grid: [10, 10], onDrag: (data) => console.log(data), }); ``` ```javascript import { Draggable, axis, bounds, BoundsFrom, grid, events, } from '@neodrag/vanilla'; const element = document.getElementById('drag-me'); const instance = new Draggable(element, [ axis('x'), bounds(BoundsFrom.parent()), grid([10, 10]), events({ onDrag: (data) => console.log(data) }), ]); ``` -------------------------------- ### Basic Usage with Bounds Source: https://next.neodrag.dev/docs/vue/plugin/bounds Demonstrates the fundamental use of the `bounds` plugin with `BoundsFrom.viewport()` and `BoundsFrom.parent()`. ```APIDOC ## Basic Usage ### Description This section shows how to apply the `bounds` plugin to restrict draggable elements to the viewport or their parent container. ### Method Use the `v-draggable` directive with the `bounds` plugin configured via `BoundsFrom` utilities. ### Example ```vue ``` ``` -------------------------------- ### Creating a Custom Logger Plugin (Solid) Source: https://next.neodrag.dev/docs/solid/migration/v2-v3 Illustrates how to create a custom plugin for Neodrag using Solid.js. The logger plugin demonstrates the setup, start, drag, and end lifecycle hooks for custom dragging behavior. ```javascript import { useDraggable, unstable_definePlugin } from '@neodrag/solid'; const loggerPlugin = unstable_definePlugin(() => ({ name: 'logger', setup(ctx) { console.log('Drag initialized'); return { startTime: 0 }; }, start(ctx, state, event) { state.startTime = Date.now(); console.log('Drag started'); }, drag(ctx, state, event) { const duration = Date.now() - state.startTime; console.log(`Dragging for ${duration}ms`); }, end(ctx, state, event) { console.log('Drag ended'); }, })); function CustomExample() { const [element, setElement] = createSignal(); useDraggable(element, [loggerPlugin]); return
Custom behavior
; } ``` -------------------------------- ### Initialize Bounds Plugin Source: https://next.neodrag.dev/docs/vue/plugin/bounds Demonstrates basic initialization of the bounds plugin for different boundary types: viewport, parent element, and a specific element. These examples show how to set up constraints for draggable elements. ```javascript bounds(BoundsFrom.viewport()); // Stay in browser window bounds(BoundsFrom.parent()); // Stay in parent element bounds(BoundsFrom.element(el)); // Stay in specific element ``` -------------------------------- ### Neodrag Events Plugin Source: https://next.neodrag.dev/docs/solid/plugin/events The `events` plugin provides callbacks that fire during different phases of dragging. Get notified when dragging starts, during movement, and when it ends - perfect for updating UI state, logging, or triggering animations. ```APIDOC ## POST /events ### Description This endpoint represents the usage of the Neodrag events plugin to listen for drag lifecycle events. ### Method POST ### Endpoint /events ### Parameters #### Query Parameters - **onDragStart** (function) - Optional - Callback function executed when dragging starts. - **onDrag** (function) - Optional - Callback function executed during dragging. - **onDragEnd** (function) - Optional - Callback function executed when dragging ends. ### Request Body This plugin is typically configured via function arguments, not a request body. ### Request Example ```javascript events({ onDragStart: (data) => console.log('Started dragging'), onDrag: (data) => console.log('Moving:', data.offset), onDragEnd: (data) => console.log('Finished dragging'), }); ``` ### Response #### Success Response (200) This plugin does not return a response body directly. Its effects are through the provided callback functions. #### Response Example N/A ``` -------------------------------- ### Monitoring Drag State Changes with Vue Source: https://next.neodrag.dev/docs/vue/plugin/statemarker This Vue.js example demonstrates how to monitor drag state changes using the stateMarker plugin and the events plugin. It displays notifications in real-time as drag operations start and end, providing feedback on drag activity. ```vue ``` -------------------------------- ### Neodrag React: Basic Grid Examples Source: https://next.neodrag.dev/docs/react/plugin/grid Shows how to integrate the Neodrag grid plugin with React components using the `useDraggable` hook. It applies different grid configurations to various elements for demonstration. ```jsx import { useRef } from 'react'; import { grid, useDraggable } from '@neodrag/react'; function GridExamples() { const squareRef = useRef(null); const rectRef = useRef(null); const horizontalRef = useRef(null); const verticalRef = useRef(null); useDraggable(squareRef, [grid([20, 20])]); useDraggable(rectRef, [grid([50, 30])]); useDraggable(horizontalRef, [grid([25, null])]); useDraggable(verticalRef, [grid([null, 20])]); return (
Snaps to 20px squares
Snaps to 50x30px rectangles
Only snaps horizontally
Only snaps vertically
); } ``` -------------------------------- ### React: Basic Usage - v2 Options API Source: https://next.neodrag.dev/docs/react/migration/v2-v3 Illustrates the basic usage of Neodrag's `useDraggable` hook in v2 using an options object for configuration. This example shows how to set axis, bounds, grid, and drag event handlers. ```javascript import { useRef } from 'react'; import { useDraggable } from '@neodrag/react'; function App() { const ref = useRef(null); useDraggable(ref, { axis: 'x', bounds: 'parent', grid: [10, 10], onDrag: (data) => console.log(data), }); return
Drag me
; } ``` -------------------------------- ### Creating a Custom Logger Plugin in Neodrag v3 Source: https://next.neodrag.dev/docs/vanilla/migration/v2-v3 Shows how to create a custom plugin for Neodrag v3 using `unstable_definePlugin`. This example defines a logger plugin that logs drag lifecycle events like initialization, start, drag, and end, demonstrating extensibility. ```javascript import { Draggable, unstable_definePlugin } from '@neodrag/vanilla'; const loggerPlugin = unstable_definePlugin(() => ({ name: 'logger', setup(ctx) { console.log('Drag initialized'); return { startTime: 0 }; }, start(ctx, state, event) { state.startTime = Date.now(); console.log('Drag started'); }, drag(ctx, state, event) { const duration = Date.now() - state.startTime; console.log(`Dragging for ${duration}ms`); }, end(ctx, state, event) { console.log('Drag ended'); }, })); const element = document.getElementById('custom'); const instance = new Draggable(element, [loggerPlugin]); ``` -------------------------------- ### Neodrag Plugin Interface Definition Source: https://next.neodrag.dev/docs/react/plugin/introduction Defines the TypeScript interface for a Neodrag plugin, outlining the available hooks and properties. This includes lifecycle methods like `setup`, `shouldStart`, `start`, `drag`, `end`, and `cleanup`, along with configuration options such as `name`, `priority`, `liveUpdate`, and `cancelable`. ```typescript interface Plugin { name: string; // Unique identifier priority?: number; // Higher = runs earlier (default: 0) liveUpdate?: boolean; // Can update during active drag cancelable?: boolean; // Respects cancellation (default: true) setup?: (ctx) => state; // Initialize plugin shouldStart?: (ctx, state, event) => boolean; // Should dragging begin? start?: (ctx, state, event) => void; // Dragging started drag?: (ctx, state, event) => void; // During dragging end?: (ctx, state, event) => void; // Dragging ended cleanup?: (ctx, state) => void; // Plugin destroyed } ``` -------------------------------- ### Basic Usage Example Source: https://next.neodrag.dev/docs/vue/plugin/axis Demonstrates the basic usage of the axis plugin with Vue's vDraggable directive. ```APIDOC ## Basic Usage ### Description This example shows how to apply the axis plugin to restrict dragging direction. ### Method Vue Directive (`vDraggable`) ### Endpoint N/A (Client-side JavaScript) ### Parameters #### Query Parameters N/A #### Request Body N/A ### Request Example ```javascript ``` ### Response #### Success Response (200) N/A (Client-side behavior) #### Response Example N/A ``` -------------------------------- ### Analytics Integration with stateMarker and SolidJS Source: https://next.neodrag.dev/docs/solid/plugin/statemarker This SolidJS example shows how to integrate drag event data with an analytics service using the `stateMarker` plugin. It captures drag start and end events, sending relevant data such as element ID, drag count, and position to an analytics tracking function. ```javascript import { createSignal } from 'solid-js'; import { stateMarker, events, useDraggable } from '@neodrag/solid'; function AnalyticsExample() { const [element, setElement] = createSignal( null, ); const trackDragAnalytics = (eventName: string, data: any) => { // Send to analytics service analytics.track(eventName, { elementId: data.rootNode.id, dragCount: data.rootNode.getAttribute('data-neodrag-count'), position: data.offset, timestamp: Date.now(), }); }; useDraggable(element, [ stateMarker(), events({ onDragStart: (data) => trackDragAnalytics('drag_started', data), onDragEnd: (data) => trackDragAnalytics('drag_completed', data), }), ]); return
Analytics-tracked element
; } ``` -------------------------------- ### Neodrag: Performance Optimization for Dynamic Controls Source: https://next.neodrag.dev/docs/react/plugin/controls Optimize Neodrag performance when using dynamic control zones by carefully managing when zones are recomputed. Avoid recomputing on every drag event if possible. Prefer recomputing only during 'setup' or 'start' hooks, or use static zones for the best performance. ```javascript // ❌ Expensive - queries DOM on every drag event controls( { allow: ControlFrom.selector('.complex-selector:nth-child(odd)'), }, (ctx) => ctx.hook === 'drag', ); // ✅ Better - cache zones, only recompute when needed controls( { allow: ControlFrom.selector('.handle'), }, (ctx) => { // Only recompute if DOM structure might have changed return ctx.hook === 'setup' || ctx.hook === 'start'; }, ); // ✅ Best - static zones for better performance controls({ allow: ControlFrom.selector('.handle'), }); // Uses default setup-only recomputation ``` -------------------------------- ### Inspect Active Neodrag Instances with JavaScript Source: https://next.neodrag.dev/docs/react/plugin/introduction Demonstrates how to inspect active Neodrag instances using the global `instances` Set. It shows how to log the total number of active instances and iterate through them to view associated elements, plugin names, and context states. ```javascript // Check all active draggable instances console.log('Active draggables:', instances.size); // Inspect specific instance for (const [element, instance] of instances) { console.log('Element:', element); console.log( 'Plugins:', instance.plugins.map((p) => p.name), ); console.log('Current state:', instance.ctx); } ``` -------------------------------- ### Basic Draggable Element Initialization Source: https://next.neodrag.dev/docs/vanilla Demonstrates the basic usage of creating a draggable instance for an HTML element. It requires importing the Draggable class and selecting the target element. ```javascript import { Draggable } from '@neodrag/vanilla'; const dragInstance = new Draggable(document.querySelector('#drag')); ``` -------------------------------- ### stateMarker Plugin Implementation (JavaScript) Source: https://next.neodrag.dev/docs/svelte/plugin/statemarker This snippet shows the simplified internal JavaScript implementation of the stateMarker plugin. It demonstrates how the plugin sets and updates data attributes on the root node during the setup, start, and end phases of a drag operation. It relies on a `setNodeDataset` function and context object for node manipulation. ```javascript setup(ctx) { setNodeDataset(ctx.rootNode, 'neodrag', ''); setNodeDataset(ctx.rootNode, 'neodrag-state', 'idle'); setNodeDataset(ctx.rootNode, 'neodrag-count', '0'); }, start(ctx) { setNodeDataset(ctx.rootNode, 'neodrag-state', 'dragging'); }, end(ctx, state) { setNodeDataset(ctx.rootNode, 'neodrag-state', 'idle'); setNodeDataset(ctx.rootNode, 'neodrag-count', ++state.count); } ``` -------------------------------- ### Neodrag Position Plugin Setup Logic Source: https://next.neodrag.dev/docs/react/plugin/position Illustrates the setup logic for the Neodrag position plugin. It runs when not interacting, uses `setForcedPosition()` to jump to coordinates, checks for actual changes before updating, and prioritizes running before other position-modifying plugins. It also supports live updates during active drags. ```javascript setup(ctx) { if (!ctx.isInteracting) { const x = options?.current?.x ?? options?.default?.x ?? ctx.offset.x; const y = options?.current?.y ?? options?.default?.y ?? ctx.offset.y; if (x !== ctx.offset.x || y !== ctx.offset.y) { ctx.setForcedPosition(x, y); } } } ``` -------------------------------- ### Neodrag: Conditional Control Zones Based on State Source: https://next.neodrag.dev/docs/react/plugin/controls Implement conditional control zones in Neodrag by providing a function to `allow` or `block` properties. This function can dynamically determine which selectors to use based on application state, such as an edit mode. Recomputation can be triggered on specific hooks like 'setup' or 'start'. ```javascript controls( { allow: (root) => { if (isEditMode) { return ControlFrom.selector('.edit-handle')(root); } else { return ControlFrom.selector('.view-handle')(root); } }, }, (ctx) => { // Recompute when mode changes return ctx.hook === 'setup' || ctx.hook === 'start'; }, ); ``` -------------------------------- ### Neodrag Plugin Lifecycle Interface Definition Source: https://next.neodrag.dev/docs/solid/plugin/introduction Defines the TypeScript interface for a Neodrag plugin, outlining the available lifecycle hooks and properties. This includes `name`, `priority`, `liveUpdate`, `cancelable`, and hooks like `setup`, `shouldStart`, `start`, `drag`, `end`, and `cleanup`. The description also details the execution flow of these hooks during a drag operation. ```typescript interface Plugin { name: string; // Unique identifier priority?: number; // Higher = runs earlier (default: 0) liveUpdate?: boolean; // Can update during active drag cancelable?: boolean; // Respects cancellation (default: true) setup?: (ctx) => state; // Initialize plugin shouldStart?: (ctx, state, event) => boolean; // Should dragging begin? start?: (ctx, state, event) => void; // Dragging started drag?: (ctx, state, event) => void; // During dragging end?: (ctx, state, event) => void; // Dragging ended cleanup?: (ctx, state) => void; // Plugin destroyed } /* Execution flow: 1. setup - Plugin initializes, returns state object 2. shouldStart - User pressed down, should we start dragging? 3. start - Dragging begins 4. drag - Called repeatedly while dragging 5. end - User released, dragging stops 6. cleanup - Plugin destroyed (when instance is destroyed) */ ``` -------------------------------- ### Analytics Integration with stateMarker in React Source: https://next.neodrag.dev/docs/react/plugin/statemarker This React example shows how to integrate drag event data with an analytics service using the stateMarker plugin. It defines a `trackDragAnalytics` function that sends drag start and end events, along with relevant data like element ID, drag count, and position, to an external `analytics.track` method. ```javascript import { useRef } from 'react'; import { stateMarker, events, useDraggable } from '@neodrag/react'; function AnalyticsExample() { const ref = useRef(null); const trackDragAnalytics = (eventName: string, data: any) => { // Send to analytics service analytics.track(eventName, { elementId: data.rootNode.id, dragCount: data.rootNode.getAttribute('data-neodrag-count'), position: data.offset, timestamp: Date.now(), }); }; useDraggable(ref, [ stateMarker(), events({ onDragStart: (data) => trackDragAnalytics('drag_started', data), onDragEnd: (data) => trackDragAnalytics('drag_completed', data), }), ]); return
Analytics-tracked element
; } ```