{"_id":"@agallaoui/dnd-core","name":"@agallaoui/dnd-core","dist-tags":{"latest":"1.0.0"},"versions":{"1.0.0":{"name":"@agallaoui/dnd-core","version":"1.0.0","description":"Framework-agnostic drag-and-drop core engine with pointer events","main":"dist/index.js","module":"dist/index.mjs","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"},"./react":{"types":"./dist/react/index.d.ts","import":"./dist/react/index.mjs","require":"./dist/react/index.js"},"./angular":{"types":"./dist/angular/index.d.ts","import":"./dist/angular/index.mjs","require":"./dist/angular/index.js"}},"sideEffects":false,"scripts":{"build":"tsup","dev":"tsup --watch","test":"vitest run","typecheck":"tsc --noEmit","prepublishOnly":"npm run build"},"peerDependencies":{"react":">=17.0.0","react-dom":">=17.0.0"},"peerDependenciesMeta":{"react":{"optional":true},"react-dom":{"optional":true}},"devDependencies":{"@types/react":"^18.2.48","@types/react-dom":"^18.2.18","react":"^18.2.0","react-dom":"^18.2.0","tsup":"^8.0.1","typescript":"^5.3.3","vitest":"^4.0.18"},"keywords":["drag-and-drop","dnd","draggable","droppable","pointer-events","framework-agnostic","react","angular"],"author":{"name":"agallaoui"},"license":"MIT","repository":{"type":"git","url":"git+https://github.com/agallaoui/dnd.git","directory":"packages/dnd-core"},"homepage":"https://github.com/agallaoui/dnd/tree/main/packages/dnd-core","_id":"@agallaoui/dnd-core@1.0.0","gitHead":"bf113d54e5507d192517a839c8d1ea1f758f9d3a","bugs":{"url":"https://github.com/agallaoui/dnd/issues"},"_nodeVersion":"22.18.0","_npmVersion":"10.9.3","dist":{"integrity":"sha512-iKMmCbBhGrHDVtBKkU0/+jrKezzHQV0KWN0iqG+QdsBqrrpiU8ab9aWtn9xNKb54bKFqhTX92aqbYnE+Td6g4Q==","shasum":"8b1a163da28205c73d53f41d4e7b51f753d2174c","tarball":"https://registry.npmjs.org/@agallaoui/dnd-core/-/dnd-core-1.0.0.tgz","fileCount":24,"unpackedSize":160789,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIDlKCYGgQqKr+vNYsFUBqLTolCg6qUb/+uZ7wE4rdvDjAiAKSyS3nLnZWLnUmcneqdxPL3BtVUmyGbQ1JAgbWEVNDw=="}]},"_npmUser":{"name":"agallaoui","email":"achref.gallaoui.dev@gmail.com"},"directories":{},"maintainers":[{"name":"agallaoui","email":"achref.gallaoui.dev@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/dnd-core_1.0.0_1770424342981_0.5099421649116407"},"_hasShrinkwrap":false}},"time":{"created":"2026-02-07T00:32:22.866Z","1.0.0":"2026-02-07T00:32:23.168Z","modified":"2026-02-07T00:32:23.398Z"},"maintainers":[{"name":"agallaoui","email":"achref.gallaoui.dev@gmail.com"}],"description":"Framework-agnostic drag-and-drop core engine with pointer events","homepage":"https://github.com/agallaoui/dnd/tree/main/packages/dnd-core","keywords":["drag-and-drop","dnd","draggable","droppable","pointer-events","framework-agnostic","react","angular"],"repository":{"type":"git","url":"git+https://github.com/agallaoui/dnd.git","directory":"packages/dnd-core"},"author":{"name":"agallaoui"},"bugs":{"url":"https://github.com/agallaoui/dnd/issues"},"license":"MIT","readme":"# @agallaoui/dnd-core\n\nA lightweight, framework-agnostic drag-and-drop engine built on Pointer Events.\n\n## Installation\n\n```bash\nnpm install @agallaoui/dnd-core\n```\n\n## Features\n\n- **Framework Agnostic** - Works with vanilla JS, React, Angular, or any framework\n- **Pointer Events** - Modern unified API for mouse, touch, and stylus\n- **Type Safe** - Full TypeScript support\n- **Tree-shakable** - Import only what you need\n- **Zero Dependencies** - No external runtime dependencies\n- **Extensible** - Built to be extended (see `@agallaoui/board-dnd`)\n\n## Import Paths\n\n| Path | Description |\n|---|---|\n| `@agallaoui/dnd-core` | Core engine (framework-agnostic) |\n| `@agallaoui/dnd-core/react` | React hooks & provider |\n| `@agallaoui/dnd-core/angular` | Angular service base class |\n\n## Usage\n\n### Vanilla JavaScript\n\n```typescript\nimport { createDndEngine } from '@agallaoui/dnd-core';\n\nconst engine = createDndEngine({\n  dragThreshold: 5,\n  callbacks: {\n    onDragStart: ({ item, position }) => {\n      console.log(`Started dragging ${item.id}`);\n    },\n    onDragOver: ({ item, dropZone }) => {\n      console.log(`${item.id} over ${dropZone.id}`);\n    },\n    onDrop: ({ item, dropZone }) => {\n      // Handle your state update\n    },\n    onDragEnd: ({ item, dropped }) => {\n      console.log(`Drag ended, dropped: ${dropped}`);\n    }\n  }\n});\n\n// Register a draggable element\nconst dragHandle = engine.registerDraggable(element, {\n  id: 'card-1',\n  type: 'card',\n  payload: { title: 'My Task' }\n});\n\n// Register a drop zone\nconst dropHandle = engine.registerDroppable(element, {\n  id: 'column-1',\n  accepts: ['card'],\n  payload: { name: 'Todo' }\n});\n\n// Subscribe to state changes\nconst unsubscribe = engine.subscribe((state) => {\n  // state.phase: 'idle' | 'dragging' | 'dropping'\n});\n\n// Cleanup\ndragHandle.destroy();\ndropHandle.destroy();\nengine.destroy();\n```\n\n### React\n\n```tsx\nimport {\n  DndProvider,\n  useDraggable,\n  useDroppable,\n  useDndState\n} from '@agallaoui/dnd-core/react';\n\nfunction DraggableCard({ id, data }) {\n  const { ref, isDragging } = useDraggable({\n    id,\n    type: 'card',\n    payload: data,\n  });\n\n  return (\n    <div ref={ref} style={{ opacity: isDragging ? 0.5 : 1 }}>\n      {data.title}\n    </div>\n  );\n}\n\nfunction DropZone({ id, children }) {\n  const { ref, isOver } = useDroppable({\n    id,\n    accepts: ['card'],\n  });\n\n  return (\n    <div ref={ref} className={isOver ? 'highlight' : ''}>\n      {children}\n    </div>\n  );\n}\n\nfunction App() {\n  return (\n    <DndProvider onDrop={handleDrop}>\n      <DropZone id=\"zone-1\">\n        <DraggableCard id=\"card-1\" data={{ title: 'Task' }} />\n      </DropZone>\n    </DndProvider>\n  );\n}\n```\n\n### Angular\n\n```typescript\nimport { Injectable, OnDestroy } from '@angular/core';\nimport { DndServiceBase } from '@agallaoui/dnd-core/angular';\n\n@Injectable({ providedIn: 'root' })\nexport class DndService extends DndServiceBase implements OnDestroy {\n  constructor() {\n    super({\n      callbacks: {\n        onDrop: (event) => this.handleDrop(event)\n      }\n    });\n  }\n\n  ngOnDestroy() {\n    this.destroy();\n  }\n}\n```\n\n## API Reference\n\n### `createDndEngine(config?)`\n\n| Option | Type | Default | Description |\n|---|---|---|---|\n| `dragThreshold` | `number` | `5` | Pixels before drag starts |\n| `capturePointer` | `boolean` | `true` | Capture pointer events during drag |\n| `draggingBodyClass` | `string` | `'dnd-dragging'` | CSS class on body during drag |\n| `callbacks` | `DndCallbacks` | `{}` | Lifecycle callbacks |\n\n### Engine Methods\n\n| Method | Description |\n|---|---|\n| `registerDraggable(el, options)` | Register draggable element |\n| `registerDroppable(el, options)` | Register drop zone |\n| `getState()` | Get current DnD state |\n| `subscribe(callback)` | Subscribe to state changes |\n| `cancel()` | Cancel current drag |\n| `destroy()` | Clean up all resources |\n\n### Callbacks\n\n```typescript\ninterface DndCallbacks {\n  onDragStart?: (event: DragStartEvent) => void;\n  onDragOver?: (event: DragOverEvent) => void;\n  onDragLeave?: (dropZone: DropZoneData) => void;\n  onDrop?: (event: DropEvent) => void;\n  onDragEnd?: (event: DragEndEvent) => void;\n}\n```\n\n## Bundle Size\n\n| Import | Size (minified + gzip) |\n|---|---|\n| Core only | ~2.5kb |\n| + React adapter | ~3.5kb |\n| + Angular adapter | ~3.2kb |\n\n## License\n\nMIT\n","readmeFilename":"README.md","_rev":"1-fcf38ada1d7084cecbf6cf4c24e1fdee"}