[
  {
    "path": ".browserslistrc",
    "content": "defaults\nlast 2 version\nnot IE 11\nnot dead\n"
  },
  {
    "path": ".changeset/README.md",
    "content": "# Changesets\n\nHello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works\nwith multi-package repos, or single-package repos to help you version and publish your code. You can\nfind the full documentation for it [in our repository](https://github.com/changesets/changesets)\n\nWe have a quick list of common questions to get you started engaging with this project in\n[our documentation](https://github.com/changesets/changesets/blob/master/docs/common-questions.md)\n"
  },
  {
    "path": ".changeset/animation-last-wins.md",
    "content": "---\n'@dnd-kit/dom': patch\n---\n\nAnimation resolution now uses last-wins semantics matching CSS composite order. `getFinalKeyframe` returns the last matching keyframe across all running animations instead of short-circuiting on the first match. `getProjectedTransform` collects the latest value per CSS property (`transform`, `translate`, `scale`) rather than accumulating transforms additively.\n"
  },
  {
    "path": ".changeset/autoscroller-options.md",
    "content": "---\n'@dnd-kit/dom': minor\n---\n\nAdd `acceleration` and `threshold` options to the `AutoScroller` plugin.\n\n- `acceleration` controls the base scroll speed multiplier (default: `25`).\n- `threshold` controls the percentage of container dimensions that defines the scroll activation zone (default: `0.2`). Accepts a single number for both axes or `{ x, y }` for per-axis control. Setting an axis to `0` disables auto-scrolling on that axis.\n\n```ts\nAutoScroller.configure({\n  acceleration: 15,\n  threshold: { x: 0, y: 0.3 },\n})\n```\n"
  },
  {
    "path": ".changeset/config.json",
    "content": "{\n  \"$schema\": \"https://unpkg.com/@changesets/config@1.5.0/schema.json\",\n  \"changelog\": [\"@changesets/changelog-github\", {\"repo\": \"clauderic/dnd-kit\"}],\n  \"commit\": false,\n  \"fixed\": [\n    [\n      \"@dnd-kit/abstract\",\n      \"@dnd-kit/collision\",\n      \"@dnd-kit/dom\",\n      \"@dnd-kit/geometry\",\n      \"@dnd-kit/helpers\",\n      \"@dnd-kit/react\",\n      \"@dnd-kit/state\",\n      \"@dnd-kit/vue\",\n      \"@dnd-kit/solid\",\n      \"@dnd-kit/svelte\"\n    ]\n  ],\n  \"access\": \"public\",\n  \"baseBranch\": \"experimental\",\n  \"updateInternalDependencies\": \"patch\",\n  \"ignore\": [],\n  \"snapshot\": {\n    \"useCalculatedVersion\": true\n  }\n}\n"
  },
  {
    "path": ".changeset/drop-animation-source-context.md",
    "content": "---\n'@dnd-kit/dom': minor\n---\n\nThe `DropAnimationFunction` context now includes `source`, providing access to the draggable entity for conditional animation logic.\n\n```tsx\nFeedback.configure({\n  dropAnimation: async (context) => {\n    if (context.source.type === 'service-draggable') return;\n    // custom animation...\n  },\n});\n```\n"
  },
  {
    "path": ".changeset/entity-batched-id-changes.md",
    "content": "---\n'@dnd-kit/abstract': minor\n'@dnd-kit/dom': minor\n---\n\nBatch entity identity changes to prevent collision oscillation during virtualized sorting.\n\nWhen entities swap ids (e.g. as `react-window` recycles DOM nodes during a drag), multiple registry updates could fire in an interleaved order, causing the collision detector to momentarily see stale or duplicate entries and oscillate between targets.\n\nEntity `id` changes are now deferred to a microtask and flushed atomically in a single `batch()`, ensuring:\n- The collision notifier skips detection while id changes are pending\n- The registry cleans up ghost registrations (stale keys left behind after an id swap)\n"
  },
  {
    "path": ".changeset/feedback-keyboard-transition.md",
    "content": "---\n'@dnd-kit/dom': minor\n---\n\nAdd `keyboardTransition` option to the `Feedback` plugin for customizing or disabling the CSS transition applied when moving elements via keyboard.\n\nBy default, keyboard-driven moves animate with `250ms cubic-bezier(0.25, 1, 0.5, 1)`. You can now customize the `duration` and `easing`, or set the option to `null` to disable the transition entirely.\n\n```ts\nFeedback.configure({\n  keyboardTransition: { duration: 150, easing: 'ease-out' },\n})\n```\n"
  },
  {
    "path": ".changeset/feedback-placeholder-sibling-reorder.md",
    "content": "---\n'@dnd-kit/dom': patch\n---\n\nFix Feedback plugin placeholder not repositioning when siblings are moved around a stationary source element.\n\nWhen a VDOM framework (e.g., Preact, Vue) reorders sibling elements during a drag operation, the source element and placeholder may remain in the DOM but no longer be adjacent. The existing `documentMutationObserver` only handled cases where the source or placeholder itself was re-added to the DOM. This adds a fallback adjacency check after processing all mutation entries, ensuring the placeholder stays next to the source element regardless of how siblings are rearranged.\n"
  },
  {
    "path": ".changeset/feedback-transform-support.md",
    "content": "---\n'@dnd-kit/dom': minor\n---\n\nThe Feedback plugin now supports full CSS `transform` property for compatibility with libraries like react-window v2 that position elements via transforms. Transform-related CSS transitions are filtered out to prevent conflicts with Feedback-managed properties. The ResizeObserver computes shapes from CSS values rather than re-measuring the element, avoiding mid-transition measurement errors. Sortable's `animate()` cancels CSS transitions on transform-related properties before measuring to ensure correct FLIP deltas.\n"
  },
  {
    "path": ".changeset/fix-event-type-aliases.md",
    "content": "---\n'@dnd-kit/abstract': minor\n'@dnd-kit/dom': minor\n'@dnd-kit/helpers': minor\n'@dnd-kit/react': minor\n'@dnd-kit/solid': minor\n'@dnd-kit/vue': minor\n'@dnd-kit/svelte': minor\n---\n\nRedesign event type system to follow the DOM EventMap pattern. Introduces `DragDropEventMap` for event object types and `DragDropEventHandlers` for event handler signatures, replacing the ambiguously named `DragDropEvents`. Event type aliases (`CollisionEvent`, `DragStartEvent`, etc.) now derive directly from `DragDropEventMap` rather than using `Parameters<>` extraction.\n\n### Migration guide\n\n- **`DragDropEvents`** has been split into two types:\n  - `DragDropEventMap` — maps event names to event object types (like `WindowEventMap`)\n  - `DragDropEventHandlers` — maps event names to `(event, manager) => void` handler signatures\n- If you were importing `DragDropEvents` to type **event objects**, use `DragDropEventMap` instead:\n  ```ts\n  // Before\n  type MyEvent = Parameters<DragDropEvents<D, P, M>['dragend']>[0];\n  // After\n  type MyEvent = DragDropEventMap<D, P, M>['dragend'];\n  ```\n- If you were importing `DragDropEvents` to type **event handlers**, use `DragDropEventHandlers` instead:\n  ```ts\n  // Before\n  const handler: DragDropEvents<D, P, M>['dragend'] = (event, manager) => {};\n  // After\n  const handler: DragDropEventHandlers<D, P, M>['dragend'] = (event, manager) => {};\n  ```\n- The `DragDropEvents` re-export from `@dnd-kit/react` and `@dnd-kit/solid` has been removed. Import `DragDropEventMap` or `DragDropEventHandlers` from `@dnd-kit/abstract` directly if needed.\n- Convenience aliases (`CollisionEvent`, `DragStartEvent`, `DragEndEvent`, etc.) are unchanged and continue to work as before.\n"
  },
  {
    "path": ".changeset/fix-plugin-registry-dedup-ordering.md",
    "content": "---\n'@dnd-kit/abstract': patch\n---\n\nFixed plugin registration order when deduplicating configured plugins.\n\nWhen a plugin was provided via `Plugin.configure()` alongside an internally-registered instance of the same plugin, the dedup logic would reorder it to the end of the registration list. This broke plugins like `Feedback` that resolve `StyleInjector` from the registry during construction, since `StyleInjector` would not yet be registered.\n\nThis also prevented users from configuring `StyleInjector` with a CSP `nonce` without breaking drag feedback:\n\n```ts\nplugins: (defaults) => [...defaults, StyleInjector.configure({ nonce: 'abc123' })]\n```\n"
  },
  {
    "path": ".changeset/fix-pointer-sensor-stale-activation.md",
    "content": "---\n'@dnd-kit/dom': patch\n---\n\nFixed `setPointerCapture` error on touch devices caused by stale pointer activation.\n\nWhen a touch was released during the activation delay and followed by a quick re-touch, the pending delay timer from the first touch could fire with a stale `pointerId`, causing `setPointerCapture` to throw. The `PointerSensor` now properly aborts the activation controller during cleanup to cancel pending delay timers, and defensively handles `setPointerCapture` failures.\n"
  },
  {
    "path": ".changeset/per-entity-plugin-config.md",
    "content": "---\n'@dnd-kit/abstract': minor\n'@dnd-kit/dom': minor\n'@dnd-kit/react': minor\n'@dnd-kit/solid': minor\n'@dnd-kit/vue': minor\n'@dnd-kit/svelte': minor\n---\n\nAdded per-entity plugin configuration and moved `feedback` from the Draggable entity to the Feedback plugin.\n\nDraggable entities now accept a `plugins` property for per-entity plugin configuration, using the existing `Plugin.configure()` pattern. Plugins can read per-entity options via `source.pluginConfig(PluginClass)`.\n\nThe `feedback` property (`'default' | 'move' | 'clone' | 'none'`) has been moved from the Draggable entity to `FeedbackOptions`. Drop animation can also now be configured per-draggable.\n\nPlugins listed in an entity's `plugins` array are auto-registered on the manager if not already present. The Sortable class now uses this generic mechanism instead of its own custom registration logic.\n\n### Migration guide\n\nThe `feedback` property has been moved from the draggable/sortable hook input to per-entity Feedback plugin configuration.\n\n**Before:**\n\n```tsx\nimport { FeedbackType } from '@dnd-kit/dom';\n\nuseDraggable({ id: 'item', feedback: 'clone' });\nuseSortable({ id: 'item', index: 0, feedback: 'clone' });\n```\n\n**After:**\n\n```tsx\nimport { Feedback } from '@dnd-kit/dom';\n\nuseDraggable({\n  id: 'item',\n  plugins: [Feedback.configure({ feedback: 'clone' })],\n});\nuseSortable({\n  id: 'item',\n  index: 0,\n  plugins: [Feedback.configure({ feedback: 'clone' })],\n});\n```\n\nDrop animation can now be configured per-draggable:\n\n```tsx\nuseDraggable({\n  id: 'item',\n  plugins: [Feedback.configure({ feedback: 'clone', dropAnimation: null })],\n});\n```\n"
  },
  {
    "path": ".changeset/refactor-style-injector.md",
    "content": "---\n'@dnd-kit/dom': minor\n---\n\nRenamed `StyleSheetManager` to `StyleInjector` and centralized CSP `nonce` configuration.\n\nThe `StyleInjector` plugin now accepts a `nonce` option that is applied to all injected `<style>` elements. The `nonce` options have been removed from the `Cursor`, `PreventSelection`, and `Feedback` plugin options.\n\nBefore:\n\n```ts\nconst manager = new DragDropManager({\n  plugins: (defaults) => [\n    ...defaults,\n    Cursor.configure({ nonce: 'abc123' }),\n    PreventSelection.configure({ nonce: 'abc123' }),\n  ],\n});\n```\n\nAfter:\n\n```ts\nconst manager = new DragDropManager({\n  plugins: (defaults) => [\n    ...defaults,\n    StyleInjector.configure({ nonce: 'abc123' }),\n  ],\n});\n```\n\nThe `Cursor` and `PreventSelection` plugins now route their style injection through the `StyleInjector`, so all injected styles respect the centralized `nonce` configuration.\n"
  },
  {
    "path": ".changeset/scroll-into-view-rewrite.md",
    "content": "---\n'@dnd-kit/dom': patch\n---\n\nRewrite `scrollIntoViewIfNeeded` with manual scroll calculations for more predictable behavior in nested scroll containers.\n"
  },
  {
    "path": ".changeset/thick-cloths-poke.md",
    "content": "---\n'@dnd-kit/abstract': patch\n---\n\nInfer type of source.data object from type argument\n"
  },
  {
    "path": ".changeset/use-deep-signal-flush-sync.md",
    "content": "---\n'@dnd-kit/react': patch\n---\n\nFix `useDeepSignal` calling `flushSync` from within a React lifecycle method.\n\nWhen signal updates are triggered synchronously from a React effect (e.g. during a `useEffect` batch), calling `flushSync` directly violates React's internal invariant. The synchronous re-render is now deferred to a microtask via `queueMicrotask`, which runs after the current React batch completes but before the next paint.\n"
  },
  {
    "path": ".changeset/whole-cloths-warn.md",
    "content": "---\n'@dnd-kit/dom': patch\n---\n\nrecalculate AutoScroller options in the effect to avoid stale data\n"
  },
  {
    "path": ".eslintrc.js",
    "content": "module.exports = {\n  extends: [\n    'react-app',\n    'prettier/@typescript-eslint',\n    'plugin:prettier/recommended',\n  ],\n};\n"
  },
  {
    "path": ".github/FUNDING.yml",
    "content": "# These are supported funding model platforms\n\ngithub: [clauderic]\n"
  },
  {
    "path": ".github/workflows/chromatic.yml",
    "content": "name: 'Chromatic'\n\non:\n  pull_request:\n  push:\n    branches: [main]\n\njobs:\n  chromatic-vanilla:\n    name: Chromatic (Vanilla)\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          fetch-depth: 0\n      - uses: oven-sh/setup-bun@v1\n      - run: bun install && bun run build\n\n      - name: Check for Chromatic token\n        id: check\n        run: |\n          if [ -n \"$TOKEN\" ]; then\n            echo \"has-token=true\" >> \"$GITHUB_OUTPUT\"\n          else\n            echo \"has-token=false\" >> \"$GITHUB_OUTPUT\"\n          fi\n        env:\n          TOKEN: ${{ secrets.CHROMATIC_VANILLA_TOKEN }}\n\n      - name: Publish to Chromatic\n        if: steps.check.outputs.has-token == 'true'\n        uses: chromaui/action@v15\n        id: vanilla\n        with:\n          token: ${{ secrets.GITHUB_TOKEN }}\n          projectToken: ${{ secrets.CHROMATIC_VANILLA_TOKEN }}\n          buildScriptName: 'build'\n          workingDir: 'apps/stories-vanilla'\n\n      - name: Build Storybook (fork fallback)\n        if: steps.check.outputs.has-token == 'false'\n        working-directory: apps/stories-vanilla\n        run: bun run build\n\n      - name: Upload Storybook artifact\n        if: steps.check.outputs.has-token == 'false'\n        uses: actions/upload-artifact@v4\n        with:\n          name: storybook-vanilla\n          path: apps/stories-vanilla/storybook-static\n          retention-days: 30\n\n    outputs:\n      storybookUrl: ${{ steps.vanilla.outputs.storybookUrl }}\n      has-token: ${{ steps.check.outputs.has-token }}\n\n  chromatic-vue:\n    name: Chromatic (Vue)\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          fetch-depth: 0\n      - uses: oven-sh/setup-bun@v1\n      - run: bun install && bun run build\n\n      - name: Check for Chromatic token\n        id: check\n        run: |\n          if [ -n \"$TOKEN\" ]; then\n            echo \"has-token=true\" >> \"$GITHUB_OUTPUT\"\n          else\n            echo \"has-token=false\" >> \"$GITHUB_OUTPUT\"\n          fi\n        env:\n          TOKEN: ${{ secrets.CHROMATIC_VUE_TOKEN }}\n\n      - name: Publish to Chromatic\n        if: steps.check.outputs.has-token == 'true'\n        uses: chromaui/action@v15\n        id: vue\n        with:\n          token: ${{ secrets.GITHUB_TOKEN }}\n          projectToken: ${{ secrets.CHROMATIC_VUE_TOKEN }}\n          buildScriptName: 'build'\n          workingDir: 'apps/stories-vue'\n\n      - name: Build Storybook (fork fallback)\n        if: steps.check.outputs.has-token == 'false'\n        working-directory: apps/stories-vue\n        run: bun run build\n\n      - name: Upload Storybook artifact\n        if: steps.check.outputs.has-token == 'false'\n        uses: actions/upload-artifact@v4\n        with:\n          name: storybook-vue\n          path: apps/stories-vue/storybook-static\n          retention-days: 30\n\n    outputs:\n      storybookUrl: ${{ steps.vue.outputs.storybookUrl }}\n      has-token: ${{ steps.check.outputs.has-token }}\n\n  chromatic-solid:\n    name: Chromatic (Solid)\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          fetch-depth: 0\n      - uses: oven-sh/setup-bun@v1\n      - run: bun install && bun run build\n\n      - name: Check for Chromatic token\n        id: check\n        run: |\n          if [ -n \"$TOKEN\" ]; then\n            echo \"has-token=true\" >> \"$GITHUB_OUTPUT\"\n          else\n            echo \"has-token=false\" >> \"$GITHUB_OUTPUT\"\n          fi\n        env:\n          TOKEN: ${{ secrets.CHROMATIC_SOLID_TOKEN }}\n\n      - name: Publish to Chromatic\n        if: steps.check.outputs.has-token == 'true'\n        uses: chromaui/action@v15\n        id: solid\n        with:\n          token: ${{ secrets.GITHUB_TOKEN }}\n          projectToken: ${{ secrets.CHROMATIC_SOLID_TOKEN }}\n          buildScriptName: 'build'\n          workingDir: 'apps/stories-solid'\n\n      - name: Build Storybook (fork fallback)\n        if: steps.check.outputs.has-token == 'false'\n        working-directory: apps/stories-solid\n        run: bun run build\n\n      - name: Upload Storybook artifact\n        if: steps.check.outputs.has-token == 'false'\n        uses: actions/upload-artifact@v4\n        with:\n          name: storybook-solid\n          path: apps/stories-solid/storybook-static\n          retention-days: 30\n\n    outputs:\n      storybookUrl: ${{ steps.solid.outputs.storybookUrl }}\n      has-token: ${{ steps.check.outputs.has-token }}\n\n  chromatic-svelte:\n    name: Chromatic (Svelte)\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          fetch-depth: 0\n      - uses: oven-sh/setup-bun@v1\n      - run: bun install && bun run build\n\n      - name: Check for Chromatic token\n        id: check\n        run: |\n          if [ -n \"$TOKEN\" ]; then\n            echo \"has-token=true\" >> \"$GITHUB_OUTPUT\"\n          else\n            echo \"has-token=false\" >> \"$GITHUB_OUTPUT\"\n          fi\n        env:\n          TOKEN: ${{ secrets.CHROMATIC_SVELTE_TOKEN }}\n\n      - name: Publish to Chromatic\n        if: steps.check.outputs.has-token == 'true'\n        uses: chromaui/action@v15\n        id: svelte\n        with:\n          token: ${{ secrets.GITHUB_TOKEN }}\n          projectToken: ${{ secrets.CHROMATIC_SVELTE_TOKEN }}\n          buildScriptName: 'build'\n          workingDir: 'apps/stories-svelte'\n\n      - name: Build Storybook (fork fallback)\n        if: steps.check.outputs.has-token == 'false'\n        working-directory: apps/stories-svelte\n        run: bun run build\n\n      - name: Upload Storybook artifact\n        if: steps.check.outputs.has-token == 'false'\n        uses: actions/upload-artifact@v4\n        with:\n          name: storybook-svelte\n          path: apps/stories-svelte/storybook-static\n          retention-days: 30\n\n    outputs:\n      storybookUrl: ${{ steps.svelte.outputs.storybookUrl }}\n      has-token: ${{ steps.check.outputs.has-token }}\n\n  chromatic:\n    name: Chromatic\n    runs-on: ubuntu-latest\n    needs:\n      - chromatic-vanilla\n      - chromatic-vue\n      - chromatic-solid\n      - chromatic-svelte\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          fetch-depth: 0\n      - uses: oven-sh/setup-bun@v1\n      - run: bun install && bun run build\n\n      - name: Check for Chromatic token\n        id: check\n        run: |\n          if [ -n \"$TOKEN\" ]; then\n            echo \"has-token=true\" >> \"$GITHUB_OUTPUT\"\n          else\n            echo \"has-token=false\" >> \"$GITHUB_OUTPUT\"\n          fi\n        env:\n          TOKEN: ${{ secrets.CHROMATIC_TOKEN }}\n\n      - name: Publish to Chromatic\n        if: steps.check.outputs.has-token == 'true'\n        uses: chromaui/action@v15\n        with:\n          token: ${{ secrets.GITHUB_TOKEN }}\n          projectToken: ${{ secrets.CHROMATIC_TOKEN }}\n          buildScriptName: 'build'\n          workingDir: 'apps/stories'\n        env:\n          VANILLA_STORYBOOK_URL: ${{ needs.chromatic-vanilla.outputs.storybookUrl }}\n          VUE_STORYBOOK_URL: ${{ needs.chromatic-vue.outputs.storybookUrl }}\n          SOLID_STORYBOOK_URL: ${{ needs.chromatic-solid.outputs.storybookUrl }}\n          SVELTE_STORYBOOK_URL: ${{ needs.chromatic-svelte.outputs.storybookUrl }}\n\n      - name: Build Storybook (fork fallback)\n        if: steps.check.outputs.has-token == 'false'\n        working-directory: apps/stories\n        run: bun run build\n\n      - name: Upload Storybook artifact\n        if: steps.check.outputs.has-token == 'false'\n        uses: actions/upload-artifact@v4\n        with:\n          name: storybook-react\n          path: apps/stories/storybook-static\n          retention-days: 30\n\n      - name: Summary\n        if: steps.check.outputs.has-token == 'false' && github.event_name == 'pull_request'\n        uses: actions/github-script@v7\n        with:\n          script: |\n            const runUrl = `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`;\n\n            const body = [\n              `### Storybook Preview (Fork PR)`,\n              ``,\n              `Chromatic was skipped because the Chromatic project tokens are not available on fork PRs.`,\n              `Storybook builds have been uploaded as workflow artifacts instead:`,\n              ``,\n              `| Storybook | Artifact |`,\n              `| --- | --- |`,\n              `| React | \\`storybook-react\\` |`,\n              `| Vanilla | \\`storybook-vanilla\\` |`,\n              `| Vue | \\`storybook-vue\\` |`,\n              `| Solid | \\`storybook-solid\\` |`,\n              `| Svelte | \\`storybook-svelte\\` |`,\n              ``,\n              `Download artifacts from the [workflow run](${runUrl}) and open \\`index.html\\` to preview.`,\n            ].join('\\n');\n\n            // Check for an existing comment to update\n            const { data: comments } = await github.rest.issues.listComments({\n              owner: context.repo.owner,\n              repo: context.repo.repo,\n              issue_number: context.issue.number,\n            });\n\n            const marker = '### Storybook Preview (Fork PR)';\n            const existing = comments.find(c => c.body?.startsWith(marker));\n\n            if (existing) {\n              await github.rest.issues.updateComment({\n                owner: context.repo.owner,\n                repo: context.repo.repo,\n                comment_id: existing.id,\n                body,\n              });\n            } else {\n              await github.rest.issues.createComment({\n                owner: context.repo.owner,\n                repo: context.repo.repo,\n                issue_number: context.issue.number,\n                body,\n              });\n            }\n\n            core.summary.addHeading('Storybook Preview (Fork PR)', 2);\n            core.summary.addRaw(\n              'Chromatic was skipped because project tokens are not available on fork PRs. ' +\n              'Storybook builds have been uploaded as workflow artifacts. ' +\n              'Download them from the Artifacts section of this workflow run to preview changes locally.'\n            );\n            await core.summary.write();\n"
  },
  {
    "path": ".github/workflows/continous-release.yml",
    "content": "name: Continuous Release\non:\n  pull_request:\n  push:\n    branches: [main]\n\njobs:\n  build:\n    name: Continuous release\n    runs-on: ubuntu-latest\n    environment: production\n\n    steps:\n      - uses: actions/checkout@v2\n        with:\n          fetch-depth: 0\n\n      - name: Setup node\n        uses: actions/setup-node@v2\n        with:\n          node-version: 20\n          # https://github.com/atlassian/changesets/issues/550#issuecomment-811245508\n          registry-url: https://registry.npmjs.org\n\n      - uses: oven-sh/setup-bun@v1\n      - run: bun install && bun run build\n\n      - name: Publish\n        run: npx pkg-pr-new publish './packages/*'\n"
  },
  {
    "path": ".github/workflows/playwright.yml",
    "content": "name: Playwright\n\non:\n  pull_request:\n  push:\n    branches: [main]\n\njobs:\n  e2e:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout Repository\n        uses: actions/checkout@v3\n\n      - name: Setup Bun\n        uses: oven-sh/setup-bun@v1\n        with:\n          bun-version: latest\n\n      - name: Install Dependencies\n        run: bun install\n\n      - name: Install Playwright Browsers\n        run: bunx playwright install --with-deps chromium\n\n      - name: Build Packages\n        run: bun run build\n\n      - name: Run Playwright Tests (React)\n        working-directory: apps/stories\n        run: bunx playwright test\n\n      - name: Run Playwright Tests (Vue)\n        working-directory: apps/stories-vue\n        run: bunx playwright test\n\n      - name: Run Playwright Tests (Solid)\n        working-directory: apps/stories-solid\n        run: bunx playwright test\n\n      - name: Upload Test Results\n        uses: actions/upload-artifact@v4\n        if: ${{ !cancelled() }}\n        with:\n          name: playwright-report\n          path: |\n            apps/stories/playwright-report/\n            apps/stories-vue/playwright-report/\n            apps/stories-solid/playwright-report/\n          retention-days: 14\n"
  },
  {
    "path": ".github/workflows/release.yml",
    "content": "name: Release\non:\n  push:\n    branches:\n      - main\n\npermissions:\n  id-token: write # Required for OIDC\n  contents: write # Required for changesets/action@v1\n  pull-requests: write # Required for changesets/action@v1\n\njobs:\n  release:\n    name: ${{ matrix.channel }}\n    runs-on: ubuntu-latest\n    environment: production\n    strategy:\n      max-parallel: 1\n      matrix:\n        channel:\n          - current\n          - beta\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          fetch-depth: 0\n\n      - name: Setup node\n        uses: actions/setup-node@v4\n        with:\n          node-version: '20'\n          # https://github.com/atlassian/changesets/issues/550#issuecomment-811245508\n          registry-url: 'https://registry.npmjs.org'\n\n      - run: npm install -g npm@latest\n\n      - uses: oven-sh/setup-bun@v1\n      - run: bun install && bun run build\n\n      - name: Create Release Pull Request or Publish to npm\n        if: matrix.channel == 'current'\n        uses: changesets/action@v1\n        with:\n          publish: npm run release\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n\n      - name: Publish packages on npm with @beta tag\n        if: matrix.channel == 'beta'\n        run: |\n          npm run version-packages:beta\n          npm run release:beta\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n"
  },
  {
    "path": ".github/workflows/tests.yml",
    "content": "name: Tests\n\non:\n  pull_request:\n  push:\n    branches: [main]\n\njobs:\n  test:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout Repository\n        uses: actions/checkout@v3\n\n      - name: Setup Bun\n        uses: oven-sh/setup-bun@v1\n        with:\n          bun-version: latest\n\n      - name: Install Dependencies\n        run: bun install\n\n      - name: Run Tests\n        run: bun run test\n"
  },
  {
    "path": ".gitignore",
    "content": ".DS_Store\nnode_modules\n.turbo\n*.log\n.next\ndist\ndist-ssr\n*.local\n.env\n.cache\nserver/dist\npublic/dist\nstorybook-static/\ntest-results/\nplaywright-report/\n/packages/**/*.js\n/packages/**/*.js.map\n/packages/**/*.cjs\n/packages/**/*.cjs.map\n/packages/**/*.d.ts\n/packages/**/*.d.cts\n/packages/**/*.d.ts.map\n/packages/**/*.d.cts.map\n.svelte-kit\n"
  },
  {
    "path": ".nvmrc",
    "content": "22\n"
  },
  {
    "path": ".prettierrc",
    "content": "{\n  \"bracketSpacing\": false,\n  \"singleQuote\": true,\n  \"semi\": true,\n  \"trailingComma\": \"es5\"\n}\n"
  },
  {
    "path": ".vscode/settings.json",
    "content": "{\n  \"editor.formatOnSave\": true,\n  \"typescript.tsdk\": \"node_modules/typescript/lib\",\n  \"search.exclude\": {\n    \"**/dist\": true,\n    \"**/.cache\": true,\n    \"packages/**/*.js\": true,\n    \"packages/**/*.js.map\": true,\n    \"packages/**/*.cjs\": true,\n    \"packages/**/*.cjs.map\": true,\n    \"packages/**/*.d.ts\": true,\n    \"packages/**/*.d.cts\": true\n  },\n  \"files.exclude\": {\n    \"**/dist\": true,\n    \"**/node_modules\": true,\n    \"**/.git\": true,\n    \"**/.cache\": true,\n    \"**/.DS_Store\": true,\n    \"**/coverage\": true,\n    \"**/storybook-static\": true,\n    \"packages/**/*.js\": true,\n    \"packages/**/*.js.map\": true,\n    \"packages/**/*.cjs\": true,\n    \"packages/**/*.cjs.map\": true,\n    \"packages/**/*.d.ts\": true,\n    \"packages/**/*.d.cts\": true\n  }\n}\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing to dnd-kit\n\nThank you for your interest in contributing to dnd-kit! This document provides guidelines and instructions for contributing to the project.\n\n## Project Structure\n\ndnd-kit is a monorepo managed with [Turborepo](https://turbo.build/docs). The main packages are:\n\n- `@dnd-kit/abstract`: Core abstractions and utilities\n- `@dnd-kit/dom`: DOM-specific implementation\n- `@dnd-kit/react`: React-specific implementation\n- `@dnd-kit/geometry`: Geometry utilities\n- `@dnd-kit/state`: State management\n- `@dnd-kit/collision`: Collision detection\n- `@dnd-kit/helpers`: Shared helper functions\n\nThe project also includes:\n\n- `apps/stories`: Storybook stories for testing and demonstrating features\n- `apps/docs`: Documentation site\n\n## Development Setup\n\n1. Fork and clone the repository\n2. Install dependencies:\n   ```bash\n   bun install\n   ```\n3. Build all packages:\n   ```bash\n   bun run build\n   ```\n\n## Development Workflow\n\n1. Create a new branch for your feature or bugfix\n2. Start the development server\n   ```bash\n   bun run dev\n   ```\n3. Make your changes\n4. Verify that the packages build:\n   ```bash\n   bun run build\n   ```\n5. Submit a pull request\n\n## Testing and Documentation\n\n### Stories\n\nThe project uses Storybook for testing and demonstrating features. To run stories:\n\n```bash\nbun run dev\n```\n\nWhen adding new features:\n\n- Add stories to demonstrate usage\n- Include different variations and edge cases\n- Ensure stories are interactive and testable\n\n### Documentation\n\nDocumentation is maintained in the `apps/docs` directory. When making changes:\n\n- Update relevant documentation\n- Add examples for new features\n- Ensure code examples are working\n- Follow the existing documentation style\n\nTo run the documentation site locally:\n\n```bash\nnpm install -g mintlify\nmintlify dev\n```\n\n## Pull Request Guidelines\n\n- Keep pull requests focused and small\n- Include tests for new features\n- Update documentation as needed\n- Follow the existing code style\n- Provide a clear description of changes\n- Add changeset if your changes affect the public API\n- Add or update stories for new features\n- Update documentation if needed\n\n## Code Style\n\n- Use TypeScript for all new code\n- Follow the project's ESLint configuration\n- Use meaningful variable and function names\n- Add appropriate comments and documentation\n- Keep functions small and focused\n\n## Testing\n\n- Write tests for new features\n- Ensure all tests pass\n- Maintain or improve test coverage\n- Test across different browsers and devices\n- Add stories for visual testing\n- Update documentation with examples\n\n## Documentation\n\n- Update README files as needed\n- Add JSDoc comments for new code\n- Keep documentation up to date\n- Provide examples for new features\n- Add stories to demonstrate usage\n- Ensure documentation is accurate and clear\n\n## Release Process\n\nThis project uses Changesets to manage releases. When making changes that affect the public API:\n\n1. Add a changeset:\n   ```bash\n   bun run changeset\n   ```\n2. Follow the prompts to describe your changes\n3. The changeset will be included in the next release\n\nThe release process is automated and will:\n\n1. Update version numbers based on changesets\n2. Update CHANGELOG.md\n3. Create release tags\n4. Publish to npm\n\n## Questions?\n\nIf you have any questions, feel free to:\n\n- Open an [issue](https://github.com/clauderic/dnd-kit/issues/new)\n- Join our [Slack community](https://dnd-kit.slack.com/)\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2021, Claudéric Demers\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE."
  },
  {
    "path": "README.md",
    "content": "<p align=\"center\">\n  <a href=\"https://dndkit.com\">\n    <img alt=\"@dnd-kit – the modern toolkit for building drag & drop interfaces\" src=\".github/assets/dnd-kit-hero-banner.svg\">\n  </a>\n</p>\n<p align=\"center\">\nA modern, lightweight, performant, accessible and extensible drag and drop toolkit for the web\n</p>\n\n## Features\n\n- **Framework agnostic core:** The architecture is built in layers — a framework-agnostic core (`@dnd-kit/abstract`), a DOM implementation (`@dnd-kit/dom`), and thin adapters for your framework of choice.\n- **Supports a wide range of use cases:** lists, grids, multiple containers, nested contexts, variable sized items, virtualized lists, 2D games, and more.\n- **Built-in support for multiple input methods:** Pointer, mouse, touch and keyboard sensors.\n- **Fully customizable & extensible:** Customize every detail — animations, transitions, behaviours, styles. Build your own sensors, collision detection algorithms, customize key bindings and more.\n- **Accessibility:** Keyboard support, sensible default ARIA attributes, customizable screen reader instructions and live regions built-in.\n- **Performance:** Built with performance in mind to support silky smooth animations.\n- **Sortable:** Need to build a sortable interface? Check out `@dnd-kit/dom/sortable`, a thin layer built on top of the core.\n\n<h2 align=\"left\">Getting started</h2>\n\n<p>\nChoose your preferred framework to get started:\n</p>\n\n<br>\n\n<table width=\"100%\" cellpadding=\"32\">\n<tr>\n<td width=\"50%\" valign=\"top\">\n<br>\n<img src=\"https://cdn.simpleicons.org/javascript/F7DF1E\" height=\"22\" alt=\"JavaScript\" />\n<br>\n\n<strong><a href=\"https://dndkit.com/quickstart\">Vanilla</a></strong>\n\nBuild drag and drop interfaces using plain JavaScript\n<br>\n\n</td>\n\n<td width=\"50%\" valign=\"top\">\n<br>\n<img src=\"https://cdn.simpleicons.org/react/61DAFB\" height=\"22\" alt=\"React\" />\n<br>\n\n<strong><a href=\"https://dndkit.com/react/quickstart\">React</a></strong>\n\nBuild drag and drop interfaces using React components and hooks\n<br><br>\n\n</td>\n</tr>\n\n<tr>\n<td width=\"50%\" valign=\"top\">\n<br>\n<img src=\"https://cdn.simpleicons.org/vue.js/4FC08D\" height=\"22\" alt=\"Vue\" />\n<br>\n\n<strong><a href=\"https://dndkit.com/vue/quickstart\">Vue</a></strong>\n\nBuild drag and drop interfaces using Vue composables and components\n<br><br>\n\n</td>\n\n<td width=\"50%\" valign=\"top\">\n<br>\n<img src=\"https://cdn.simpleicons.org/svelte/FF3E00\" height=\"22\" alt=\"Svelte\" />\n<br>\n\n<strong><a href=\"https://dndkit.com/svelte/quickstart\">Svelte</a></strong>\n\nBuild drag and drop interfaces using Svelte primitives and components\n<br><br>\n\n</td>\n</tr>\n\n<tr>\n<td width=\"50%\" valign=\"top\">\n<br>\n<img src=\"https://cdn.simpleicons.org/solid/2C4F7C\" height=\"22\" alt=\"SolidJS\" />\n<br>\n\n<strong><a href=\"https://dndkit.com/solid/quickstart\">Solid</a></strong>\n\nBuild drag and drop interfaces using SolidJS hooks and components\n<br><br>\n\n</td>\n\n<td width=\"50%\" valign=\"top\">\n</td>\n</tr>\n</table>\n\n## Documentation\n\nVisit **[dndkit.com](https://dndkit.com)** for full documentation, API reference, guides, and interactive examples.\n\n## Packages\n\n| Package                                    | Version                                                                                          | Description                  |\n| ------------------------------------------ | ------------------------------------------------------------------------------------------------ | ---------------------------- |\n| [`@dnd-kit/abstract`](packages/abstract)   | [![npm](https://img.shields.io/npm/v/@dnd-kit/abstract.svg)](https://npm.im/@dnd-kit/abstract)   | Abstract core                |\n| [`@dnd-kit/collision`](packages/collision) | [![npm](https://img.shields.io/npm/v/@dnd-kit/collision.svg)](https://npm.im/@dnd-kit/collision) | Collision detection          |\n| [`@dnd-kit/dom`](packages/dom)             | [![npm](https://img.shields.io/npm/v/@dnd-kit/dom.svg)](https://npm.im/@dnd-kit/dom)             | Framework-agnostic DOM layer |\n| [`@dnd-kit/geometry`](packages/geometry)   | [![npm](https://img.shields.io/npm/v/@dnd-kit/geometry.svg)](https://npm.im/@dnd-kit/geometry)   | Geometry utilities           |\n| [`@dnd-kit/helpers`](packages/helpers)     | [![npm](https://img.shields.io/npm/v/@dnd-kit/helpers.svg)](https://npm.im/@dnd-kit/helpers)     | Helper functions             |\n| [`@dnd-kit/react`](packages/react)         | [![npm](https://img.shields.io/npm/v/@dnd-kit/react.svg)](https://npm.im/@dnd-kit/react)         | React adapter                |\n| [`@dnd-kit/solid`](packages/solid)         | [![npm](https://img.shields.io/npm/v/@dnd-kit/solid.svg)](https://npm.im/@dnd-kit/solid)         | SolidJS adapter              |\n| [`@dnd-kit/state`](packages/state)         | [![npm](https://img.shields.io/npm/v/@dnd-kit/state.svg)](https://npm.im/@dnd-kit/state)         | Reactive state management    |\n| [`@dnd-kit/svelte`](packages/svelte)       | [![npm](https://img.shields.io/npm/v/@dnd-kit/svelte.svg)](https://npm.im/@dnd-kit/svelte)       | Svelte adapter               |\n| [`@dnd-kit/vue`](packages/vue)             | [![npm](https://img.shields.io/npm/v/@dnd-kit/vue.svg)](https://npm.im/@dnd-kit/vue)             | Vue adapter                  |\n\n## Contributing\n\nThis is a monorepo managed with [Turborepo](https://turbo.build/) and [bun](https://bun.sh/).\n\n```bash\n# Install dependencies\nbun install\n\n# Build all packages\nbun run build\n\n# Run dev mode\nbun run dev\n```\n\n## License\n\n[MIT](./LICENSE)\n"
  },
  {
    "path": "apps/docs/README.md",
    "content": "# Documentation\n\n## Contributing to the @dnd-kit documentation\n\nContributions are welcome to improve the @dnd-kit documentation. Open a [Pull request](https://github.com/clauderic/dnd-kit/pulls) and add the `Documentation` label.\n\n## Development\n\nInstall the [Mintlify CLI](https://www.npmjs.com/package/mintlify) to preview the documentation changes locally. To install, use the following command\n\n```\nnpm i -g mintlify\n```\n\nRun the following command at the root of the `/apps/docs` directory:\n\n```\nmintlify dev\n```\n\n#### Troubleshooting\n\n- Mintlify dev isn't running - Run `mintlify install` it'll re-install dependencies.\n- Page loads as a 404 - Make sure you are running in a folder with `mint.json`\n"
  },
  {
    "path": "apps/docs/concepts/drag-drop-manager.mdx",
    "content": "---\ntitle: 'DragDropManager'\ndescription: 'Orchestrate drag and drop interactions between elements.'\nicon: 'sitemap'\n---\n\nThe `DragDropManager` is the central orchestrator of the drag and drop system. It coordinates all interactions between draggable and droppable elements.\n\n```mermaid\ngraph TD\n    M[Manager]\n    R[Registry]\n    E[Events]\n    I[Entities]\n    D[Draggable]\n    Dr[Droppable]\n    P[Plugins]\n    S[Sensors]\n    Mod[Modifiers]\n    O[Operation]\n\n    M -.-> R\n    R -.-> I\n    R -.-> P\n    R -.-> S\n    R -.-> Mod\n\n    S -.-> |Detect input| O\n    O -.-> |Trigger| E\n    Mod -.-> |Transform| O\n\n\n    I -.-> Dr\n    I -.-> D\n```\n\n## Usage\n\nCreate a manager instance to coordinate drag and drop interactions:\n\n```js\nimport {DragDropManager} from '@dnd-kit/dom';\n\nconst manager = new DragDropManager();\n```\n\n<ParamField path=\"options\" type=\"object\">\n  Optional configuration for the manager:\n  - `sensors`: [Sensors](/extend/sensors) to detect drag interactions — an array or a function that receives the defaults\n  - `plugins`: [Plugins](/extend/plugins) to extend functionality — an array or a function that receives the defaults\n  - `modifiers`: [Modifiers](/extend/modifiers) to customize behavior — an array or a function that receives the defaults\n</ParamField>\n\n## Configuration\n\nThe manager comes with sensible defaults, but you can customize its behavior. The `plugins`, `sensors`, and `modifiers` options accept either an array (which replaces the defaults) or a function that receives the default values and returns a new array.\n\n### Extending defaults\n\nUse the function form to add to or configure the defaults without replacing them:\n\n```js\nimport {DragDropManager} from '@dnd-kit/dom';\nimport {RestrictToWindow} from '@dnd-kit/dom/modifiers';\n\nconst manager = new DragDropManager({\n  // Add a plugin to the defaults\n  plugins: (defaults) => [...defaults, MyPlugin],\n\n  // Configure a default sensor\n  sensors: (defaults) => [\n    ...defaults,\n    PointerSensor.configure({\n      activationConstraints: { distance: 5 },\n    }),\n  ],\n\n  // Add a modifier\n  modifiers: (defaults) => [...defaults, RestrictToWindow],\n});\n```\n\n### Replacing defaults\n\nPass an array to fully replace the defaults:\n\n```js\nimport {\n  DragDropManager,\n  KeyboardSensor,\n  PointerSensor,\n} from '@dnd-kit/dom';\n\nconst manager = new DragDropManager({\n  sensors: [\n    PointerSensor,  // Handles mouse and touch\n    KeyboardSensor, // Enables keyboard navigation\n  ],\n\n  plugins: [\n    AutoScroller,   // Automatic scrolling during drag\n    Accessibility,  // ARIA attributes management\n  ],\n\n  modifiers: [\n    RestrictToWindow, // Keeps dragged items within window bounds\n  ],\n});\n```\n\n<AccordionGroup>\n  <Accordion title=\"Default configuration\">\n    The manager includes these defaults out of the box:\n\n    **Sensors**\n    - `PointerSensor`: Handles mouse and touch interactions\n      - Mouse: Activates immediately on drag handle\n      - Touch: 250ms delay with 5px movement tolerance\n      - Other pointers: 200ms delay with 5px distance threshold\n    - `KeyboardSensor`: Enables keyboard navigation with arrow keys\n\n    **Plugins**\n    - `Accessibility`: Manages ARIA attributes and announcements\n    - `AutoScroller`: Scrolls containers when dragging near edges\n    - `Cursor`: Updates cursor appearance during drag\n    - `Feedback`: Controls visual feedback during drag\n    - `PreventSelection`: Prevents text selection while dragging\n    - `ScrollListener`: Monitors scroll events during drag\n    - `Scroller`: Handles programmatic scrolling\n  </Accordion>\n</AccordionGroup>\n\n## Events\n\nThe manager's `monitor` lets you observe drag and drop events:\n\n```js\n// Observe drag start\nmanager.monitor.addEventListener('beforedragstart', (event) => {\n  // Optionally prevent dragging\n  if (shouldPreventDrag(event.operation.source)) {\n    event.preventDefault();\n  }\n});\n\n// Track movement\nmanager.monitor.addEventListener('dragmove', (event) => {\n  const {source, position} = event.operation;\n  console.log(`Dragging ${source.id} to ${position.current}`);\n});\n\n// Detect collisions\nmanager.monitor.addEventListener('collision', (event) => {\n  const [firstCollision] = event.collisions;\n  if (firstCollision) {\n    console.log(`Colliding with ${firstCollision.id}`);\n  }\n});\n\n// Listen for when dragging ends\nmanager.monitor.addEventListener('dragend', (event) => {\n  const {source, target, canceled} = event.operation;\n  if (!canceled && target) {\n    console.log(`Dropped ${source.id} onto ${target.id}`);\n  }\n});\n```\n\n### Available Events\n\n<ResponseField name=\"beforedragstart\" type=\"Event\">\n  Fires before drag begins. Can be prevented.\n  <Expandable title=\"Properties\">\n    <ResponseField name=\"operation\" type=\"object\">\n      The drag operation that is about to begin\n    </ResponseField>\n    <ResponseField name=\"preventDefault\" type=\"function\">\n      Call to prevent the drag operation from starting\n    </ResponseField>\n  </Expandable>\n</ResponseField>\n\n<ResponseField name=\"dragstart\" type=\"Event\">\n  Fires when drag starts.\n  <Expandable title=\"Properties\">\n    <ResponseField name=\"operation\" type=\"object\">\n      The current drag operation\n    </ResponseField>\n    <ResponseField name=\"nativeEvent\" type=\"Event\">\n      The original browser event that triggered the drag\n    </ResponseField>\n  </Expandable>\n</ResponseField>\n\n<ResponseField name=\"dragmove\" type=\"Event\">\n  Fires during movement. Can be prevented.\n  <Expandable title=\"Properties\">\n    <ResponseField name=\"operation\" type=\"object\">\n      The current drag operation\n    </ResponseField>\n    <ResponseField name=\"to\" type=\"Point\">\n      The destination coordinates\n    </ResponseField>\n    <ResponseField name=\"by\" type=\"Point\">\n      The movement delta\n    </ResponseField>\n    <ResponseField name=\"nativeEvent\" type=\"Event\">\n      The original browser event\n    </ResponseField>\n  </Expandable>\n</ResponseField>\n\n<ResponseField name=\"dragover\" type=\"Event\">\n  Fires when over a droppable. Call `event.preventDefault()` to prevent the default behavior of plugins that respond to this event.\n  <Expandable title=\"Properties\">\n    <ResponseField name=\"operation\" type=\"object\">\n      The current drag operation\n    </ResponseField>\n  </Expandable>\n</ResponseField>\n\n<ResponseField name=\"collision\" type=\"Event\">\n  Fires on droppable collision. Can be prevented.\n  <Expandable title=\"Properties\">\n    <ResponseField name=\"collisions\" type=\"Collision[]\">\n      Array of detected collisions with droppable targets\n    </ResponseField>\n  </Expandable>\n</ResponseField>\n\n<ResponseField name=\"dragend\" type=\"Event\">\n  Fires when drag ends.\n  <Expandable title=\"Properties\">\n    <ResponseField name=\"operation\" type=\"object\">\n      The completed drag operation\n    </ResponseField>\n    <ResponseField name=\"canceled\" type=\"boolean\">\n      Whether the operation was canceled\n    </ResponseField>\n    <ResponseField name=\"nativeEvent\" type=\"Event\">\n      The original browser event\n    </ResponseField>\n  </Expandable>\n</ResponseField>\n\n## Registration\n\nThe manager's `registry` tracks draggable and droppable elements:\n\n```js\n// Manual registration\nconst cleanup = manager.registry.register(draggable);\ncleanup(); // Or manager.registry.unregister(draggable);\n\n// Auto-registration with manager reference\nconst draggable = new Draggable({\n  id: 'draggable-1',\n  element,\n}, manager);\n\n// Opt out of auto-registration\nconst draggable = new Draggable({\n  id: 'draggable-1',\n  element,\n  register: false\n}, manager);\n```\n\n<Tip>\n  Elements automatically register when created with a manager reference. Only use manual registration for advanced use cases.\n</Tip>\n\n## API Reference\n\n### Properties\n\n- `registry`: Tracks active elements and extensions\n  - `draggables`: Map of registered draggable elements\n  - `droppables`: Map of registered droppable elements\n  - `plugins`: Registry of active plugins\n  - `sensors`: Registry of active sensors\n  - `modifiers`: Registry of active modifiers\n\n- `dragOperation`: Current drag operation state\n  - `source`: Currently dragged element\n  - `target`: Current drop target\n  - `position`: Current drag coordinates\n  - `status`: Current operation status\n  - `canceled`: Whether operation was canceled\n\n- `monitor`: Event system\n  - `addEventListener`: Add event listener\n  - `removeEventListener`: Remove listener\n\n- `renderer`: Integration with asynchronous renderers such as React\n\n### Methods\n\n<ParamField path=\"destroy()\" type=\"function\">\n  Clean up the manager and all registered elements:\n  - Unregisters all draggables and droppables\n  - Cleans up all plugins, sensors, and modifiers\n  - Removes all event listeners\n</ParamField>\n\n## Lifecycle\n\n1. **Initialization**\n   - Manager created\n   - Default plugins and sensors registered\n   - Custom configuration applied\n\n2. **Registration**\n   - Draggable and droppable elements register\n   - Plugins initialize\n   - Event listeners bound\n\n3. **Operation**\n   - Drag operations tracked\n   - Events dispatched\n   - Collisions detected\n\n4. **Cleanup**\n   - Elements unregister\n   - Event listeners removed\n   - Resources released\n"
  },
  {
    "path": "apps/docs/concepts/draggable.mdx",
    "content": "---\ntitle: 'Draggable'\ndescription: 'Make elements draggable to drop them over droppable targets.'\nicon: 'bullseye-pointer'\n---\n\nimport {Story} from '/snippets/story.mdx';\nimport {CodeSandbox} from '/snippets/sandbox.mdx';\nimport {draggableStyles} from '/snippets/code.mdx';\n\n## Usage\n\nFirst, create a [DragDropManager](/concepts/drag-drop-manager) instance to orchestrate the drag and drop system. Then use the `Draggable` class to make elements draggable:\n\nexport const code = `\nimport {Draggable, DragDropManager} from '@dnd-kit/dom';\n\nexport function App() {\n  const manager = new DragDropManager();\n\n  const element = document.createElement('button');\n  element.innerText = 'draggable';\n  element.classList.add('btn');\n\n  const draggable = new Draggable({\n    id: 'draggable-1', // Required - must be unique\n    element,\n  }, manager);\n\n  document.body.appendChild(element);\n}\n`.trim();\n\n<CodeSandbox files={{\n  'index.js': {code: `import './styles.css';\\nimport {App} from './draggable.js';\\n\\nApp();`, hidden: true},\n  'draggable.js': {code, active: true},\n  'styles.css': {code: draggableStyles, hidden: true},\n}} height={360} previewHeight={200} template=\"vanilla\" hero />\n\n## Handles\n\nBy default, the entire element can be used to initiate dragging. You can restrict dragging to a specific handle element:\n\n```js\nconst element = document.createElement('div');\nconst handle = document.createElement('div');\nhandle.classList.add('handle');\nhandle.innerHTML = '⋮'; // Three dots menu icon for drag handle\n\nelement.appendChild(handle);\n\nconst draggable = new Draggable({\n  id: 'draggable-1',\n  element,\n  handle, // Only allow dragging from the handle\n}, manager);\n```\n\n## Types\n\nYou can assign types to draggable elements to restrict which [droppable targets](/concepts/droppable) they can be dropped on:\n\n```js\n// Assign a type\nconst draggable = new Draggable({\n  id: 'draggable-1',\n  element,\n  type: 'item', // Only droppables accepting 'item' type will be valid targets\n}, manager);\n```\n\n## Feedback\n\nYou can customize how the element behaves while being dragged using the [Feedback](/extend/plugins/feedback) plugin's per-entity configuration:\n\n```js\nimport {Draggable, DragDropManager, Feedback} from '@dnd-kit/dom';\n\nconst draggable = new Draggable({\n  id: 'draggable-1',\n  element,\n  plugins: [Feedback.configure({ feedback: 'clone' })],\n}, manager);\n```\n\nAvailable feedback options:\n- `'default'`: The original element moves with the drag (best for most cases)\n- `'clone'`: A copy of the element stays in place while the original moves (good for drag-to-copy)\n- `'move'`: The element moves without a placeholder (minimal visual feedback)\n- `'none'`: No visual feedback (useful for custom drag overlays)\n\n## API Reference\n\n### Arguments\n\nThe `Draggable` class accepts the following arguments:\n\n<ParamField path=\"id\" type=\"string | number\" required>\n  A unique identifier for this draggable element within the same [drag and drop context provider](/concepts/drag-drop-manager).\n</ParamField>\n\n<ParamField path=\"element\" type=\"Element\">\n  The DOM element to make draggable. While not required in the constructor, it must be set to enable dragging.\n</ParamField>\n\n<ParamField path=\"handle\" type=\"Element\">\n  Optionally specify a drag handle element. If not provided, the entire element will be draggable. See [drag handles](#handles).\n</ParamField>\n\n<ParamField path=\"type\" type=\"string | number | Symbol\">\n  Optionally assign a type to restrict which droppable targets can accept this element. See [types](#types).\n</ParamField>\n\n<ParamField path=\"plugins\" type=\"PluginDescriptor[]\">\n  An array of plugin descriptors for per-entity plugin configuration. Use `Plugin.configure()` to create descriptors. See [feedback](#feedback).\n</ParamField>\n\n<ParamField path=\"disabled\" type=\"boolean\">\n  Set to `true` to temporarily prevent dragging this element.\n</ParamField>\n\n<ParamField path=\"modifiers\" type=\"Modifier[]\">\n  An array of [modifiers](/extend/modifiers) to customize drag behavior.\n</ParamField>\n\n<ParamField path=\"sensors\" type=\"Sensors[]\">\n  An array of [sensors](/extend/sensors) to detect drag interactions.\n</ParamField>\n\n<ParamField path=\"data\" type=\"{[key: string]: any}\">\n  Optional data to associate with this draggable element, available in event handlers.\n</ParamField>\n\n<ParamField path=\"effects\" type=\"() => Effect[]\">\n  <Info>This is an advanced feature and should not need to be used by most consumers.</Info>\n  You can supply a function that returns an array of reactive effects that can be set up and automatically cleaned up when invoking the `destroy()` method of this instance.\n</ParamField>\n\n### Properties\n\nThe `Draggable` instance provides these key properties:\n\n- `id`: The unique identifier\n- `element`: The main DOM element\n- `handle`: The drag handle element (if specified)\n- `type`: The assigned type\n- `disabled`: Whether dragging is disabled\n- `isDragging`: Whether this element is currently being dragged\n- `isDropping`: Whether this element is being dropped\n\n### Methods\n\n- `register()`: Register this draggable with the manager\n- `unregister()`: Remove this draggable from the manager\n- `destroy()`: Clean up this draggable instance and remove all listeners\n"
  },
  {
    "path": "apps/docs/concepts/droppable.mdx",
    "content": "---\ntitle: 'Droppable'\ndescription: 'Create droppable targets for draggable elements.'\nicon: 'expand'\n---\n\nimport {Story} from '/snippets/story.mdx';\n\n<Story id=\"droppable-basic-setup--example\" framework=\"vanilla\" height=\"400\" hero />\n\n## Usage\n\nThe `Droppable` class creates drop targets that can receive [draggable](/concepts/draggable) elements. First, create a [DragDropManager](/concepts/drag-drop-manager) instance:\n\n```js\nimport {Droppable, DragDropManager} from '@dnd-kit/dom';\n\nconst manager = new DragDropManager();\n\nconst element = document.createElement('div');\nelement.classList.add('droppable');\n\n// Create a droppable target\nconst droppable = new Droppable({\n  id: 'drop-zone',\n  element,\n}, manager);\n\ndocument.body.appendChild(element);\n\n// Listen for drop events\nmanager.monitor.addEventListener('dragend', (event) => {\n  if (event.operation.target?.id === droppable.id) {\n    console.log('Item dropped!', event.operation.source);\n  }\n});\n```\n\n## Accepting Specific Types\n\nYou can restrict which draggable elements can be dropped by using the `accepts` property. See the [draggable types](/concepts/draggable#types) documentation for more details.\n\n```js\n// Accept only draggables with type 'item'\nconst droppable = new Droppable({\n  id: 'drop-zone',\n  element,\n  accepts: 'item'\n}, manager);\n\n// Accept multiple types\nconst droppable = new Droppable({\n  id: 'drop-zone',\n  element,\n  accepts: ['item', 'card']\n}, manager);\n\n// Use a function for custom logic\nconst droppable = new Droppable({\n  id: 'drop-zone',\n  element,\n  accepts: (draggable) => {\n    // Custom acceptance logic\n    return draggable.type === 'item' && draggable.data.category === 'fruit';\n  }\n}, manager);\n```\n\n## Collision Detection\n\nBy default, the `Droppable` class uses rectangle intersection to detect when draggable elements are over the drop target:\n\n<img src=\"/images/droppable/shape-intersection.svg\" alt=\"Rectangle intersection collision detection\" />\n\nYou can customize this behavior with different collision detection algorithms:\n\n```js\nimport {\n  closestCenter,\n  pointerIntersection,\n  directionBiased\n} from '@dnd-kit/collision';\n\n// Use closest center point for card stacking\nconst droppable = new Droppable({\n  id: 'card-stack',\n  element,\n  collisionDetector: closestCenter\n}, manager);\n```\n\nFor example, the `closestCenter` detector will detect collisions based on the distance between the center points, which is ideal for card stacking:\n\n<img src=\"/images/droppable/closest-center.svg\" alt=\"Closest center collision detection\" />\n\n### Collision Priority\n\nWhen multiple droppable targets overlap, you can set priority to determine which one should receive the drop. This is particularly useful for nested containers:\n\n```js\nconst container = new Droppable({\n  id: 'container',\n  element: containerElement,\n  collisionPriority: 1 // Lower priority\n}, manager);\n\nconst item = new Droppable({\n  id: 'item',\n  element: itemElement,\n  collisionPriority: 2 // Higher priority\n}, manager);\n```\n\n## API Reference\n\n### Arguments\n\nThe `Droppable` class accepts the following arguments:\n\n<ParamField path=\"id\" type=\"string | number\" required>\n  A unique identifier for this droppable target within the same [drag and drop context provider](/concepts/drag-drop-manager).\n</ParamField>\n\n<ParamField path=\"element\" type=\"Element\">\n  The DOM element to make droppable. While not required in the constructor, it must be set to enable dropping.\n</ParamField>\n\n<ParamField path=\"accepts\" type=\"string | number | Symbol | ((draggable: Draggable) => boolean)\">\n  Specify which draggable elements can be dropped on this target. See [accepting specific types](#accepting-specific-types) for more details.\n</ParamField>\n\n<ParamField path=\"collisionDetector\" type=\"CollisionDetector\">\n  A function to determine when draggable elements are over this target. See [collision detection](#collision-detection) for built-in options, such as:\n  - `shapeIntersection`: Default, uses rectangle intersection\n  - `pointerIntersection`: Uses pointer position for precise detection\n  - `closestCenter`: Uses center point distance, ideal for card stacking\n  - `directionBiased`: Considers drag direction, useful for sortable lists\n</ParamField>\n\n<ParamField path=\"collisionPriority\" type=\"number\">\n  Priority level when multiple droppable targets overlap. Higher numbers take precedence. See [collision priority](#collision-priority) for more details.\n</ParamField>\n\n<ParamField path=\"disabled\" type=\"boolean\">\n  Set to `true` to temporarily prevent dropping on this target.\n</ParamField>\n\n<ParamField path=\"data\" type=\"{[key: string]: any}\">\n  Optional data to associate with this droppable target, available in event handlers.\n</ParamField>\n\n<ParamField path=\"effects\" type=\"() => Effect[]\">\n  <Info>This is an advanced feature and should not need to be used by most consumers.</Info>\n  You can supply a function that returns an array of reactive effects that can be set up and automatically cleaned up when invoking the `destroy()` method of this instance.\n</ParamField>\n\n### Properties\n\nThe `Droppable` instance provides these key properties:\n\n- `id`: The unique identifier\n- `element`: The DOM element acting as the drop target\n- `disabled`: Whether dropping is currently disabled\n- `isDropTarget`: Whether a draggable is currently over this target\n- `shape`: The current bounding shape of the drop target\n\n### Methods\n\n- `accepts(draggable)`: Check if this target accepts a draggable element\n- `refreshShape()`: Recalculate the target's dimensions\n- `register()`: Register this target with the manager\n- `unregister()`: Remove this target from the manager\n- `destroy()`: Clean up this droppable instance and remove all listeners\n"
  },
  {
    "path": "apps/docs/concepts/sortable.mdx",
    "content": "---\ntitle: 'Sortable'\ndescription: 'Reorder elements in a list or across multiple lists.'\nicon: 'layer-group'\n---\n\nimport {Story} from '/snippets/story.mdx';\nimport {CodeSandbox} from '/snippets/sandbox.mdx';\nimport {sortableStyles} from '/snippets/code.mdx';\n\n<Story id=\"react-sortable--example\" height=\"320\" hero />\n\n## Usage\n\nThe `Sortable` class allows you to reorder elements in a list or across multiple lists. A sortable element is both [Droppable](/concepts/droppable) and [Draggable](/concepts/draggable), which means you can drag it and drop it to reorder.\n\nFirst, create a [DragDropManager](/concepts/drag-drop-manager) instance and use it to create sortable items:\n\nexport const code = `\nimport {DragDropManager} from '@dnd-kit/dom';\nimport {Sortable} from '@dnd-kit/dom/sortable';\n\nexport function App() {\n  const manager = new DragDropManager();\n\n  const wrapper = document.createElement('ul');\n  const items = ['Item 1', 'Item 2', 'Item 3', 'Item 4'];\n\n  wrapper.classList.add('list');\n\n  items.forEach((item, index) => {\n    const element = document.createElement('li');\n\n    element.classList.add('item');\n    element.innerText = item;\n\n    const sortable = new Sortable({\n      id: item,\n      index, // Required - the position in the list\n      element,\n    }, manager);\n\n    wrapper.appendChild(element);\n  });\n\n  document.body.appendChild(wrapper);\n}\n`.trim();\n\n<CodeSandbox files={{\n  'index.js': {code: `import './styles.css';\\nimport {App} from './sortable.js';\\n\\nApp();`, hidden: true},\n  'sortable.js': {code, active: true},\n  'styles.css': {code: sortableStyles, hidden: true},\n}} height={580} previewHeight={180} template=\"vanilla\" />\n\n## Multiple Lists\n\nYou can create multiple sortable lists by assigning sortable items to different groups:\n\n```js\nconst list1 = ['Item 1', 'Item 2'];\nconst list2 = ['Item 3', 'Item 4'];\n\n// First list\nlist1.forEach((item, index) => {\n  new Sortable({\n    id: item,\n    index,\n    group: 'list1', // Assign to first group\n    element: createItemElement(item),\n  }, manager);\n});\n\n// Second list\nlist2.forEach((item, index) => {\n  new Sortable({\n    id: item,\n    index,\n    group: 'list2', // Assign to second group\n    element: createItemElement(item),\n  }, manager);\n});\n```\n\n## Drag Handles\n\nBy default, the entire sortable element can be used to initiate dragging. You can restrict dragging to a specific handle element:\n\n```js\nconst element = document.createElement('li');\nconst handle = document.createElement('div');\nhandle.classList.add('handle');\n\nelement.appendChild(handle);\n\nnew Sortable({\n  id: 'item-1',\n  index: 0,\n  element,\n  handle, // Only allow dragging from the handle\n}, manager);\n```\n\n## Animations\n\nSortable items automatically animate when their position changes. You can customize the animation through the `transition` option:\n\n```js\nnew Sortable({\n  id: 'item-1',\n  index: 0,\n  transition: {\n    duration: 250, // Animation duration in ms\n    easing: 'cubic-bezier(0.25, 1, 0.5, 1)', // Animation easing\n    idle: false, // Whether to animate when no drag is in progress\n  }\n}, manager);\n```\n\n## Optimistic Sorting\n\nBy default, every `Sortable` instance registers the `OptimisticSortingPlugin`. This plugin optimistically reorders DOM elements during a drag operation so that the UI feels responsive — without requiring your framework to re-render on every `dragover` event.\n\n### How it works\n\nWhen you drag a sortable item over another sortable item, the plugin:\n\n1. Physically moves the DOM elements to reflect the new order.\n2. Updates the `index` (and `group`, for multi-list scenarios) on each affected `Sortable` instance.\n3. Sets the **drop target** to the drag source itself by calling `manager.actions.setDropTarget(source.id)`.\n\nStep 3 has an important consequence: **during a drag, `source` and `target` on the operation will refer to the same element.** This also means that `isDragSource` and `isDropTarget` will both be `true` on the dragged item.\n\n### Tracking position changes\n\nSince `source` and `target` are the same, you cannot compare their IDs to determine what moved. Instead, use the sortable-specific properties available on the source:\n\n| Property | Description |\n|----------|-------------|\n| `index` | The current position of the item (updated by the plugin as it moves) |\n| `initialIndex` | The position the item was in when the drag started |\n| `group` | The current group the item belongs to |\n| `initialGroup` | The group the item was in when the drag started |\n\n### Preventing optimistic sorting for a single event\n\nIf you call `event.preventDefault()` in a `dragover` handler, the `OptimisticSortingPlugin` will skip the optimistic update for that particular event. This is useful when you want to handle certain moves yourself (for example, to prevent items from being dragged into a specific group) while still letting the plugin handle the rest:\n\n```js\nmanager.monitor.addEventListener('dragover', (event) => {\n  const {source, target} = event.operation;\n\n  if (shouldPreventMove(source, target)) {\n    event.preventDefault(); // Optimistic sorting will not run for this event\n  }\n});\n```\n\n### Disabling optimistic sorting\n\nIf you prefer to manage sorting entirely in your application state (for example, by handling every `dragover` event), you can disable optimistic sorting by omitting the `OptimisticSortingPlugin` from the `plugins` array:\n\n```js\nimport {SortableKeyboardPlugin} from '@dnd-kit/dom/sortable';\n\nnew Sortable({\n  id: 'item-1',\n  index: 0,\n  element,\n  plugins: [SortableKeyboardPlugin], // No OptimisticSortingPlugin\n}, manager);\n```\n\nWithout optimistic sorting, `source` and `target` will be different elements during drag, and you can use their IDs directly. However, you will need to handle reordering in your `dragover` listener for smooth visual feedback.\n\n## Managing state without the move helper\n\nThe `move` helper from `@dnd-kit/helpers` is a convenience function that takes your items and a drag event and returns a new array with the item moved to its new position. It supports flat arrays and grouped records, handles canceled drags, and works with optimistic sorting out of the box.\n\nIf you need more control over state updates, you can manage state manually using the sortable properties and the `isSortable` type guard.\n\n### Single list\n\nWith optimistic sorting enabled (the default), you only need to handle the `dragend` event. The `isSortable` type guard narrows the `source` to expose `initialIndex` and `index`:\n\n```js\nimport {isSortable} from '@dnd-kit/dom/sortable';\n\nmanager.monitor.addEventListener('dragend', (event) => {\n  if (event.canceled) return;\n\n  const {source} = event.operation;\n\n  if (isSortable(source)) {\n    const {initialIndex, index} = source;\n\n    if (initialIndex !== index) {\n      // Reorder your data: move the item from initialIndex to index\n      const newItems = [...items];\n      const [removed] = newItems.splice(initialIndex, 1);\n      newItems.splice(index, 0, removed);\n      items = newItems;\n    }\n  }\n});\n```\n\n### Multiple lists\n\nFor multiple lists, use `initialGroup` and `group` to detect whether the item stayed in the same list or moved to a different one:\n\n```js\nmanager.monitor.addEventListener('dragend', (event) => {\n  if (event.canceled) return;\n\n  const {source} = event.operation;\n\n  if (isSortable(source)) {\n    const {initialIndex, index, initialGroup, group} = source;\n\n    if (initialGroup === group) {\n      // Same group: reorder within the list\n      const groupItems = [...items[group]];\n      const [removed] = groupItems.splice(initialIndex, 1);\n      groupItems.splice(index, 0, removed);\n      items = {...items, [group]: groupItems};\n    } else {\n      // Cross-group transfer\n      const sourceItems = [...items[initialGroup]];\n      const [removed] = sourceItems.splice(initialIndex, 1);\n      const targetItems = [...items[group]];\n      targetItems.splice(index, 0, removed);\n      items = {...items, [initialGroup]: sourceItems, [group]: targetItems};\n    }\n  }\n});\n```\n\n## Type Guards\n\n`@dnd-kit/dom/sortable` exports two type guards to help you work with sortable drag operations.\n\n### `isSortable`\n\nChecks whether a `Draggable` or `Droppable` instance is a sortable element. If it returns `true`, the type is narrowed to expose sortable-specific properties like `index`, `initialIndex`, `group`, and `initialGroup`.\n\n```js\nimport {isSortable} from '@dnd-kit/dom/sortable';\n\nconst {source} = event.operation;\n\nif (isSortable(source)) {\n  console.log(source.index);        // number\n  console.log(source.initialIndex);  // number\n  console.log(source.group);         // string | number | undefined\n  console.log(source.initialGroup);  // string | number | undefined\n}\n```\n\n### `isSortableOperation`\n\nChecks whether **both** `source` and `target` of a drag operation are sortable elements. This is useful when you want to narrow the entire operation at once:\n\n```js\nimport {isSortableOperation} from '@dnd-kit/dom/sortable';\n\nconst {operation} = event;\n\nif (isSortableOperation(operation)) {\n  // Both source and target are narrowed to sortable types\n  console.log(operation.source.initialIndex);\n  console.log(operation.target.index);\n}\n```\n\nBoth type guards are also available from framework-specific packages:\n\n- `@dnd-kit/react/sortable`\n- `@dnd-kit/vue/sortable`\n- `@dnd-kit/svelte/sortable`\n- `@dnd-kit/solid/sortable`\n\n## API Reference\n\n### Arguments\n\nThe `Sortable` class accepts the following arguments:\n\n<ParamField path=\"id\" type=\"string | number\" required>\n  A unique identifier for this sortable item within the drag and drop manager.\n</ParamField>\n\n<ParamField path=\"index\" type=\"number\" required>\n  The position of this item within its sortable group.\n</ParamField>\n\n<ParamField path=\"element\" type=\"Element\">\n  The DOM element to make sortable. While not required in the constructor, it must be set to enable sorting.\n</ParamField>\n\n<ParamField path=\"group\" type=\"string | number\">\n  Optionally assign this item to a group. Items can only be sorted within their group.\n</ParamField>\n\n<ParamField path=\"handle\" type=\"Element\">\n  Optionally specify a drag handle element. If not provided, the entire element will be draggable.\n</ParamField>\n\n<ParamField path=\"target\" type=\"Element\">\n  Optionally specify a different element to use as the drop target. By default, uses the main element.\n</ParamField>\n\n<ParamField path=\"transition\" type=\"SortableTransition | null\">\n  Configure the animation when items are reordered:\n  ```ts\n  interface SortableTransition {\n    duration?: number; // Duration in ms (default: 250)\n    easing?: string;  // CSS easing function (default: cubic-bezier)\n    idle?: boolean;   // Animate when not dragging (default: false)\n  }\n  ```\n</ParamField>\n\n<ParamField path=\"disabled\" type=\"boolean\">\n  Set to `true` to temporarily disable sorting for this item.\n</ParamField>\n\n<ParamField path=\"type\" type=\"string | number | Symbol\">\n  Optionally restrict which types of items can be sorted together.\n</ParamField>\n\n<ParamField path=\"accepts\" type=\"string | number | Symbol | ((type) => boolean)\">\n  Optionally restrict which types of items can be dropped on this item.\n</ParamField>\n\n<ParamField path=\"modifiers\" type=\"Modifier[]\">\n  An array of [modifiers](/extend/modifiers) to customize drag behavior.\n</ParamField>\n\n<ParamField path=\"sensors\" type=\"Sensors[]\">\n  An array of [sensors](/extend/sensors) to detect drag interactions.\n</ParamField>\n\n<ParamField path=\"data\" type=\"{[key: string]: any}\">\n  Optional data to associate with this sortable item, available in event handlers.\n</ParamField>\n\n### Properties\n\nThe `Sortable` instance provides these key properties:\n\n- `index`: The current position in the list\n- `group`: The assigned group identifier\n- `isDragging`: Whether this item is currently being dragged\n- `isDropTarget`: Whether this item is currently a drop target\n- `disabled`: Whether sorting is disabled for this item\n- `element`: The main DOM element\n- `target`: The drop target element (if different from main element)\n\n### Methods\n\n- `register()`: Register this sortable item with the manager\n- `unregister()`: Remove this item from the manager\n- `destroy()`: Clean up this sortable instance\n- `accepts(draggable)`: Check if this item accepts a draggable\n- `refreshShape()`: Recalculate the item's dimensions\n"
  },
  {
    "path": "apps/docs/docs.json",
    "content": "{\n  \"$schema\": \"https://mintlify.com/docs.json\",\n  \"theme\": \"mint\",\n  \"name\": \"@dnd-kit\",\n  \"colors\": {\n    \"primary\": \"#596dff\",\n    \"light\": \"#596dff\",\n    \"dark\": \"#596dff\"\n  },\n  \"favicon\": \"/favicon.png\",\n  \"navigation\": {\n    \"versions\": [\n      {\n        \"version\": \"Latest\",\n        \"anchors\": [\n          {\n            \"anchor\": \"Vanilla\",\n            \"icon\": \"js\",\n            \"groups\": [\n              {\n                \"group\": \" \",\n                \"pages\": [\"overview\"]\n              },\n              {\n                \"group\": \"Get Started\",\n                \"pages\": [\"quickstart\"]\n              },\n              {\n                \"group\": \"Concepts\",\n                \"pages\": [\n                  \"concepts/drag-drop-manager\",\n                  \"concepts/draggable\",\n                  \"concepts/droppable\",\n                  \"concepts/sortable\"\n                ]\n              },\n              {\n                \"group\": \"Extensibility\",\n                \"pages\": [\n                  {\n                    \"group\": \"Plugins\",\n                    \"icon\": \"cube\",\n                    \"pages\": [\n                      \"extend/plugins\",\n                      \"extend/plugins/accessibility\",\n                      \"extend/plugins/auto-scroller\",\n                      \"extend/plugins/cursor\",\n                      \"extend/plugins/debug\",\n                      \"extend/plugins/feedback\",\n                      \"extend/plugins/style-injector\"\n                    ]\n                  },\n                  {\n                    \"group\": \"Sensors\",\n                    \"icon\": \"monitor-waveform\",\n                    \"pages\": [\n                      \"extend/sensors\",\n                      \"extend/sensors/pointer-sensor\",\n                      \"extend/sensors/keyboard-sensor\"\n                    ]\n                  },\n                  \"extend/modifiers\"\n                ]\n              }\n            ]\n          },\n          {\n            \"anchor\": \"React\",\n            \"icon\": \"react\",\n            \"groups\": [\n              {\n                \"group\": \"Get Started\",\n                \"pages\": [\"react/quickstart\"]\n              },\n              {\n                \"group\": \"Components\",\n                \"pages\": [\n                  \"react/components/drag-drop-provider\",\n                  \"react/components/drag-overlay\"\n                ]\n              },\n              {\n                \"group\": \"Hooks\",\n                \"pages\": [\n                  \"react/hooks/use-draggable\",\n                  \"react/hooks/use-droppable\",\n                  \"react/hooks/use-sortable\",\n                  \"react/hooks/use-drag-drop-monitor\"\n                ]\n              },\n              {\n                \"group\": \"Guides\",\n                \"pages\": [\n                  \"react/guides/migration\",\n                  \"react/guides/multiple-sortable-lists\",\n                  \"react/guides/sortable-state-management\"\n                ]\n              }\n            ]\n          },\n          {\n            \"anchor\": \"Vue\",\n            \"icon\": \"vuejs\",\n            \"groups\": [\n              {\n                \"group\": \"Get Started\",\n                \"pages\": [\"vue/quickstart\"]\n              },\n              {\n                \"group\": \"Components\",\n                \"pages\": [\n                  \"vue/components/drag-drop-provider\",\n                  \"vue/components/drag-overlay\"\n                ]\n              },\n              {\n                \"group\": \"Composables\",\n                \"pages\": [\n                  \"vue/composables/use-draggable\",\n                  \"vue/composables/use-droppable\",\n                  \"vue/composables/use-sortable\"\n                ]\n              }\n            ]\n          },\n          {\n            \"anchor\": \"Svelte\",\n            \"icon\": \"svelte\",\n            \"groups\": [\n              {\n                \"group\": \"Get Started\",\n                \"pages\": [\"svelte/quickstart\"]\n              },\n              {\n                \"group\": \"Components\",\n                \"pages\": [\n                  \"svelte/components/drag-drop-provider\",\n                  \"svelte/components/drag-overlay\"\n                ]\n              },\n              {\n                \"group\": \"Primitives\",\n                \"pages\": [\n                  \"svelte/primitives/create-draggable\",\n                  \"svelte/primitives/create-droppable\",\n                  \"svelte/primitives/create-sortable\"\n                ]\n              }\n            ]\n          },\n          {\n            \"anchor\": \"Solid\",\n            \"icon\": \"solidjs\",\n            \"groups\": [\n              {\n                \"group\": \"Get Started\",\n                \"pages\": [\"solid/quickstart\"]\n              },\n              {\n                \"group\": \"Components\",\n                \"pages\": [\n                  \"solid/components/drag-drop-provider\",\n                  \"solid/components/drag-overlay\"\n                ]\n              },\n              {\n                \"group\": \"Hooks\",\n                \"pages\": [\n                  \"solid/hooks/use-draggable\",\n                  \"solid/hooks/use-droppable\",\n                  \"solid/hooks/use-sortable\"\n                ]\n              }\n            ]\n          }\n        ]\n      },\n      {\n        \"version\": \"Legacy\",\n        \"anchors\": [\n          {\n            \"anchor\": \"React\",\n            \"icon\": \"react\",\n            \"groups\": [\n              {\n                \"group\": \"Get started\",\n                \"pages\": [\n                  \"legacy/introduction/installation\",\n                  \"legacy/introduction/getting-started\"\n                ]\n              },\n              {\n                \"group\": \"Concepts\",\n                \"pages\": [\n                  {\n                    \"group\": \"Context Provider\",\n                    \"pages\": [\n                      \"legacy/api-documentation/context-provider/dnd-context\",\n                      \"legacy/api-documentation/context-provider/collision-detection-algorithms\",\n                      \"legacy/api-documentation/context-provider/use-dnd-context\",\n                      \"legacy/api-documentation/context-provider/use-dnd-monitor\"\n                    ],\n                    \"icon\": \"sitemap\"\n                  },\n                  {\n                    \"group\": \"Draggable\",\n                    \"pages\": [\n                      \"legacy/api-documentation/draggable\",\n                      \"legacy/api-documentation/draggable/use-draggable\",\n                      \"legacy/api-documentation/draggable/drag-overlay\"\n                    ],\n                    \"icon\": \"bullseye-pointer\"\n                  },\n                  {\n                    \"group\": \"Droppable\",\n                    \"pages\": [\n                      \"legacy/api-documentation/droppable\",\n                      \"legacy/api-documentation/droppable/use-droppable\"\n                    ],\n                    \"icon\": \"expand\"\n                  },\n                  {\n                    \"group\": \"Sortable\",\n                    \"pages\": [\n                      \"legacy/presets/sortable/overview\",\n                      \"legacy/presets/sortable/sortable-context\",\n                      \"legacy/presets/sortable/use-sortable\"\n                    ],\n                    \"icon\": \"layer-group\"\n                  }\n                ]\n              },\n              {\n                \"group\": \"Extensibility\",\n                \"pages\": [\n                  {\n                    \"group\": \"Sensors\",\n                    \"pages\": [\n                      \"legacy/api-documentation/sensors\",\n                      \"legacy/api-documentation/sensors/pointer\",\n                      \"legacy/api-documentation/sensors/mouse\",\n                      \"legacy/api-documentation/sensors/touch\",\n                      \"legacy/api-documentation/sensors/keyboard\"\n                    ],\n                    \"icon\": \"signal-stream\"\n                  },\n                  \"legacy/api-documentation/modifiers\"\n                ]\n              },\n              {\n                \"group\": \"Guides\",\n                \"pages\": [\"legacy/guides/accessibility\"]\n              }\n            ]\n          }\n        ]\n      }\n    ]\n  },\n  \"contextual\": {\n    \"options\": [\"copy\", \"view\", \"chatgpt\", \"claude\"]\n  },\n  \"redirects\": [\n    {\n      \"source\": \"/introduction/getting-started\",\n      \"destination\": \"/legacy/introduction/getting-started\"\n    },\n    {\n      \"source\": \"/introduction/installation\",\n      \"destination\": \"/legacy/introduction/installation\"\n    },\n    {\n      \"source\": \"/introduction/:slug*\",\n      \"destination\": \"/legacy/introduction/:slug*\"\n    },\n    {\n      \"source\": \"/api-documentation/context-provider\",\n      \"destination\": \"/legacy/api-documentation/context-provider/dnd-context\"\n    },\n    {\n      \"source\": \"/api-documentation/context-provider/usedndcontext\",\n      \"destination\": \"/legacy/api-documentation/context-provider/use-dnd-context\"\n    },\n    {\n      \"source\": \"/api-documentation/context-provider/usedndmonitor\",\n      \"destination\": \"/legacy/api-documentation/context-provider/use-dnd-monitor\"\n    },\n    {\n      \"source\": \"/api-documentation/context-provider/dndcontext\",\n      \"destination\": \"/legacy/api-documentation/context-provider/dnd-context\"\n    },\n    {\n      \"source\": \"/api-documentation/draggable/usedraggable\",\n      \"destination\": \"/legacy/api-documentation/draggable/use-draggable\"\n    },\n    {\n      \"source\": \"/api-documentation/droppable/usedroppable\",\n      \"destination\": \"/legacy/api-documentation/droppable/use-droppable\"\n    },\n    {\n      \"source\": \"/api-documentation/:slug*\",\n      \"destination\": \"/legacy/api-documentation/:slug*\"\n    },\n    {\n      \"source\": \"/presets/sortable\",\n      \"destination\": \"/legacy/presets/sortable/overview\"\n    },\n    {\n      \"source\": \"/presets/sortable/usesortable\",\n      \"destination\": \"/legacy/presets/sortable/use-sortable\"\n    },\n    {\n      \"source\": \"/presets/sortable/:slug*\",\n      \"destination\": \"/legacy/presets/sortable/:slug*\"\n    },\n    {\n      \"source\": \"/guides/:slug*\",\n      \"destination\": \"/legacy/guides/:slug*\"\n    },\n    {\n      \"source\": \"/react/migration\",\n      \"destination\": \"/react/guides/migration\"\n    }\n  ],\n  \"logo\": \"/images/logo/logo.svg\",\n  \"navbar\": {\n    \"links\": [\n      {\n        \"label\": \"Examples\",\n        \"href\": \"https://examples.dndkit.com\"\n      },\n      {\n        \"label\": \"Community\",\n        \"href\": \"https://dnd-kit.slack.com/\"\n      }\n    ],\n    \"primary\": {\n      \"type\": \"button\",\n      \"label\": \"Github\",\n      \"href\": \"https://github.com/clauderic/dnd-kit\"\n    }\n  },\n  \"footer\": {\n    \"socials\": {\n      \"x\": \"https://x.com/dndkit\",\n      \"github\": \"https://github.com/clauderic/dnd-kit\"\n    }\n  }\n}\n"
  },
  {
    "path": "apps/docs/extend/modifiers.mdx",
    "content": "---\ntitle: 'Modifiers'\ndescription: 'Transform and constrain drag movement.'\nicon: 'arrows-from-line'\n---\n\n## Overview\n\nModifiers transform the movement of draggable elements during drag operations. They can restrict movement to axes or boundaries, adjust positioning, or implement any custom movement logic.\n\n## Built-in Modifiers\n\n### Abstract Modifiers\n\nAvailable in `@dnd-kit/abstract/modifiers`, these modifiers are environment-agnostic:\n\n<CardGroup cols={2}>\n  <Card title=\"RestrictToHorizontalAxis\">\n    Constrain movement to the horizontal axis only\n  </Card>\n  <Card title=\"RestrictToVerticalAxis\">\n    Constrain movement to the vertical axis only\n  </Card>\n  <Card title=\"Snap\">\n    Snap movement to a grid with configurable size\n  </Card>\n</CardGroup>\n\nExample using axis restriction:\n\n```ts\nimport {RestrictToVerticalAxis} from '@dnd-kit/abstract/modifiers';\n\n// Only allow vertical movement\nconst manager = new DragDropManager({\n  modifiers: [RestrictToVerticalAxis],\n});\n```\n\nExample combining modifiers:\n\n```ts\nimport {\n  Snap,\n  RestrictToHorizontalAxis\n} from '@dnd-kit/abstract/modifiers';\n\n// Horizontal movement that snaps to a grid\nconst manager = new DragDropManager({\n  modifiers: [\n    RestrictToHorizontalAxis,\n    Snap.configure({\n      size: {\n        x: 20,  // Snap every 20px horizontally\n        y: 0    // No vertical snapping (already restricted)\n      }\n    })\n  ],\n});\n```\n\n<Info>\n  Modifiers are applied in order, so place restrictions before transformations.\n</Info>\n\n### Concrete Modifiers\n\nEnvironment-specific modifiers for the DOM, available in `@dnd-kit/dom/modifiers`:\n\n<CardGroup cols={2}>\n  <Card title=\"RestrictToWindow\">\n    Constrain movement within the window boundaries\n  </Card>\n  <Card title=\"RestrictToElement\">\n    Constrain movement within a container element\n  </Card>\n</CardGroup>\n\n## Usage\n\nModifiers can be applied globally or per draggable element. The `modifiers` option accepts either an array or a function that receives the default modifiers.\n\n### Extending defaults\n\nUse the function form to add modifiers without replacing the defaults:\n\n```ts\nimport {DragDropManager} from '@dnd-kit/dom';\nimport {RestrictToWindow} from '@dnd-kit/dom/modifiers';\n\nconst manager = new DragDropManager({\n  modifiers: (defaults) => [...defaults, RestrictToWindow],\n});\n```\n\n### Replacing defaults\n\nPass an array to fully replace the default modifiers:\n\n```ts\nimport {DragDropManager} from '@dnd-kit/dom';\nimport {RestrictToWindow} from '@dnd-kit/dom/modifiers';\n\nconst manager = new DragDropManager({\n  modifiers: [RestrictToWindow],\n});\n```\n\n### Per-draggable modifiers\n\nModifiers can also be configured on individual draggable elements:\n\n```ts\nimport {RestrictToElement} from '@dnd-kit/dom/modifiers';\n\nconst draggable = new Draggable({\n  id: 'draggable-1',\n  element,\n  modifiers: [\n    RestrictToElement.configure({\n      element: containerElement\n    })\n  ],\n}, manager);\n```\n\n<Info>\n  Local modifiers on draggable elements take precedence over global modifiers.\n</Info>\n\n## Creating Custom Modifiers\n\nCreate custom modifiers by extending the `Modifier` class:\n\n```ts\nimport {Modifier} from '@dnd-kit/abstract';\nimport type {Coordinates} from '@dnd-kit/geometry';\n\ninterface GridOptions {\n  gridSize: number;\n}\n\nclass SnapToGrid extends Modifier {\n  constructor(manager, options?: GridOptions) {\n    super(manager, options);\n  }\n\n  public apply(operation): Coordinates {\n    if (this.disabled) return operation.transform;\n\n    const {gridSize = 20} = this.options ?? {};\n    const {transform} = operation;\n\n    return {\n      x: Math.round(transform.x / gridSize) * gridSize,\n      y: Math.round(transform.y / gridSize) * gridSize,\n    };\n  }\n}\n```\n\n## Modifier Lifecycle\n\n1. **Construction**\n   - Modifier instance created\n   - Options configured\n\n2. **Application**\n   - `apply()` called during drag\n   - Transforms coordinates\n   - Can access drag operation state\n\n3. **Cleanup**\n   - Resources cleaned up on destroy\n\n## API Reference\n\n### Base Modifier Class\n\n<ParamField path=\"manager\" type=\"DragDropManager\" required>\n  Reference to the drag and drop manager instance.\n</ParamField>\n\n<ParamField path=\"options\" type=\"Record<string, any>\">\n  Optional configuration for the modifier.\n</ParamField>\n\n### Methods\n\n- `apply(operation)`: Transform drag coordinates\n- `enable()`: Enable the modifier\n- `disable()`: Disable the modifier\n- `isDisabled()`: Check if modifier is disabled\n- `destroy()`: Clean up resources\n\n### Static Methods\n\n- `configure(options)`: Create configured modifier\n\n```ts\nconst snapToGrid = SnapToGrid.configure({\n  gridSize: 10\n});\n\nconst manager = new DragDropManager({\n  modifiers: [snapToGrid]\n});\n```\n"
  },
  {
    "path": "apps/docs/extend/plugins/accessibility.mdx",
    "content": "---\ntitle: 'Accessibility'\ndescription: 'Manages ARIA attributes and screen reader announcements for drag and drop operations.'\nicon: 'universal-access'\n---\n\n## Overview\n\nThe `Accessibility` plugin provides screen reader support for drag and drop operations. It automatically manages ARIA attributes on draggable elements, provides screen reader instructions, and announces drag events via a live region.\n\nThis plugin is included by default when creating a new `DragDropManager`.\n\n## Configuration\n\nUse `Accessibility.configure()` to customize announcements, screen reader instructions, and other options:\n\n<CodeGroup>\n```ts Vanilla\nimport {DragDropManager, Accessibility} from '@dnd-kit/dom';\n\nconst manager = new DragDropManager({\n  plugins: (defaults) => [\n    ...defaults,\n    Accessibility.configure({\n      announcements: {\n        dragstart({operation: {source}}) {\n          if (!source) return;\n          return `Started dragging ${source.id}`;\n        },\n        dragover({operation: {source, target}}) {\n          if (!source || !target) return;\n          return `${source.id} is over ${target.id}`;\n        },\n        dragend({operation: {source, target}, canceled}) {\n          if (!source) return;\n          if (canceled) return `Dragging canceled`;\n          return `Dropped ${source.id} on ${target?.id ?? 'nothing'}`;\n        },\n      },\n    }),\n  ],\n});\n```\n\n```tsx React\nimport {DragDropProvider} from '@dnd-kit/react';\nimport {Accessibility} from '@dnd-kit/dom';\n\nfunction App() {\n  return (\n    <DragDropProvider\n      plugins={(defaults) => [\n        ...defaults,\n        Accessibility.configure({\n          announcements: {\n            dragstart({operation: {source}}) {\n              if (!source) return;\n              return `Started dragging ${source.id}`;\n            },\n            dragover({operation: {source, target}}) {\n              if (!source || !target) return;\n              return `${source.id} is over ${target.id}`;\n            },\n            dragend({operation: {source, target}, canceled}) {\n              if (!source) return;\n              if (canceled) return `Dragging canceled`;\n              return `Dropped ${source.id} on ${target?.id ?? 'nothing'}`;\n            },\n          },\n        }),\n      ]}\n    >\n      {/* ... */}\n    </DragDropProvider>\n  );\n}\n```\n\n```vue Vue\n<script setup>\nimport {DragDropProvider} from '@dnd-kit/vue';\nimport {Accessibility} from '@dnd-kit/dom';\n\nconst plugins = (defaults) => [\n  ...defaults,\n  Accessibility.configure({\n    announcements: {\n      dragstart({operation: {source}}) {\n        if (!source) return;\n        return `Started dragging ${source.id}`;\n      },\n      dragover({operation: {source, target}}) {\n        if (!source || !target) return;\n        return `${source.id} is over ${target.id}`;\n      },\n      dragend({operation: {source, target}, canceled}) {\n        if (!source) return;\n        if (canceled) return `Dragging canceled`;\n        return `Dropped ${source.id} on ${target?.id ?? 'nothing'}`;\n      },\n    },\n  }),\n];\n</script>\n\n<template>\n  <DragDropProvider :plugins=\"plugins\">\n    <!-- ... -->\n  </DragDropProvider>\n</template>\n```\n\n```svelte Svelte\n<script>\n  import {DragDropProvider} from '@dnd-kit/svelte';\n  import {Accessibility} from '@dnd-kit/dom';\n\n  const plugins = (defaults) => [\n    ...defaults,\n    Accessibility.configure({\n      announcements: {\n        dragstart({operation: {source}}) {\n          if (!source) return;\n          return `Started dragging ${source.id}`;\n        },\n        dragover({operation: {source, target}}) {\n          if (!source || !target) return;\n          return `${source.id} is over ${target.id}`;\n        },\n        dragend({operation: {source, target}, canceled}) {\n          if (!source) return;\n          if (canceled) return `Dragging canceled`;\n          return `Dropped ${source.id} on ${target?.id ?? 'nothing'}`;\n        },\n      },\n    }),\n  ];\n</script>\n\n<DragDropProvider {plugins}>\n  <!-- ... -->\n</DragDropProvider>\n```\n\n```tsx Solid\nimport {DragDropProvider} from '@dnd-kit/solid';\nimport {Accessibility} from '@dnd-kit/dom';\n\nfunction App() {\n  return (\n    <DragDropProvider\n      plugins={(defaults) => [\n        ...defaults,\n        Accessibility.configure({\n          announcements: {\n            dragstart({operation: {source}}) {\n              if (!source) return;\n              return `Started dragging ${source.id}`;\n            },\n            dragover({operation: {source, target}}) {\n              if (!source || !target) return;\n              return `${source.id} is over ${target.id}`;\n            },\n            dragend({operation: {source, target}, canceled}) {\n              if (!source) return;\n              if (canceled) return `Dragging canceled`;\n              return `Dropped ${source.id} on ${target?.id ?? 'nothing'}`;\n            },\n          },\n        }),\n      ]}\n    >\n      {/* ... */}\n    </DragDropProvider>\n  );\n}\n```\n</CodeGroup>\n\n## ARIA Attributes\n\nThe plugin automatically sets the following attributes on draggable activator elements (the handle or, if no handle is set, the draggable element itself):\n\n- `role=\"button\"` — unless the element is already a `<button>` or has an explicit `role`\n- `aria-roledescription=\"draggable\"`\n- `aria-describedby` — points to a hidden element containing screen reader instructions\n- `aria-pressed` and `aria-grabbed` — reflect the current dragging state\n- `aria-disabled` — reflects the disabled state of the draggable\n- `tabindex=\"0\"` — ensures the element is focusable (added when the element is not natively focusable)\n\n## Default Announcements\n\nThe plugin ships with default announcements for the `dragstart`, `dragover`, and `dragend` events:\n\n- **dragstart**: `\"Picked up draggable item {id}.\"`\n- **dragover** (over a target): `\"Draggable item {id} was moved over droppable target {targetId}.\"`\n- **dragover** (no target): `\"Draggable item {id} is no longer over a droppable target.\"`\n- **dragend** (dropped on target): `\"Draggable item {id} was dropped over droppable target {targetId}\"`\n- **dragend** (canceled): `\"Dragging was cancelled. Draggable item {id} was dropped.\"`\n- **dragend** (no target): `\"Draggable item {id} was dropped.\"`\n\n## Default Screen Reader Instructions\n\nThe default instructions read:\n\n> To pick up a draggable item, press the space bar. While dragging, use the arrow keys to move the item in a given direction. Press space again to drop the item in its new position, or press escape to cancel.\n\n## Options\n\n<ParamField path=\"announcements\" type=\"Announcements\">\n  Custom announcement functions for drag events. Each function receives the event and the `DragDropManager` instance, and returns a string to announce (or `undefined` to skip the announcement).\n\n  ```ts\n  interface Announcements {\n    dragstart: (event, manager) => string | undefined;\n    dragmove?: (event, manager) => string | undefined;\n    dragover?: (event, manager) => string | undefined;\n    dragend: (event, manager) => string | undefined;\n  }\n  ```\n</ParamField>\n\n<ParamField path=\"screenReaderInstructions\" type=\"ScreenReaderInstructions\">\n  Custom screen reader instructions displayed in a visually hidden element that is referenced by `aria-describedby` on draggable activator elements.\n\n  ```ts\n  interface ScreenReaderInstructions {\n    draggable: string;\n  }\n  ```\n</ParamField>\n\n<ParamField path=\"debounce\" type=\"number\" default=\"500\">\n  The number of milliseconds to debounce announcement updates. Only `dragover` and `dragmove` announcements are debounced; `dragstart` and `dragend` announcements are dispatched immediately.\n</ParamField>\n\n<ParamField path=\"id\" type=\"string\">\n  A stable identifier used to generate the `id` attributes for the hidden description and live region elements. When not provided, a unique id is generated automatically. Useful when you need to reference these elements from outside the plugin.\n</ParamField>\n\n<ParamField path=\"idPrefix\" type=\"{description?: string; announcement?: string}\">\n  Custom prefixes for the generated element ids.\n\n  Defaults to `{description: 'dnd-kit-description', announcement: 'dnd-kit-announcement'}`.\n</ParamField>\n"
  },
  {
    "path": "apps/docs/extend/plugins/auto-scroller.mdx",
    "content": "---\ntitle: 'AutoScroller'\ndescription: 'Automatically scrolls containers when dragging near edges.'\nicon: 'arrows-up-down'\n---\n\n## Overview\n\nThe `AutoScroller` plugin automatically scrolls scrollable containers when the pointer approaches their edges during a drag operation. It works in conjunction with the internal `Scroller` plugin that detects scrollable ancestors and computes scroll intent.\n\nThis plugin is included by default when creating a new `DragDropManager`.\n\n## Behavior\n\nWhen a drag operation is in progress and the pointer is near the edge of a scrollable container, the `AutoScroller` will:\n\n1. Detect the nearest scrollable ancestor of the element under the pointer.\n2. Compute the scroll direction and speed based on the pointer's proximity to the edge.\n3. Continuously scroll the container at the computed speed until the pointer moves away from the edge or the container can no longer scroll in that direction.\n\nThe scroll speed increases as the pointer gets closer to the edge of the container.\n\n## Configuration\n\nUse `AutoScroller.configure()` to customize the scroll speed and activation zone:\n\n<CodeGroup>\n```ts Vanilla\nimport {DragDropManager, AutoScroller} from '@dnd-kit/dom';\n\nconst manager = new DragDropManager({\n  plugins: (defaults) => [\n    ...defaults,\n    AutoScroller.configure({\n      acceleration: 15,\n      threshold: { x: 0, y: 0.3 },\n    }),\n  ],\n});\n```\n\n```tsx React\nimport {DragDropProvider} from '@dnd-kit/react';\nimport {AutoScroller} from '@dnd-kit/dom';\n\nfunction App() {\n  return (\n    <DragDropProvider\n      plugins={(defaults) => [\n        ...defaults,\n        AutoScroller.configure({\n          acceleration: 15,\n          threshold: { x: 0, y: 0.3 },\n        }),\n      ]}\n    >\n      {/* ... */}\n    </DragDropProvider>\n  );\n}\n```\n\n```vue Vue\n<script setup>\nimport {DragDropProvider} from '@dnd-kit/vue';\nimport {AutoScroller} from '@dnd-kit/dom';\n</script>\n\n<template>\n  <DragDropProvider\n    :plugins=\"(defaults) => [...defaults, AutoScroller.configure({ acceleration: 15, threshold: { x: 0, y: 0.3 } })]\"\n  >\n    <!-- ... -->\n  </DragDropProvider>\n</template>\n```\n\n```svelte Svelte\n<script>\n  import {DragDropProvider} from '@dnd-kit/svelte';\n  import {AutoScroller} from '@dnd-kit/dom';\n</script>\n\n<DragDropProvider\n  plugins={(defaults) => [...defaults, AutoScroller.configure({ acceleration: 15, threshold: { x: 0, y: 0.3 } })]}\n>\n  <!-- ... -->\n</DragDropProvider>\n```\n\n```tsx Solid\nimport {DragDropProvider} from '@dnd-kit/solid';\nimport {AutoScroller} from '@dnd-kit/dom';\n\nfunction App() {\n  return (\n    <DragDropProvider\n      plugins={(defaults) => [\n        ...defaults,\n        AutoScroller.configure({\n          acceleration: 15,\n          threshold: { x: 0, y: 0.3 },\n        }),\n      ]}\n    >\n      {/* ... */}\n    </DragDropProvider>\n  );\n}\n```\n</CodeGroup>\n\n## Options\n\n<ParamField path=\"acceleration\" type=\"number\" default=\"25\">\n  Base scroll speed multiplier. The scroll speed scales linearly as the pointer approaches the edge of a scrollable container — higher values scroll faster.\n</ParamField>\n\n<ParamField path=\"threshold\" type=\"number | { x: number; y: number }\" default=\"{ x: 0.2, y: 0.2 }\">\n  Percentage of container dimensions that defines the scroll activation zone. For example, `0.2` means scrolling activates when the pointer enters the outer 20% of a scrollable container.\n\n  A single number applies to both axes. Use `{ x, y }` for per-axis control. Setting an axis to `0` disables auto-scrolling on that axis.\n</ParamField>\n\n## Disabling\n\nTo disable auto-scrolling, omit the `AutoScroller` from the plugins array:\n\n<CodeGroup>\n```ts Vanilla\nimport {DragDropManager, AutoScroller} from '@dnd-kit/dom';\n\nconst manager = new DragDropManager({\n  plugins: (defaults) => defaults.filter((plugin) => plugin !== AutoScroller),\n});\n```\n\n```tsx React\nimport {DragDropProvider} from '@dnd-kit/react';\nimport {AutoScroller} from '@dnd-kit/dom';\n\nfunction App() {\n  return (\n    <DragDropProvider\n      plugins={(defaults) => defaults.filter((plugin) => plugin !== AutoScroller)}\n    >\n      {/* ... */}\n    </DragDropProvider>\n  );\n}\n```\n\n```vue Vue\n<script setup>\nimport {DragDropProvider} from '@dnd-kit/vue';\nimport {AutoScroller} from '@dnd-kit/dom';\n</script>\n\n<template>\n  <DragDropProvider\n    :plugins=\"(defaults) => defaults.filter((plugin) => plugin !== AutoScroller)\"\n  >\n    <!-- ... -->\n  </DragDropProvider>\n</template>\n```\n\n```svelte Svelte\n<script>\n  import {DragDropProvider} from '@dnd-kit/svelte';\n  import {AutoScroller} from '@dnd-kit/dom';\n</script>\n\n<DragDropProvider\n  plugins={(defaults) => defaults.filter((plugin) => plugin !== AutoScroller)}\n>\n  <!-- ... -->\n</DragDropProvider>\n```\n\n```tsx Solid\nimport {DragDropProvider} from '@dnd-kit/solid';\nimport {AutoScroller} from '@dnd-kit/dom';\n\nfunction App() {\n  return (\n    <DragDropProvider\n      plugins={(defaults) => defaults.filter((plugin) => plugin !== AutoScroller)}\n    >\n      {/* ... */}\n    </DragDropProvider>\n  );\n}\n```\n</CodeGroup>\n\nTo dynamically disable auto-scrolling at runtime, access the plugin instance from the manager registry and call its `disable()` method:\n\n<CodeGroup>\n```ts Vanilla\nimport {DragDropManager, AutoScroller} from '@dnd-kit/dom';\n\nconst manager = new DragDropManager();\nconst autoScroller = manager.registry.plugins.get(AutoScroller);\n\n// Disable auto-scrolling\nautoScroller.disable();\n\n// Re-enable auto-scrolling\nautoScroller.enable();\n```\n\n```tsx React\nimport {useDragDropManager} from '@dnd-kit/react';\nimport {AutoScroller} from '@dnd-kit/dom';\n\nfunction AutoScrollToggle() {\n  const manager = useDragDropManager();\n  const autoScroller = manager.registry.plugins.get(AutoScroller);\n\n  return (\n    <button onClick={() => {\n      autoScroller.disabled\n        ? autoScroller.enable()\n        : autoScroller.disable();\n    }}>\n      Toggle auto-scroll\n    </button>\n  );\n}\n```\n\n```vue Vue\n<script setup>\nimport {useDragDropManager} from '@dnd-kit/vue';\nimport {AutoScroller} from '@dnd-kit/dom';\n\nconst manager = useDragDropManager();\nconst autoScroller = manager.registry.plugins.get(AutoScroller);\n\nfunction toggle() {\n  autoScroller.disabled\n    ? autoScroller.enable()\n    : autoScroller.disable();\n}\n</script>\n\n<template>\n  <button @click=\"toggle\">Toggle auto-scroll</button>\n</template>\n```\n\n```svelte Svelte\n<script>\n  import {getDragDropManager} from '@dnd-kit/svelte';\n  import {AutoScroller} from '@dnd-kit/dom';\n\n  const manager = getDragDropManager();\n  const autoScroller = manager.registry.plugins.get(AutoScroller);\n\n  function toggle() {\n    autoScroller.disabled\n      ? autoScroller.enable()\n      : autoScroller.disable();\n  }\n</script>\n\n<button onclick={toggle}>Toggle auto-scroll</button>\n```\n\n```tsx Solid\nimport {useDragDropManager} from '@dnd-kit/solid';\nimport {AutoScroller} from '@dnd-kit/dom';\n\nfunction AutoScrollToggle() {\n  const manager = useDragDropManager();\n  const autoScroller = manager.registry.plugins.get(AutoScroller);\n\n  return (\n    <button onClick={() => {\n      autoScroller.disabled\n        ? autoScroller.enable()\n        : autoScroller.disable();\n    }}>\n      Toggle auto-scroll\n    </button>\n  );\n}\n```\n</CodeGroup>\n"
  },
  {
    "path": "apps/docs/extend/plugins/cursor.mdx",
    "content": "---\ntitle: 'Cursor'\ndescription: 'Updates cursor styles during drag operations.'\nicon: 'arrow-pointer'\n---\n\n## Overview\n\nThe `Cursor` plugin overrides the cursor style on the entire document while a drag operation is in progress, providing visual feedback that an element is being dragged.\n\nThis plugin is included by default when creating a new `DragDropManager`.\n\n## Configuration\n\nUse `Cursor.configure()` to customize the cursor style:\n\n<CodeGroup>\n```ts Vanilla\nimport {DragDropManager, Cursor} from '@dnd-kit/dom';\n\nconst manager = new DragDropManager({\n  plugins: (defaults) => [\n    ...defaults,\n    Cursor.configure({ cursor: 'move' }),\n  ],\n});\n```\n\n```tsx React\nimport {DragDropProvider} from '@dnd-kit/react';\nimport {Cursor} from '@dnd-kit/dom';\n\nfunction App() {\n  return (\n    <DragDropProvider\n      plugins={(defaults) => [\n        ...defaults,\n        Cursor.configure({ cursor: 'move' }),\n      ]}\n    >\n      {/* ... */}\n    </DragDropProvider>\n  );\n}\n```\n\n```vue Vue\n<script setup>\nimport {DragDropProvider} from '@dnd-kit/vue';\nimport {Cursor} from '@dnd-kit/dom';\n</script>\n\n<template>\n  <DragDropProvider\n    :plugins=\"(defaults) => [...defaults, Cursor.configure({ cursor: 'move' })]\"\n  >\n    <!-- ... -->\n  </DragDropProvider>\n</template>\n```\n\n```svelte Svelte\n<script>\n  import {DragDropProvider} from '@dnd-kit/svelte';\n  import {Cursor} from '@dnd-kit/dom';\n</script>\n\n<DragDropProvider\n  plugins={(defaults) => [...defaults, Cursor.configure({ cursor: 'move' })]}\n>\n  <!-- ... -->\n</DragDropProvider>\n```\n\n```tsx Solid\nimport {DragDropProvider} from '@dnd-kit/solid';\nimport {Cursor} from '@dnd-kit/dom';\n\nfunction App() {\n  return (\n    <DragDropProvider\n      plugins={(defaults) => [\n        ...defaults,\n        Cursor.configure({ cursor: 'move' }),\n      ]}\n    >\n      {/* ... */}\n    </DragDropProvider>\n  );\n}\n```\n</CodeGroup>\n\n## Options\n\n<ParamField path=\"cursor\" type=\"string\" default=\"grabbing\">\n  The CSS cursor value to apply to the document body during drag operations.\n</ParamField>\n"
  },
  {
    "path": "apps/docs/extend/plugins/debug.mdx",
    "content": "---\ntitle: 'Debug'\ndescription: 'Visualize drag and drop operations for debugging.'\nicon: 'bug'\n---\n\nimport {Story} from '/snippets/story.mdx';\n\n## Overview\n\nThe `Debug` plugin renders visual overlays that help you understand what's happening during drag and drop operations. It displays the shapes of draggable and droppable elements, highlights collision targets, and shows the current pointer position.\n\nThis plugin is **not** included by default — add it during development to help debug layout, collision, and positioning issues.\n\n## Usage\n\n<CodeGroup>\n```ts Vanilla\nimport {DragDropManager} from '@dnd-kit/dom';\nimport {Debug} from '@dnd-kit/dom/plugins/debug';\n\nconst manager = new DragDropManager({\n  plugins: (defaults) => [...defaults, Debug],\n});\n```\n\n```tsx React\nimport {DragDropProvider} from '@dnd-kit/react';\nimport {Debug} from '@dnd-kit/dom/plugins/debug';\n\nfunction App() {\n  return (\n    <DragDropProvider\n      plugins={(defaults) => [Debug, ...defaults]}\n    >\n      {/* ... */}\n    </DragDropProvider>\n  );\n}\n```\n\n```vue Vue\n<script setup>\nimport {DragDropProvider} from '@dnd-kit/vue';\nimport {Debug} from '@dnd-kit/dom/plugins/debug';\n</script>\n\n<template>\n  <DragDropProvider\n    :plugins=\"(defaults) => [Debug, ...defaults]\"\n  >\n    <!-- ... -->\n  </DragDropProvider>\n</template>\n```\n\n```svelte Svelte\n<script>\n  import {DragDropProvider} from '@dnd-kit/svelte';\n  import {Debug} from '@dnd-kit/dom/plugins/debug';\n</script>\n\n<DragDropProvider\n  plugins={(defaults) => [Debug, ...defaults]}\n>\n  <!-- ... -->\n</DragDropProvider>\n```\n\n```tsx Solid\nimport {DragDropProvider} from '@dnd-kit/solid';\nimport {Debug} from '@dnd-kit/dom/plugins/debug';\n\nfunction App() {\n  return (\n    <DragDropProvider\n      plugins={(defaults) => [Debug, ...defaults]}\n    >\n      {/* ... */}\n    </DragDropProvider>\n  );\n}\n```\n</CodeGroup>\n\n<Warning>\n  The `Debug` plugin is intended for development only. Remove it before shipping to production.\n</Warning>\n\n## Example\n\n<Story id=\"react-sortable-vertical-list--debug\" height=\"320\" />\n\n## What It Shows\n\n- **Draggable shape** (blue overlay): The computed bounding rectangle of the element being dragged.\n- **Droppable zones** (gray overlays): The bounding rectangles of all registered droppable elements.\n- **Drop target** (green overlay): The current drop target.\n- **Top collisions** (yellow overlays): The next closest collision candidates.\n- **Pointer crosshair**: The current pointer position tracked by the drag operation.\n"
  },
  {
    "path": "apps/docs/extend/plugins/feedback.mdx",
    "content": "---\ntitle: 'Feedback'\ndescription: 'Manages visual feedback during drag operations, including top layer promotion and drop animations.'\nicon: 'eye'\n---\n\n## Overview\n\nThe `Feedback` plugin manages the visual appearance of elements during drag operations. It promotes dragged elements to the browser's [top layer](https://developer.mozilla.org/en-US/docs/Glossary/Top_layer) using the [Popover API](https://developer.mozilla.org/en-US/docs/Web/API/Popover_API), and injects CSS rules to handle positioning and to reset browser default popover styles.\n\nThis plugin is included by default when creating a new `DragDropManager`.\n\n## Configuration\n\nUse `Feedback.configure()` to customize the drop animation or other options:\n\n<CodeGroup>\n```ts Vanilla\nimport {DragDropManager, Feedback} from '@dnd-kit/dom';\n\nconst manager = new DragDropManager({\n  plugins: (defaults) => [\n    ...defaults,\n    Feedback.configure({ dropAnimation: null }),\n  ],\n});\n```\n\n```tsx React\nimport {DragDropProvider} from '@dnd-kit/react';\nimport {Feedback} from '@dnd-kit/dom';\n\nfunction App() {\n  return (\n    <DragDropProvider\n      plugins={(defaults) => [\n        ...defaults,\n        Feedback.configure({ dropAnimation: null }),\n      ]}\n    >\n      {/* ... */}\n    </DragDropProvider>\n  );\n}\n```\n\n```vue Vue\n<script setup>\nimport {DragDropProvider} from '@dnd-kit/vue';\nimport {Feedback} from '@dnd-kit/dom';\n</script>\n\n<template>\n  <DragDropProvider\n    :plugins=\"(defaults) => [...defaults, Feedback.configure({ dropAnimation: null })]\"\n  >\n    <!-- ... -->\n  </DragDropProvider>\n</template>\n```\n\n```svelte Svelte\n<script>\n  import {DragDropProvider} from '@dnd-kit/svelte';\n  import {Feedback} from '@dnd-kit/dom';\n</script>\n\n<DragDropProvider\n  plugins={(defaults) => [...defaults, Feedback.configure({ dropAnimation: null })]}\n>\n  <!-- ... -->\n</DragDropProvider>\n```\n\n```tsx Solid\nimport {DragDropProvider} from '@dnd-kit/solid';\nimport {Feedback} from '@dnd-kit/dom';\n\nfunction App() {\n  return (\n    <DragDropProvider\n      plugins={(defaults) => [\n        ...defaults,\n        Feedback.configure({ dropAnimation: null }),\n      ]}\n    >\n      {/* ... */}\n    </DragDropProvider>\n  );\n}\n```\n</CodeGroup>\n\n## Per-entity configuration\n\nIn addition to global configuration on the `DragDropManager`, you can configure the Feedback plugin on individual draggable or sortable entities using `Feedback.configure()` in the entity's `plugins` array. Per-entity options override the global configuration for that entity.\n\n<CodeGroup>\n```tsx React\nimport {useDraggable} from '@dnd-kit/react';\nimport {Feedback} from '@dnd-kit/dom';\n\nfunction Draggable({id}) {\n  const {ref} = useDraggable({\n    id,\n    plugins: [\n      Feedback.configure({\n        feedback: 'clone',\n        dropAnimation: null,\n      }),\n    ],\n  });\n\n  return <button ref={ref}>Draggable</button>;\n}\n```\n\n```ts Vanilla\nimport {Draggable, Feedback} from '@dnd-kit/dom';\n\nconst draggable = new Draggable({\n  id: 'draggable-1',\n  element,\n  plugins: [\n    Feedback.configure({\n      feedback: 'clone',\n      dropAnimation: null,\n    }),\n  ],\n}, manager);\n```\n</CodeGroup>\n\n### Per-entity options\n\n<ParamField path=\"feedback\" type=\"FeedbackType\">\n  The type of visual feedback to show during drag for this entity.\n\n  - `'default'` — the original element moves with the drag\n  - `'clone'` — a copy of the element stays in place while the original moves\n  - `'move'` — the element moves without a placeholder\n  - `'none'` — no visual feedback (useful for custom drag overlays)\n</ParamField>\n\n<ParamField path=\"dropAnimation\" type=\"DropAnimation | null\">\n  Customize or disable the drop animation for this entity. Overrides the global `dropAnimation` option.\n</ParamField>\n\n## Global options\n\n<ParamField path=\"dropAnimation\" type=\"DropAnimation | null\">\n  Customize or disable the drop animation that plays when a dragged element is released.\n\n  - `undefined` (default) — use the built-in drop animation\n  - `null` — disable the drop animation entirely\n  - `DropAnimationOptions` — customize the duration and easing of the built-in animation\n  - `DropAnimationFunction` — provide a fully custom animation function\n</ParamField>\n\n<ParamField path=\"keyboardTransition\" type=\"KeyboardTransition | null\">\n  Customize or disable the CSS transition applied when moving elements via keyboard.\n\n  By default, keyboard-driven moves animate with `250ms cubic-bezier(0.25, 1, 0.5, 1)`. This transition is automatically disabled when the user prefers reduced motion.\n\n  - `undefined` (default) — use the built-in keyboard transition\n  - `null` — disable the transition (moves are instant, like pointer operations)\n  - `{ duration, easing }` — customize the transition duration (in ms) and CSS easing function\n</ParamField>\n\n<ParamField path=\"rootElement\" type=\"Element | ((source: Draggable) => Element)\">\n  An element (or a function returning one) to use as the root container for the dragged element. When set, the dragged element is moved into this container during the drag operation.\n</ParamField>\n\n## CSS Cascade Layer\n\nThe Feedback plugin uses a CSS cascade layer named `dnd-kit` to reset user-agent popover styles (such as `background`, `border`, `margin`, and `padding`) that browsers apply to elements promoted to the top layer.\n\nBy default, this layer is injected at the beginning of the document's `<head>`, giving it the lowest cascade priority. This means your styles will take precedence without needing `!important`.\n\nIf you use a CSS framework that defines its own cascade layers (such as Tailwind CSS v4), you can explicitly declare the `dnd-kit` layer first to ensure it has the lowest priority:\n\n```css\n@layer dnd-kit, base, components, utilities;\n```\n"
  },
  {
    "path": "apps/docs/extend/plugins/style-injector.mdx",
    "content": "---\ntitle: 'StyleInjector'\ndescription: 'Centralized style injection for drag and drop operations.'\nicon: 'palette'\n---\n\n## Overview\n\nThe `StyleInjector` plugin is the centralized style injection layer used by dnd-kit. It manages CSS rules that need to be present during drag operations, handling injection into both `Document` and `ShadowRoot` contexts.\n\nThis plugin is always included automatically — you do not need to add it to your plugins array.\n\n## How It Works\n\nOther plugins (such as [Feedback](/extend/plugins/feedback)) register CSS rules with the `StyleInjector`. During a drag operation, the `StyleInjector` automatically injects those rules into the relevant document and shadow roots, and cleans them up when the operation ends.\n\n### Document Roots\n\nFor `Document` roots, CSS is injected via a `<style>` element prepended to `<head>`. This ensures that any `@layer` declarations appear before layers from regular stylesheets, giving them the lowest cascade priority.\n\nA `MutationObserver` monitors the `<head>` to re-inject the `<style>` element if it is removed by other scripts during a drag operation.\n\n### Shadow DOM Roots\n\nFor `ShadowRoot` roots, CSS is injected via [`adoptedStyleSheets`](https://developer.mozilla.org/en-US/docs/Web/API/Document/adoptedStyleSheets) to avoid DOM side effects like interfering with `:first-child` or `:nth-child` selectors inside the shadow tree.\n\n## Configuration\n\nUse `StyleInjector.configure()` to set a CSP nonce that will be applied to all injected `<style>` elements:\n\n<CodeGroup>\n```ts Vanilla\nimport {DragDropManager, StyleInjector} from '@dnd-kit/dom';\n\nconst manager = new DragDropManager({\n  plugins: (defaults) => [\n    ...defaults,\n    StyleInjector.configure({ nonce: 'abc123' }),\n  ],\n});\n```\n\n```tsx React\nimport {DragDropProvider} from '@dnd-kit/react';\nimport {StyleInjector} from '@dnd-kit/dom';\n\nfunction App() {\n  return (\n    <DragDropProvider\n      plugins={(defaults) => [\n        ...defaults,\n        StyleInjector.configure({ nonce: 'abc123' }),\n      ]}\n    >\n      {/* ... */}\n    </DragDropProvider>\n  );\n}\n```\n\n```vue Vue\n<script setup>\nimport {DragDropProvider} from '@dnd-kit/vue';\nimport {StyleInjector} from '@dnd-kit/dom';\n</script>\n\n<template>\n  <DragDropProvider\n    :plugins=\"(defaults) => [...defaults, StyleInjector.configure({ nonce: 'abc123' })]\"\n  >\n    <!-- ... -->\n  </DragDropProvider>\n</template>\n```\n\n```svelte Svelte\n<script>\n  import {DragDropProvider} from '@dnd-kit/svelte';\n  import {StyleInjector} from '@dnd-kit/dom';\n</script>\n\n<DragDropProvider\n  plugins={(defaults) => [...defaults, StyleInjector.configure({ nonce: 'abc123' })]}\n>\n  <!-- ... -->\n</DragDropProvider>\n```\n\n```tsx Solid\nimport {DragDropProvider} from '@dnd-kit/solid';\nimport {StyleInjector} from '@dnd-kit/dom';\n\nfunction App() {\n  return (\n    <DragDropProvider\n      plugins={(defaults) => [\n        ...defaults,\n        StyleInjector.configure({ nonce: 'abc123' }),\n      ]}\n    >\n      {/* ... */}\n    </DragDropProvider>\n  );\n}\n```\n</CodeGroup>\n\n<Info>\n  The `StyleInjector` is the single place to configure CSP nonces. All built-in plugins that inject styles (such as [Feedback](/extend/plugins/feedback), [Cursor](/extend/plugins/cursor), and [PreventSelection](/extend/plugins/prevent-selection)) route their style injection through the `StyleInjector`.\n</Info>\n\n## Options\n\n<ParamField path=\"nonce\" type=\"string\">\n  A nonce value applied to all `<style>` elements injected into `Document` roots. Required when your site uses a [Content Security Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP) that restricts inline styles.\n</ParamField>\n\n## API\n\n### `register(cssRules: string)`\n\nRegisters CSS rules to be injected into the active drag operation's document and shadow roots. Returns a cleanup function that unregisters the rules.\n\n```ts\nconst styleInjector = manager.registry.plugins.get(StyleInjector);\n\nconst unregister = styleInjector.register(`\n  .my-drag-styles { opacity: 0.5; }\n`);\n\n// Later, when no longer needed:\nunregister();\n```\n\n### `addRoot(root: Document | ShadowRoot)`\n\nAdds an additional root to track for style injection. This is useful when a dragged element is rendered in a different document or shadow root than the drag source. Returns a cleanup function that removes the root.\n\n```ts\nconst removeRoot = styleInjector.addRoot(shadowRoot);\n\n// Later:\nremoveRoot();\n```\n"
  },
  {
    "path": "apps/docs/extend/plugins.mdx",
    "content": "---\ntitle: 'Plugins'\ndescription: 'Extend beyond the core functionality with plugins.'\nsidebarTitle: 'Overview'\n---\n\n## Overview\n\nPlugins are a powerful way to extend the core functionality of @dnd-kit. They can be used to add new features, modify existing behavior, or react to drag and drop operations.\n\n## Built-in Plugins\n\nSeveral plugins are included by default when creating a new `DragDropManager`:\n\n<CardGroup cols={2}>\n  <Card\n    title=\"Accessibility\"\n    icon=\"universal-access\"\n    href=\"./plugins/accessibility\"\n  >\n    Manages ARIA attributes and screen reader announcements for drag and drop operations.\n  </Card>\n  <Card\n    title=\"AutoScroller\"\n    icon=\"arrows-up-down\"\n    href=\"./plugins/auto-scroller\"\n  >\n    Automatically scrolls containers when dragging near edges.\n  </Card>\n  <Card\n    title=\"Cursor\"\n    icon=\"arrow-pointer\"\n    href=\"./plugins/cursor\"\n  >\n    Updates cursor styles during drag operations.\n  </Card>\n  <Card\n    title=\"Debug\"\n    icon=\"bug\"\n    href=\"./plugins/debug\"\n  >\n    Visualize drag shapes, droppable zones, and collisions for debugging.\n  </Card>\n  <Card\n    title=\"Feedback\"\n    icon=\"eye\"\n    href=\"./plugins/feedback\"\n  >\n    Manages visual feedback during dragging, including top layer promotion and drop animations.\n  </Card>\n  <Card\n    title=\"StyleInjector\"\n    icon=\"palette\"\n    href=\"./plugins/style-injector\"\n  >\n    Centralized style injection with CSP nonce support.\n  </Card>\n</CardGroup>\n\n## Using Plugins\n\nThe `plugins` option accepts either an array or a function that receives the default plugins.\n\n### Extending defaults\n\nUse the function form to add plugins to the defaults or configure existing ones, without replacing them:\n\n```ts\nimport {DragDropManager} from '@dnd-kit/dom';\n\nconst manager = new DragDropManager({\n  plugins: (defaults) => [...defaults, MyPlugin],\n});\n```\n\n```ts\nimport {DragDropManager, Feedback} from '@dnd-kit/dom';\n\nconst manager = new DragDropManager({\n  plugins: (defaults) => [\n    ...defaults,\n    Feedback.configure({ dropAnimation: null }),\n  ],\n});\n```\n\n### Replacing defaults\n\nPass an array to fully replace the default plugins:\n\n```ts\nconst manager = new DragDropManager({\n  plugins: [\n    MyPlugin.configure({ delay: 500 }),\n    AutoScroller,\n  ]\n});\n```\n\n## Creating a Plugin\n\nTo create a custom plugin, extend the `Plugin` class:\n\n```ts\nimport {Plugin} from '@dnd-kit/abstract';\n\ninterface MyPluginOptions {\n  delay?: number;\n}\n\nclass MyPlugin extends Plugin {\n  constructor(manager, options?: MyPluginOptions) {\n    super(manager, options);\n\n    this.registerEffect(() => {\n      const {monitor} = this.manager;\n\n      const cleanup = monitor.addEventListener('dragstart', (event) => {\n        console.log('Drag started:', event.operation.source.id);\n      });\n\n      return cleanup;\n    });\n  }\n\n  public customMethod() {\n    if (this.disabled) return;\n    // Custom functionality\n  }\n}\n```\n\n## Plugin Lifecycle\n\n1. **Construction**: Plugin instance created with manager reference\n2. **Configuration**: Options applied if provided\n3. **Registration**: Plugin registered with manager\n4. **Operation**: Plugin effects are run\n5. **Cleanup**: Plugin destroyed when manager is destroyed\n\n## API Reference\n\n### Plugin Class\n\nThe base class for all plugins:\n\n<ParamField path=\"manager\" type=\"DragDropManager\" required>\n  Reference to the drag and drop manager instance.\n</ParamField>\n\n<ParamField path=\"options\" type=\"PluginOptions\">\n  Optional configuration options for the plugin.\n</ParamField>\n\n### Properties\n\n- `disabled`: Whether the plugin is currently disabled\n- `options`: Current plugin options\n\n### Methods\n\n- `enable()`: Enable the plugin\n- `disable()`: Disable the plugin\n- `isDisabled()`: Check if plugin is disabled\n- `configure(options)`: Update plugin options\n- `destroy()`: Clean up plugin resources\n- `registerEffect(callback)`: Register a reactive effect\n\n### Static Methods\n\n- `configure(options)`: Create a configured plugin descriptor\n\n```ts\nconst configuredPlugin = MyPlugin.configure({\n  delay: 500\n});\n\nconst manager = new DragDropManager({\n  plugins: [configuredPlugin]\n});\n```\n\n### Effects\n\nPlugins can register effects that automatically clean up:\n\n```ts\nclass MyPlugin extends Plugin {\n  constructor(manager) {\n    super(manager);\n\n    this.registerEffect(() => {\n      const interval = setInterval(() => {\n        // Do something periodically\n      }, 100);\n\n      return () => clearInterval(interval);\n    });\n  }\n}\n```\n\n### Best Practices\n\n1. **Clean Up Resources**: Always clean up listeners and timers in the `destroy` method\n2. **Check Disabled State**: Check `this.disabled` before performing operations\n3. **Use Type Safety**: Leverage TypeScript for better type checking\n4. **Document Options**: Clearly document all available options\n5. **Follow Patterns**: Study built-in plugins for patterns and conventions\n"
  },
  {
    "path": "apps/docs/extend/sensors/keyboard-sensor.mdx",
    "content": "---\ntitle: 'Keyboard Sensor'\ndescription: 'Detect keyboard input to initiate drag and drop operations.'\nicon: 'keyboard'\n---\n\n## Overview\n\nThe Keyboard sensor enables keyboard-based drag and drop interactions. It is enabled by default in the [DragDropManager](/concepts/drag-drop-manager).\n\n## Usage\n\n```ts\nimport {DragDropManager} from '@dnd-kit/dom';\nimport {KeyboardSensor} from '@dnd-kit/dom/sensors';\n\nconst manager = new DragDropManager({\n  sensors: [\n    KeyboardSensor.configure({\n      keyboardCodes: {\n        start: ['Space', 'Enter'],\n        cancel: ['Escape'],\n        end: ['Space', 'Enter'],\n        up: ['ArrowUp'],\n        down: ['ArrowDown'],\n        left: ['ArrowLeft'],\n        right: ['ArrowRight'],\n      },\n    }),\n  ],\n});\n```\n\n## Default Key Bindings\n\nThe Keyboard sensor comes with these default key bindings:\n\n```ts\nconst defaultKeyboardCodes = {\n  start: ['Space', 'Enter'],    // Start dragging\n  cancel: ['Escape'],           // Cancel drag operation\n  end: ['Space', 'Enter'],      // End dragging\n  up: ['ArrowUp'],             // Move up\n  down: ['ArrowDown'],         // Move down\n  left: ['ArrowLeft'],         // Move left\n  right: ['ArrowRight'],       // Move right\n};\n```\n\n## Customizing Key Bindings\n\nYou can customize which keys trigger different actions:\n\n```ts\nKeyboardSensor.configure({\n  keyboardCodes: {\n    // Use Tab to start/end dragging\n    start: ['Tab'],\n    end: ['Tab'],\n\n    // Use WASD for movement\n    up: ['KeyW'],\n    down: ['KeyS'],\n    left: ['KeyA'],\n    right: ['KeyD'],\n\n    // Additional cancel keys\n    cancel: ['Escape', 'KeyQ'],\n  },\n});\n```\n\n## Default behavior\n\nBy default, each key press moves the dragged item by 10 pixels. Hold <kbd>Shift</kbd> to move by 50 pixels instead.\n\n## API Reference\n\n### Options\n\n<ParamField path=\"keyboardCodes\" type=\"KeyboardCodes\">\n  Configure which keyboard codes trigger different actions:\n\n  ```ts\n  interface KeyboardCodes {\n    start: KeyCode[];    // Start dragging\n    cancel: KeyCode[];   // Cancel operation\n    end: KeyCode[];      // End dragging\n    up: KeyCode[];       // Move up\n    down: KeyCode[];     // Move down\n    left: KeyCode[];     // Move left\n    right: KeyCode[];    // Move right\n  }\n\n  type KeyCode = KeyboardEvent['code'];\n  ```\n</ParamField>\n\n### Events\n\nThe Keyboard sensor handles these events:\n\n- `keydown`: Key press detection\n- `keyup`: Key release detection\n\n### Activation\n\nThe sensor activates when:\n1. A draggable element or its handle has focus\n2. A configured start key is pressed\n3. The element isn't disabled\n\n### Best Practices\n\n1. Provide clear focus indicators:\n   - Use visible focus rings\n   - Maintain sufficient contrast\n\n2. Support screen readers:\n   - Use proper ARIA attributes\n   - Provide clear instructions\n\n3. Consider key combinations:\n   - Avoid conflicts with browser shortcuts\n   - Support standard keyboard patterns\n"
  },
  {
    "path": "apps/docs/extend/sensors/pointer-sensor.mdx",
    "content": "---\ntitle: 'Pointer Sensor'\ndescription: 'Detect pointer events to initiate drag and drop operations.'\nicon: 'arrow-pointer'\n---\n\n## Overview\n\nThe Pointer sensor responds to [Pointer events](https://developer.mozilla.org/en-US/docs/Web/API/Pointer_events) for mouse, touch, and pen input. It is enabled by default in the [DragDropManager](/concepts/drag-drop-manager).\n\n## Usage\n\n```ts\nimport {DragDropManager} from '@dnd-kit/dom';\nimport {PointerSensor, PointerActivationConstraints} from '@dnd-kit/dom';\n\nconst manager = new DragDropManager({\n  sensors: [\n    PointerSensor.configure({\n      activationConstraints: [\n        // Start dragging after moving 5px\n        new PointerActivationConstraints.Distance({value: 5}),\n        // Or after holding for 200ms with 10px tolerance\n        new PointerActivationConstraints.Delay({value: 200, tolerance: 10}),\n      ],\n    }),\n  ],\n});\n```\n\n## Activation Constraints\n\nThe Pointer sensor supports composable activation constraints through the `PointerActivationConstraints` class. Multiple constraints can be combined to create sophisticated activation behaviors.\n\n### Distance Constraint\n\nActivates dragging after the pointer moves a certain distance:\n\n```ts\nimport {PointerActivationConstraints} from '@dnd-kit/dom';\n\nPointerSensor.configure({\n  activationConstraints: [\n    new PointerActivationConstraints.Distance({\n      // Required distance in pixels\n      value: 5,\n      // Optional tolerance - aborts if exceeded\n      tolerance: 10,\n    }),\n  ],\n});\n```\n\nThe `tolerance` option defines a movement threshold that, if exceeded, will abort the activation. This is useful for distinguishing between intentional drags and accidental movements.\n\n### Delay Constraint\n\nActivates dragging after holding the pointer for a duration:\n\n```ts\nimport {PointerActivationConstraints} from '@dnd-kit/dom';\n\nPointerSensor.configure({\n  activationConstraints: [\n    new PointerActivationConstraints.Delay({\n      // Required hold duration in ms\n      value: 200,\n      // Movement tolerance during delay (in pixels)\n      tolerance: 5,\n    }),\n  ],\n});\n```\n\nThe `tolerance` option specifies how much the pointer can move during the delay period before the activation is aborted.\n\n### Combining Constraints\n\nMultiple constraints can be combined in an array. The drag operation activates when any constraint is satisfied:\n\n```ts\nPointerSensor.configure({\n  activationConstraints: [\n    // Activate after 200ms delay OR 5px movement\n    new PointerActivationConstraints.Delay({value: 200, tolerance: 10}),\n    new PointerActivationConstraints.Distance({value: 5}),\n  ],\n});\n```\n\n## Default Behavior\n\nBy default, the Pointer sensor uses different activation constraints based on the pointer type and context:\n\n- **Mouse on handle**: Immediate activation\n- **Touch**: 250ms delay with 5px tolerance\n- **Text inputs**: 200ms delay with 0px tolerance\n- **Other pointers**: 200ms delay with 10px tolerance + 5px distance\n\nYou can customize this behavior by providing a function that returns constraints based on the event and source:\n\n```ts\nimport {PointerActivationConstraints} from '@dnd-kit/dom';\n\nPointerSensor.configure({\n  activationConstraints(event, source) {\n    const {pointerType, target} = event;\n\n    // Custom constraints based on pointer type\n    switch (pointerType) {\n      case 'mouse':\n        return [\n          new PointerActivationConstraints.Distance({value: 5}),\n        ];\n      case 'touch':\n        return [\n          new PointerActivationConstraints.Delay({value: 250, tolerance: 5}),\n        ];\n      default:\n        return [\n          new PointerActivationConstraints.Delay({value: 200, tolerance: 10}),\n          new PointerActivationConstraints.Distance({value: 5}),\n        ];\n    }\n  },\n});\n```\n\n## API Reference\n\n### Options\n\n<ParamField path=\"activationConstraints\" type=\"ActivationConstraints&lt;PointerEvent&gt; | (event: PointerEvent, source: Draggable) =&gt; ActivationConstraints&lt;PointerEvent&gt;\">\n  Configure when dragging should start using an array of constraint instances:\n\n  ```ts\n  import {PointerActivationConstraints} from '@dnd-kit/dom';\n\n  // Array of constraint instances\n  type ActivationConstraints<E extends Event> = ActivationConstraint<E>[];\n\n  // Distance type\n  type Distance = number | {x?: number; y?: number};\n\n  // Distance constraint\n  new PointerActivationConstraints.Distance({\n    value: number;        // Required distance in pixels\n    tolerance?: Distance; // Optional abort threshold\n  });\n\n  // Delay constraint\n  new PointerActivationConstraints.Delay({\n    value: number;        // Required duration in ms\n    tolerance: Distance;  // Movement tolerance\n  });\n  ```\n\n  Can be a fixed array of constraints or a function that returns constraints based on the event and source.\n</ParamField>\n\n### Built-in constraints\n\nThe `PointerActivationConstraints` class provides built-in constraint primitives. You can also create your own custom activation constraints by extending the `ActivationConstraint` class.\n\n#### Distance\n\nActivates dragging after the pointer moves a certain distance.\n\n##### Options for `Distance`\n\n<ParamField path=\"value\" type=\"number\" required>\n  Required distance in pixels.\n</ParamField>\n\n<ParamField path=\"tolerance\" type=\"number | {x?: number; y?: number}\" optional>\n  If specified, aborts activation if movement exceeds this threshold. Can be a number or an object with optional x and y properties.\n</ParamField>\n\n#### Delay\n\nActivates dragging after holding the pointer for a duration.\n\n##### Options\n\n<ParamField path=\"value\" type=\"number\" required>\n  Required hold duration in milliseconds.\n</ParamField>\n\n<ParamField path=\"tolerance\" type=\"number | {x?: number; y?: number}\" optional>\n  Maximum movement allowed during delay. Can be a number or an object with optional x and y properties. Exceeding this aborts activation.\n</ParamField>\n\n### Events\n\nThe Pointer sensor handles these events:\n\n- `pointerdown`: Initial pointer contact\n- `pointermove`: Pointer movement\n- `pointerup`: Pointer release\n\nThe sensor automatically binds listeners across all same-origin documents, enabling drag operations across same-origin iframes.\n\n### Best Practices\n\n1. Use appropriate constraints for different input types:\n   - Shorter delays for mouse\n   - Longer delays with tolerance for touch\n   - Distance constraints for precision\n\n2. Consider accessibility:\n   - Don't rely solely on hover\n   - Provide clear activation feedback\n   - Support keyboard input via [KeyboardSensor](/extend/sensors/keyboard-sensor)\n\n"
  },
  {
    "path": "apps/docs/extend/sensors.mdx",
    "content": "---\ntitle: 'Sensors'\ndescription: 'Detect user input and translate it into drag and drop operations.'\nsidebarTitle: 'Overview'\n---\n\n## Overview\n\nSensors detect user input and translate it into drag and drop operations. They handle the initiation, movement, and completion of drag operations from different input sources.\n\n## Built-in Sensors\n\nThe `@dnd-kit/dom` package provides a set of built-in sensors that can be used to detect user input in the browser:\n\n<CardGroup cols={2}>\n  <Card\n    title=\"Pointer\"\n    icon=\"arrow-pointer\"\n    href=\"./sensors/pointer-sensor\"\n  >\n    Handles mouse, touch, and pen input with configurable activation constraints.\n  </Card>\n  <Card\n    title=\"Keyboard\"\n    icon=\"keyboard\"\n    href=\"./sensors/keyboard-sensor\"\n  >\n    Enables keyboard navigation and activation using customizable key bindings.\n  </Card>\n</CardGroup>\n\n## Usage\n\nSensors can be configured both globally and per draggable element. The `sensors` option accepts either an array or a function that receives the default sensors.\n\n### Extending defaults\n\nUse the function form to configure or add sensors without replacing the defaults:\n\n```ts\nimport {DragDropManager} from '@dnd-kit/dom';\nimport {PointerSensor, PointerActivationConstraints} from '@dnd-kit/dom';\n\nconst manager = new DragDropManager({\n  sensors: (defaults) => [\n    ...defaults,\n    PointerSensor.configure({\n      activationConstraints: [\n        new PointerActivationConstraints.Distance({value: 5}),\n      ],\n    }),\n  ],\n});\n```\n\n### Replacing defaults\n\nPass an array to fully replace the default sensors:\n\n```ts\nimport {DragDropManager} from '@dnd-kit/dom';\nimport {\n  PointerSensor,\n  PointerActivationConstraints,\n  KeyboardSensor\n} from '@dnd-kit/dom';\n\nconst manager = new DragDropManager({\n  sensors: [\n    PointerSensor.configure({\n      activationConstraints: [\n        new PointerActivationConstraints.Distance({value: 5}),\n        new PointerActivationConstraints.Delay({\n          value: 200,\n          tolerance: {x: 10, y: 5},\n        }),\n      ]\n    }),\n    KeyboardSensor,\n  ]\n});\n```\n\n### Per-draggable sensors\n\nSensors can also be configured on individual draggable elements:\n\n```ts\nconst draggable = new Draggable({\n  id: 'draggable-1',\n  element,\n  sensors: [KeyboardSensor],\n}, manager);\n```\n\n<Info>\n  Local sensors configured on individual draggable elements take precedence over global sensors.\n</Info>\n\n## Creating Custom Sensors\n\nYou can create custom sensors by extending the `Sensor` class:\n\n```ts\nimport {Sensor} from '@dnd-kit/abstract';\n\ninterface CustomSensorOptions {\n  delay?: number;\n}\n\nclass CustomSensor extends Sensor {\n  constructor(manager, options?: CustomSensorOptions) {\n    super(manager, options);\n  }\n\n  public bind(source) {\n    // Register event listeners\n    const unbind = this.registerEffect(() => {\n      const target = source.handle ?? source.element;\n\n      if (!target) return;\n\n      const handleStart = (event) => {\n        if (this.disabled) return;\n\n        this.manager.actions.setDragSource(source.id);\n        this.manager.actions.start({\n          event,\n          coordinates: getCoordinates(event)\n        });\n      };\n\n      target.addEventListener('customstart', handleStart);\n\n      return () => {\n        target.removeEventListener('customstart', handleStart);\n      };\n    });\n\n    return unbind;\n  }\n}\n```\n\n## Sensor Lifecycle\n\n1. **Construction**\n   - Sensor instance created\n   - Options configured\n   - Initial setup performed\n\n2. **Binding**\n   - Sensor bound to draggable element\n   - Event listeners registered\n   - Effects set up\n\n3. **Operation**\n   - Input detected\n   - Coordinates tracked\n   - Drag operations managed\n\n4. **Cleanup**\n   - Event listeners removed\n   - Effects cleaned up\n   - Resources released\n\n## API Reference\n\n### Base Sensor Class\n\n<ParamField path=\"manager\" type=\"DragDropManager\" required>\n  Reference to the drag and drop manager instance.\n</ParamField>\n\n<ParamField path=\"options\" type=\"SensorOptions\">\n  Optional configuration options for the sensor.\n</ParamField>\n\n### Methods\n\n- `bind(source: Draggable)`: Bind sensor to draggable element\n- `enable()`: Enable the sensor\n- `disable()`: Disable the sensor\n- `isDisabled()`: Check if sensor is disabled\n- `destroy()`: Clean up sensor resources\n\n### Static Methods\n\n- `configure(options)`: Create a configured sensor descriptor\n\n```ts\nconst configuredSensor = CustomSensor.configure({\n  delay: 500\n});\n\nconst manager = new DragDropManager({\n  sensors: [configuredSensor]\n});\n```\n"
  },
  {
    "path": "apps/docs/legacy/api-documentation/context-provider/collision-detection-algorithms.mdx",
    "content": "---\ntitle: Collision detection algorithms\n---\n\nIf you're familiar with how 2D games are built, you may have come across the notion of collision detection algorithms.\n\nOne of the simpler forms of collision detection is between two rectangles that are axis aligned — meaning rectangles that are not rotated. This form of collision detection is generally referred to as [Axis-Aligned Bounding Box](https://developer.mozilla.org/en-US/docs/Games/Techniques/2D_collision_detection#Axis-Aligned_Bounding_Box) (AABB).\n\nThe built-in collision detection algorithms assume a rectangular bounding box.\n\n> The bounding box of an element is the smallest possible rectangle (aligned with the axes of that element's user coordinate system) that entirely encloses it and its descendants.\\\n> – Source: [MDN](https://developer.mozilla.org/en-US/docs/Glossary/bounding_box)\n\nThis means that even if the draggable or droppable nodes look round or triangular, their bounding boxes will still be rectangular:\n\n![Axis-aligned bounding boxes](/images/legacy/axis-aligned-rectangle.png)\n\nIf you'd like to use other shapes than rectangles for detecting collisions, build your own [custom collision detection algorithm](./collision-detection-algorithms#custom-collision-detection-strategies).\n\n## Rectangle intersection\n\nBy default, [`DndContext`](./dnd-context) uses the **rectangle intersection** collision detection algorithm.\n\nThe algorithm works by ensuring there is no gap between any of the 4 sides of the rectangles. Any gap means a collision does not exist.\n\nThis means that in order for a draggable item to be considered **over** a droppable area, there needs to be an intersection between both rectangles:\n\n![Rectangle intersection](/images/legacy/rectangle-intersection.png)\n\n## Closest center\n\nWhile the rectangle intersection algorithm is well suited for most drag and drop use cases, it can be unforgiving, since it requires both the draggable and droppable bounding rectangles to come into direct contact and intersect.\n\nFor some use cases, such as [sortable](../../presets/sortable/) lists, using a more forgiving collision detection algorithm is recommended.\n\nAs its name suggests, the closest center algorithm finds the droppable container who's center is closest to the center of the bounding rectangle of the active draggable item:\n\n![Closest center](/images/legacy/closest-center.png)\n\n## Closest corners\n\nLike to the closest center algorithm, the closest corner algorithm doesn't require the draggable and droppable rectangles to intersect.\n\nRather, it measures the distance between all four corners of the active draggable item and the four corners of each droppable container to find the closest one.\n\n![Closest corners](/images/legacy/closest-corners.png)\n\nThe distance is measured from the top left corner of the draggable item to the top left corner of the droppable bounding rectangle, top right to top right, bottom left to bottom left, and bottom right to bottom right.\n\n### **When should I use the closest corners algorithm instead of closest center?**\n\nIn most cases, the **closest center** algorithm works well, and is generally the recommended default for sortable lists because it provides a more forgiving experience than the **rectangle intersection algorithm**.\n\nIn general, the closest center and closest corners algorithms will yield the same results. However, when building interfaces where droppable containers are stacked on top of one another, for example, when building a Kanban, the closest center algorithm can sometimes return the underlaying droppable of the entire Kanban column rather than the droppable areas within that column.\n\n![Closest center is 'A', though the human eye would likely expect 'A2'](/images/legacy/closest-center-kanban.png)\n\nIn those situations, the **closest corners** algorithm is preferred and will yield results that are more aligned with what the human eye would predict:\n\n![Closest corners is 'A2', as the human eye would expect.](/images/legacy/closest-corners-kanban.png)\n\n## Pointer within\n\nAs its name suggests, the pointer within collision detection algorithm only registers collision when the pointer is contained within the bounding rectangle of other droppable containers.\n\nThis collision detection algorithm is well suited for high precision drag and drop interfaces.\n\n<Info>\nAs its name suggests, this collision detection algorithm **only works with pointer-based sensors**. For this reason, we suggest you use [composition of collision detection algorithms](#composition-of-existing-algorithms) if you intend to use the `pointerWithin` collision detection algorithm so that you can fall back to a different collision detection algorithm for the Keyboard sensor.\n</Info>\n\n## Custom collision detection algorithms\n\nIn advanced use cases, you may want to build your own collision detection algorithms if the ones provided out of the box do not suit your use case.\n\nYou can either write a new collision detection algorithm from scratch, or compose two or more existing collision detection algorithms.\n\n### Composition of existing algorithms\n\nSometimes, you don't need to build custom collision detection algorithms from scratch. Instead, you can compose existing collision algorithms to augment them.\n\nA common example of this is when using the `pointerWithin` collision detection algorithm. As its name suggest, this collision detection algorithm depends on pointer coordinates, and therefore does not work when using other sensors like the Keyboard sensor. It's also a very high precision collision detection algorithm, so it can sometimes be helpful to fall back to a more tolerant collision detection algorithm when the `pointerWithin` algorithm does not return any collisions.\n\n```javascript\nimport {pointerWithin, rectIntersection} from '@dnd-kit/core';\n\nfunction customCollisionDetectionAlgorithm(args) {\n  // First, let's see if there are any collisions with the pointer\n  const pointerCollisions = pointerWithin(args);\n\n  // Collision detection algorithms return an array of collisions\n  if (pointerCollisions.length > 0) {\n    return pointerCollisions;\n  }\n\n  // If there are no collisions with the pointer, return rectangle intersections\n  return rectIntersection(args);\n}\n```\n\nAnother example where composition of existing algorithms can be useful is if you want some of your droppable containers to have a different collision detection algorithm than the others.\n\nFor instance, if you were building a sortable list that also supported moving items to a trash bin, you may want to compose both the `closestCenter` and `rectangleIntersection` collision detection algorithms.\n\n![Use the closest corners algorithm for all droppables except 'trash'.](/images/legacy/custom-collision-detection.png)\n\n![Use the intersection detection algorithm for the 'trash' droppable.](/images/legacy/custom-collision-detection-intersection.png)\n\nFrom an implementation perspective, the custom intersection algorithm described in the example above would look like:\n\n```javascript\nimport {closestCorners, rectIntersection} from '@dnd-kit/core';\n\nfunction customCollisionDetectionAlgorithm({droppableContainers, ...args}) {\n  // First, let's see if the `trash` droppable rect is intersecting\n  const rectIntersectionCollisions = rectIntersection({\n    ...args,\n    droppableContainers: droppableContainers.filter(({id}) => id === 'trash'),\n  });\n\n  // Collision detection algorithms return an array of collisions\n  if (rectIntersectionCollisions.length > 0) {\n    // The trash is intersecting, return early\n    return rectIntersectionCollisions;\n  }\n\n  // Compute other collisions\n  return closestCorners({\n    ...args,\n    droppableContainers: droppableContainers.filter(({id}) => id !== 'trash'),\n  });\n}\n```\n\n### Building custom collision detection algorithms\n\nFor advanced use cases or to detect collision between non-rectangular or non-axis aligned shapes, you'll want to build your own collision detection algorithms.\n\nHere's an example to [detect collisions between circles](https://developer.mozilla.org/en-US/docs/Games/Techniques/2D_collision_detection#Circle_Collision) instead of rectangles:\n\n```javascript\n/**\n * Sort collisions in descending order (from greatest to smallest value)\n */\nexport function sortCollisionsDesc(\n  {data: {value: a}},\n  {data: {value: b}}\n) {\n  return b - a;\n}\n\nfunction getCircleIntersection(entry, target) {\n  // Abstracted the logic to calculate the radius for simplicity\n  var circle1 = {radius: 20, x: entry.offsetLeft, y: entry.offsetTop};\n  var circle2 = {radius: 12, x: target.offsetLeft, y: target.offsetTop};\n\n  var dx = circle1.x - circle2.x;\n  var dy = circle1.y - circle2.y;\n  var distance = Math.sqrt(dx * dx + dy * dy);\n\n  if (distance < circle1.radius + circle2.radius) {\n    return distance;\n  }\n\n  return 0;\n}\n\n/**\n * Returns the circle that has the greatest intersection area\n */\nfunction circleIntersection({\n  collisionRect,\n  droppableRects,\n  droppableContainers,\n}) => {\n  const collisions = [];\n\n  for (const droppableContainer of droppableContainers) {\n    const {id} = droppableContainer;\n    const rect = droppableRects.get(id);\n\n    if (rect) {\n      const intersectionRatio = getCircleIntersection(rect, collisionRect);\n\n      if (intersectionRatio > 0) {\n        collisions.push({\n          id,\n          data: {droppableContainer, value: intersectionRatio},\n        });\n      }\n    }\n  }\n\n  return collisions.sort(sortCollisionsDesc);\n};\n```\n\nTo learn more, refer to the implementation of the built-in collision detection algorithms.\n"
  },
  {
    "path": "apps/docs/legacy/api-documentation/context-provider/dnd-context.mdx",
    "content": "---\ntitle: DndContext\ndescription: >-\n  The parent component for your drag and drop application.\nsidebarTitle: <DndContext>\n---\n\n## Application structure\n\nIn order for your your [Droppable](../droppable) and [Draggable](../draggable) components to interact with each other, you'll need to make sure that the part of your React tree that uses them is nested within a parent `<DndContext>` component. The `<DndContext>` provider makes use of the [React Context API](https://reactjs.org/docs/context.html) to share data between draggable and droppable components and hooks.\n\n> React context provides a way to pass data through the component tree without having to pass props down manually at every level.\n\nTherefore, components that use [`useDraggable`](../draggable/use-draggable), [`useDroppable`](../droppable/use-droppable) or [`DragOverlay`](../draggable/drag-overlay) will need to be nested within a `DndContext` provider.\n\nThey don't need to be direct descendants, but, there does need to be a parent `<DndContext>` provider somewhere higher up in the tree.\n\n```jsx\nimport React from 'react';\nimport {DndContext} from '@dnd-kit/core';\n\nfunction App() {\n  return (\n    <DndContext>\n      {/* Components that use `useDraggable`, `useDroppable` */}\n    </DndContext>\n  );\n}\n```\n\n## Nesting\n\nYou may also nest `<DndContext>` providers within other `<DndContext>` providers to achieve nested draggable/droppable interfaces that are independent of one another.\n\n```jsx\nimport React from 'react';\nimport {DndContext} from '@dnd-kit/core';\n\nfunction App() {\n  return (\n    <DndContext>\n      {/* Components that use `useDraggable`, `useDroppable` */}\n      <DndContext>\n        {/* ... */}\n        <DndContext>{/* ... */}</DndContext>\n      </DndContext>\n    </DndContext>\n  );\n}\n```\n\nWhen nesting `DndContext` providers, keep in mind that the `useDroppable` and `useDraggable` hooks will only have access to the other draggable and droppable nodes within that context.\n\nIf multiple `DndContext` providers are listening for the same event, events will be captured by the first `DndContext` that contains a [Sensor](../sensors/) that is activated by that event, similar to how [events bubble in the DOM](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events#Event_bubbling_and_capture).\n\n## Props\n\n```typescript\ninterface Props {\n  announcements?: Announcements;\n  autoScroll?: boolean;\n  cancelDrop?: CancelDrop;\n  children?: React.ReactNode;\n  collisionDetection?: CollisionDetection;\n  layoutMeasuring?: Partial<LayoutMeasuring>;\n  modifiers?: Modifiers;\n  screenReaderInstructions?: ScreenReaderInstructions;\n  sensors?: SensorDescriptor<any>[];\n  onDragStart?(event: DragStartEvent): void;\n  onDragMove?(event: DragMoveEvent): void;\n  onDragOver?(event: DragOverEvent): void;\n  onDragEnd?(event: DragEndEvent): void;\n  onDragCancel?(): void;\n}\n```\n\n### Event handlers\n\nAs you can see from the list of props above, there are a number of different events emitted by `<DndContext>` that you can listen to and decide how to handle.\n\nThe main events you can listen to are:\n\n#### `onDragStart`\n\nFires when a drag event that meets the [activation constraints](../sensors/#concepts) for that [sensor ](../sensors/)happens, along with the unique identifier of the draggable element that was picked up.\n\n#### `onDragMove`\n\nFires anytime as the [draggable](../draggable) item is moved. Depending on the activated [sensor](../sensors/#activators), this could for example be as the [Pointer](../sensors/pointer) is moved or the [Keyboard](../sensors/keyboard) movement keys are pressed.\n\n#### `onDragOver`\n\nFires when a [draggable](../draggable) item is moved over a [droppable](../droppable) container, along with the unique identifier of that droppable container.\n\n#### `onDragEnd`\n\nFires after a draggable item is dropped.\n\nThis event contains information about the active draggable `id` along with information on whether the draggable item was dropped `over`.\n\nIf there are no [collisions detected](./collision-detection-algorithms) when the draggable item is dropped, the `over` property will be `null`. If a collision is detected, the `over` property will contain the `id` of the droppable over which it was dropped.\n\n<Info>\nIt's important to understand that the `onDragEnd` event **does not move** [**draggable**](../draggable) **items into** [**droppable**](../droppable) **containers.**\n\nRather, it provides **information** about which draggable item was dropped and whether it was over a droppable container when it was dropped.\n\nIt is up to the **consumer** of `DndContext` to decide what to do with that information and how to react to it, for example, by updating \\(or not\\) its internal state in response to the event so that the items are declaratively rendered in a different parent droppable.\n</Info>\n\n#### `onDragCancel`\n\nFires if a drag operation is cancelled, for example, if the user presses `escape` while dragging a draggable item.\n\n### Accessibility\n\nFor more details and best practices around accessibility of draggable and droppable components, read the accessibility section:\n\n<Card href=\"/legacy/guides/accessibility\" horizontal icon=\"universal-access\" iconType=\"light\">\n  Accessibility\n</Card>\n\n#### Announcements\n\nUse the `announcements` prop to customize the screen reader announcements that are announced in the live region when draggable items are picked up, moved over droppable regions, and dropped.\n\nThe default announcements are:\n\n```javascript\nconst defaultAnnouncements = {\n  onDragStart(id) {\n    return `Picked up draggable item ${id}.`;\n  },\n  onDragOver(id, overId) {\n    if (overId) {\n      return `Draggable item ${id} was moved over droppable area ${overId}.`;\n    }\n\n    return `Draggable item ${id} is no longer over a droppable area.`;\n  },\n  onDragEnd(id, overId) {\n    if (overId) {\n      return `Draggable item was dropped over droppable area ${overId}`;\n    }\n\n    return `Draggable item ${id} was dropped.`;\n  },\n  onDragCancel(id) {\n    return `Dragging was cancelled. Draggable item ${id} was dropped.`;\n  },\n};\n```\n\nWhile these default announcements are sensible defaults that should cover most simple use cases, you know your application best, and we highly recommend that you customize these to provide a screen reader experience that is more tailored to the use case you are building.\n\n#### Screen reader instructions\n\nUse the `screenReaderInstructions` prop to customize the instructions that are read to screen readers when the focus is moved\n\n### Autoscroll\n\nUse the optional `autoScroll` boolean prop to temporarily or permanently disable auto-scrolling for all sensors used within this `DndContext`.\n\nAuto-scrolling may also be disabled on an individual sensor basis using the static property `autoScrollEnabled` of the sensor. For example, the [Keyboard sensor](../sensors/keyboard) manages scrolling internally, and therefore has the static property `autoScrollEnabled` set to `false`.\n\n### Collision detection\n\nUse the `collisionDetection` prop to customize the collision detection algorithm used to detect collisions between draggable nodes and droppable areas within the`DndContext` provider.\n\nThe default collision detection algorithm is the [rectangle intersection](./collision-detection-algorithms.md#rectangle-intersection) algorithm.\n\nThe built-in collision detection algorithms are:\n\n- [Rectangle intersection](./collision-detection-algorithms.md#rectangle-intersection)\n- [Closest center](./collision-detection-algorithms.md#closest-center)\n- [Closest corners](./collision-detection-algorithms.md#closest-corners)\n\nYou may also build custom collision detection algorithms or compose existing ones.\n\nTo learn more, read the collision detection guide:\n\n<Card href=\"./collision-detection-algorithms\">\n  Learn more about collision detection\n</Card>\n\n### Sensors\n\nSensors are an abstraction to detect different input methods in order to initiate drag operations, respond to movement and end or cancel the operation.\n\nThe default sensors used by `DndContext` are the [Pointer](../sensors/pointer) and [Keyboard](../sensors/keyboard) sensors.\n\nTo learn how to customize sensors or how to pass different sensors to `DndContext`, read the Sensors guide:\n\n<Card href=\"../sensors \">\n  Learn more about sensors\n</Card>\n\n### Modifiers\n\nModifiers let you dynamically modify the movement coordinates that are detected by sensors. They can be used for a wide range of use cases, for example:\n\n- Restricting motion to a single axis\n- Restricting motion to the draggable node container's bounding rectangle\n- Restricting motion to the draggable node's scroll container bounding rectangle\n- Applying resistance or clamping the motion\n\nTo learn more about how to use Modifiers, read the Modifiers guide:\n\n<Card href=\"../modifiers\">\n  Learn more about modifiers\n</Card>\n\n### Layout measuring\n\nYou can configure when and how often `DndContext` should measure its droppable elements by using the `layoutMeasuring` prop.\n\nThe `frequency` argument controls how frequently layouts should be measured. By default, layout measuring is set to `optimized`, which only measures layouts based on the `strategy`.\n\nSpecify one of the following strategies:\n\n- `LayoutMeasuringStrategy.WhileDragging`: Default behavior, only measure droppable elements right after dragging has begun.\n\n  `LayoutMeasuringStrategy.BeforeDragging`: Measure droppable elements before dragging begins and right after it ends.\n\n- `LayoutMeasuringStrategy.Always`: Measure droppable elements before dragging begins, right after dragging has begun, and after it ends.\n\nExample usage:\n\n```jsx\nimport {DndContext, LayoutMeasuringStrategy} from '@dnd-kit/core';\n\n<DndContext layoutMeasuring={{strategy: LayoutMeasuringStrategy.Always}} />;\n```\n"
  },
  {
    "path": "apps/docs/legacy/api-documentation/context-provider/use-dnd-context.mdx",
    "content": "---\ntitle: useDndContext\n---\n\nThe `useDndContext` hook can be used within components wrapped in a `DndContext` provider to access the internal context of the `DndContext`. This can be useful if you're building your own custom components or presets on top of `@dnd-kit/core`.\n\n```jsx\nimport {useDndContext} from '@dnd-kit/core';\n\nfunction App() {\n  <DndContext>\n    <MyComponent />\n  </DndContext>\n}\n\nfunction MyComponent() {\n  const dndContext = useDndContext();\n\n  console.log(dndContext);\n}\n```\n\n<Warning>\nMake sure you use the `useDndContext` hook within a [`<DndContext>`](./dnd-context) provider.\n</Warning>\n\n"
  },
  {
    "path": "apps/docs/legacy/api-documentation/context-provider/use-dnd-monitor.mdx",
    "content": "---\ntitle: useDndMonitor\n---\n\nThe `useDndMonitor` hook can be used within components wrapped in a `DndContext` provider to monitor the different drag and drop events that happen for that `DndContext`.\n\n```jsx\nimport {DndContext, useDndMonitor} from '@dnd-kit/core';\n\nfunction App() {\n  return (\n    <DndContext>\n      <MyComponent />\n    </DndContext>\n  );\n}\n\nfunction MyComponent() {\n  // Monitor drag and drop events that happen on the parent `DndContext` provider\n  useDndMonitor({\n    onDragStart(event) {\n      console.log('Drag started', event);\n    },\n    onDragMove(event) {\n      console.log('Drag moved', event);\n    },\n    onDragOver(event) {\n      console.log('Drag over', event);\n    },\n    onDragEnd(event) {\n      console.log('Drag ended', event);\n    },\n    onDragCancel(event) {\n      console.log('Drag cancelled', event);\n    },\n  });\n}\n```\n\n<Warning>\nMake sure you use the `useDndMonitor` hook within a [`<DndContext>`](./dnd-context) provider.\n</Warning>\n"
  },
  {
    "path": "apps/docs/legacy/api-documentation/draggable/drag-overlay.mdx",
    "content": "---\ntitle: Drag overlay\nsidebarTitle: <DragOverlay>\ndescription: >-\n  The `<DragOverlay>` component provides a way to render a draggable overlay that is removed from the normal document flow and is positioned relative to the viewport.\n---\n\n![Drag overlay](/images/legacy/dragoverlay.png)\n\n## When should I use a drag overlay?\n\nDepending on your use-case, you may want to use a drag overlay rather than transforming the original draggable source element that is connected to the [`useDraggable`](./use-draggable) hook:\n\n- If you'd like to **show a preview** of where the draggable source will be when dropped, you can update the position of the draggable source while dragging without affecting the drag overlay.\n- If your item needs to **move from one container to another while dragging**, we strongly recommend you use the `<DragOverlay>` component so the draggable item can unmount from its original container while dragging and mount back into a different container without affecting the drag overlay.\n- If your draggable item is within a **scrollable container,** we also recommend you use a `<DragOverlay>`, otherwise you'll need to set the draggable element to `position: fixed` yourself so the item isn't restricted to the overflow and stacking context of its scroll container, and can move without being affected by the scroll position of its container.\n- If your `useDraggable` items are within a **virtualized list**, you will absolutely want to use a drag overlay, since the original drag source can unmount while dragging as the virtualized container is scrolled.\n- If you want **smooth drop animations** without the effort of building them yourself.\n\n## Usage\n\nYou may render any valid JSX within the children of the `<DragOverlay>`.\n\nThe `<DragOverlay>` component should **remain mounted at all times** so that it can perform the drop animation. If you conditionally render the `<DragOverlay>` component, drop animations will not work.\n\nAs a rule of thumb, try to render the `<DragOverlay>` outside of your draggable components, and follow the [presentational component pattern ](./drag-overlay#presentational-components)to maintain a good separation of concerns.\n\nInstead, you should conditionally render the children passed to the `<DragOverlay>`:\n\n<CodeGroup>\n```jsx App.jsx\nimport React, {useState} from 'react';\nimport {DndContext, DragOverlay} from '@dnd-kit/core';\n\nimport {Draggable} from './Draggable';\n\n/*\n * The implementation details of <Item> and <ScrollableList> are not\n * relevant for this example and are therefore omitted.\n */\n\nfunction App() {\nconst [items] = useState(['1', '2', '3', '4', '5']);\nconst [activeId, setActiveId] = useState(null);\n\nreturn (\n<DndContext onDragStart={handleDragStart} onDragEnd={handleDragEnd}>\n<ScrollableList>\n{items.map(id =>\n<Draggable key={id} id={id}>\n<Item value={`Item ${id}`} />\n</Draggable>\n)}\n</ScrollableList>\n\n      <DragOverlay>\n        {activeId ? (\n          <Item value={`Item ${activeId}`} />\n        ): null}\n      </DragOverlay>\n    </DndContext>\n\n);\n\nfunction handleDragStart(event) {\nsetActiveId(event.active.id);\n}\n\nfunction handleDragEnd() {\nsetActiveId(null);\n}\n}\n\n```\n\n```jsx Draggable.jsx\nimport React from 'react';\nimport {useDraggable} from '@dnd-kit/core';\n\nfunction Draggable(props) {\n  const {attributes, listeners, setNodeRef} = useDraggable({\n    id: props.id,\n  });\n\n  return (\n    <li ref={setNodeRef} {...listeners} {...attributes}>\n      {props.children}\n    </li>\n  );\n}\n```\n\n</CodeGroup>\n\n## Patterns\n\n### Presentational components\n\nWhile this is an optional pattern, we recommend that the components you intend to make draggable be [presentational components ](https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0)that are decoupled from `@dnd-kit`.\n\nUsing this pattern, create a presentational version of your component that you intend on rendering within the drag overlay, and another version that is draggable and renders the presentational component.\n\n#### Wrapper nodes\n\nAs you may have noticed from the example above, we can create small abstract components that render a wrapper node and make any children rendered within draggable:\n\n<CodeGroup>\n```jsx Draggable.jsx\nimport React from 'react';\nimport {useDraggable} from '@dnd-kit/core';\n\nfunction Draggable(props) {\nconst Element = props.element || 'div';\nconst {attributes, listeners, setNodeRef} = useDraggable({\nid: props.id,\n});\n\nreturn (\n<Element ref={setNodeRef} {...listeners} {...attributes}>\n{props.children}\n</Element>\n);\n}\n\n```\n</CodeGroup>\n\nUsing this pattern, we can then render our presentational components within `<Draggable>` and within `<DragOverlay>`:\n\n<CodeGroup>\n```jsx App.jsx\n```jsx\nimport React, {useState} from 'react';\nimport {DndContext, DragOverlay} from '@dnd-kit/core';\n\nimport {Draggable} from './Draggable';\n\n/* The implementation details of <Item> is not\n * relevant for this example and therefore omitted. */\n\nfunction App() {\n  const [isDragging, setIsDragging] = useState(false);\n\n  return (\n    <DndContext onDragStart={handleDragStart} onDragEnd={handleDragEnd}>\n      <Draggable id=\"my-draggable-element\">\n        <Item />\n      </Draggable>\n\n      <DragOverlay>\n        {isDragging ? (\n          <Item />\n        ): null}\n      </DragOverlay>\n    </DndContext>\n  );\n\n  function handleDragStart() {\n    setIsDragging(true);\n  }\n\n  function handleDragEnd() {\n    setIsDragging(false);\n  }\n}\n```\n\n</CodeGroup>\n\n#### Ref forwarding\n\nUse the[ ref forwarding pattern](https://reactjs.org/docs/forwarding-refs.html) to connect your presentational components to the `useDraggable` hook:\n\n```jsx\nimport React, {forwardRef} from 'react';\n\nconst Item = forwardRef(({children, ...props}, ref) => {\n  return (\n    <li {...props} ref={ref}>\n      {children}\n    </li>\n  );\n});\n```\n\nThis way, you can create two versions of your component, one that is presentational, and one that is draggable and renders the presentational component **without the need for additional wrapper elements**:\n\n```jsx\nimport React from 'react';\nimport {useDraggable} from '@dnd-kit/core';\n\nfunction DraggableItem(props) {\n  const {attributes, listeners, setNodeRef} = useDraggable({\n    id: props.id,\n  });\n\n  return (\n    <Item ref={setNodeRef} {...attributes} {...listeners}>\n      {value}\n    </Item>\n  )\n});\n```\n\n### Portals\n\nThe drag overlay is not rendered in a portal by default. Rather, it is rendered in the container where it is rendered.\n\nIf you would like to render the `<DragOverlay>` in a different container than where it is rendered, import the [`createPortal`](https://reactjs.org/docs/portals.html) helper from `react-dom`:\n\n```jsx\nimport React, {useState} from 'react';\nimport {createPortal} from 'react-dom';\nimport {DndContext, DragOverlay} from '@dnd-kit/core';\n\nfunction App() {\n  return (\n    <DndContext>\n      {createPortal(<DragOverlay>{/* ... */}</DragOverlay>, document.body)}\n    </DndContext>\n  );\n}\n```\n\n## Props\n\n```typescript\n{\n  adjustScale?: boolean;\n  children?: React.ReactNode;\n  className?: string;\n  dropAnimation?: DropAnimation | null;\n  style?: React.CSSProperties;\n  transition?: string | TransitionGetter;\n  modifiers?: Modifiers;\n  wrapperElement?: keyof JSX.IntrinsicElements;\n  zIndex?: number;\n}\n```\n\n### Children\n\nYou may render any valid JSX within the children of the `<DragOverlay>`. However, **make sure that the components rendered within the drag overlay do not use the `useDraggable` hook**.\n\nPrefer conditionally rendering the `children` of `<DragOverlay>` rather than conditionally rendering `<DragOverlay>`, otherwise drop animations will not work.\n\n### Class name and inline styles\n\nIf you'd like to customize the[ wrapper element](./drag-overlay#wrapper-element) that the `DragOverlay`'s children are rendered into, use the `className` and `style` props:\n\n```jsx\n<DragOverlay\n  className=\"my-drag-overlay\"\n  style={{\n    width: 500,\n  }}\n>\n  {/* ... */}\n</DragOverlay>\n```\n\n### Drop animation\n\nUse the `dropAnimation` prop to configure the drop animation.\n\n```typescript\ninterface DropAnimation {\n  duration: number;\n  easing: string;\n}\n```\n\nThe `duration` option should be a number, in `milliseconds`. The default value is `250` milliseconds. The `easing` option should be a string that represents a valid [CSS easing function](https://developer.mozilla.org/en-US/docs/Web/CSS/easing-function). The default easing is `ease`.\n\n```jsx\n<DragOverlay\n  dropAnimation={{\n    duration: 500,\n    easing: 'cubic-bezier(0.18, 0.67, 0.6, 1.22)',\n  }}\n>\n  {/* ... */}\n</DragOverlay>\n```\n\nTo disable drop animations, set the `dropAnimation` prop to `null`.\n\n```jsx\n<DragOverlay dropAnimation={null}>{/* ... */}</DragOverlay>\n```\n\n<Warning>\nThe `<DragOverlay>` component should **remain mounted at all times** so that it can perform the drop animation. If you conditionally render the `<DragOverlay>` component, drop animations will not work.\n</Warning>\n\n### Modifiers\n\nModifiers let you dynamically modify the movement coordinates that are detected by sensors. They can be used for a wide range of use-cases, which you can learn more about by reading the [Modifiers](../modifiers) documentation.\n\nFor example, you can use modifiers to restrict the movement of the `<DragOverlay>` to the bounds of the window:\n\n```jsx\nimport {DndContext, DragOverlay} from '@dnd-kit';\nimport {restrictToWindowEdges} from '@dnd-kit/modifiers';\n\nfunction App() {\n  return (\n    <DndContext>\n      {/* ... */}\n      <DragOverlay modifiers={[restrictToWindowEdges]}>{/* ... */}</DragOverlay>\n    </DndContext>\n  );\n}\n```\n\n### Transition\n\nBy default, the `<DragOverlay>` component does not have any transitions, unless activated by the [`Keyboard` sensor](../sensors/keyboard). Use the `transition` prop to create a function that returns the transition based on the [activator event](../sensors/#activators). The default implementation is:\n\n```javascript\nfunction defaultTransition(activatorEvent) {\n  const isKeyboardActivator = activatorEvent instanceof KeyboardEvent;\n\n  return isKeyboardActivator ? 'transform 250ms ease' : undefined;\n}\n```\n\n### Wrapper element\n\nBy default, the `<DragOverlay>` component renders your elements within a `div` element. If your draggable elements are list items, you'll want to update the `<DragOverlay>` component to render a `ul` wrapper instead, since wrapping a `li` item without a parent `ul` is invalid HTML:\n\n```jsx\n<DragOverlay wrapperElement=\"ul\">{/* ... */}</DragOverlay>\n```\n\n### `z-index`\n\nThe `zIndex` prop sets the [z-order](https://developer.mozilla.org/en-US/docs/Web/CSS/z-index) of the drag overlay. The default value is `999` for compatibility reasons, but we highly recommend you use a lower value.\n"
  },
  {
    "path": "apps/docs/legacy/api-documentation/draggable/use-draggable.mdx",
    "content": "---\ntitle: useDraggable\n---\n\n## Arguments\n\n```typescript\ninterface UseDraggableArguments {\n  id: string | number;\n  attributes?: {\n    role?: string;\n    roleDescription?: string;\n    tabIndex?: number;\n  };\n  data?: Record<string, any>;\n  disabled?: boolean;\n}\n```\n\n### Identifier\n\nThe `id` argument is a `string` or `number` that should be a unique identifier, meaning there should be no other **draggable** elements that share that same identifier within a given [`DndContext`](../context-provider/) provider.\n\nIf you're building a component that uses both the `useDraggable` and `useDroppable` hooks, they can both share the same identifier since draggable elements are stored in a different key-value store than droppable elements.\n\n### Data\n\nThe `data` argument is for advanced use-cases where you may need access to additional data about the draggable element in event handlers, modifiers or custom sensors.\n\nFor example, if you were building a sortable preset, you could use the `data` attribute to store the index of the draggable element within a sortable list to access it within a custom sensor.\n\n```jsx\nconst {setNodeRef} = useDraggable({\n  id: props.id,\n  data: {\n    index: props.index,\n  },\n});\n```\n\nAnother more advanced example where the `data` argument can be useful is create relationships between draggable nodes and droppable areas, for example, to specify which types of droppable nodes your draggable node can be dropped on:\n\n```jsx\nimport {DndContext, useDraggable, useDroppable} from '@dnd-kit/core';\n\nfunction Droppable() {\n  const {setNodeRef} = useDroppable({\n    id: 'droppable',\n    data: {\n      type: 'type1',\n    },\n  });\n\n  /* ... */\n}\n\nfunction Draggable() {\n  const {attributes, listeners, setNodeRef, transform} = useDraggable({\n    id: 'draggable',\n    data: {\n      supports: ['type1', 'type2'],\n    },\n  });\n\n  /* ... */\n}\n\nfunction App() {\n  return <DndContext onDragEnd={handleDragEnd}>/* ... */</DndContext>;\n\n  function handleDragEnd(event) {\n    const {active, over} = event;\n\n    if (over && active.data.current.supports.includes(over.data.current.type)) {\n      // do stuff\n    }\n  }\n}\n```\n\n### Disabled\n\nSince [hooks cannot be conditionally invoked](https://react.dev/reference/rules/rules-of-hooks), use the `disabled` argument and set it to `true` if you need to temporarily disable a `draggable` element.\n\n### Attributes\n\nThe default values for the `attributes` property are sensible defaults that should cover a wide range of use cases, but there is no one-size-fits-all solution.\n\nYou know your application best, and we encourage you to manually attach only the attributes that you think make sense in the context of your application rather than using them all without considering whether it makes sense to do so.\n\nFor example, if the HTML element you are attaching the `useDraggable` `listeners` to is already a native HTML `button` element, although it's harmless to do so, there's no need to add the `role=\"button\"` attribute, since that is already the default role of `button`.\n\n#### Role\n\nThe ARIA `\"role\"` attribute lets you explicitly define the role for an element, which communicates its purpose to assistive technologies.\n\nThe default value for the `\"role\"` attribute is `\"button\"`.\n\n<Info>\nIf it makes sense in the context of what you are building, we recommend that you leverage the native HTML `<button>` element for draggable elements.\n</Info>\n\n#### Role description\n\nThe `roleDescription` argument can be used to tailor the screen reader experience to your application. For example, if you're building a sortable list of products you'd want to set the `roleDescription` value to something like `\"sortable product\"`.\n\n**Tab index**\n\nThe `tabindex` attribute dictates the order in which focus moves throughout the document.\n\n- Natively interactive elements such as [buttons](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button), [anchor tags](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a) and[ form controls ](https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormControlsCollection)have a default `tabindex` value of `0`.\n- Custom elements that are intended to be interactive and receive keyboard focus need to have an explicitly assigned `tabindex=\"0\"`(for example, `div` and `li` elements)\n\nIn other words, in order for your draggable elements to receive keyboard focus, they **need** to have the `tabindex` attribute set to `0` if they are not natively interactive elements (such as the HTML `button` element).\n\nFor this reason, the `useDraggable` hook sets the `tabindex=\"0\"` attribute by default.\n\n## Properties\n\n```typescript\n{\n  active: {\n    id: UniqueIdentifier;\n    node: React.MutableRefObject<HTMLElement>;\n    rect: ViewRect;\n  } | null;\n  attributes: {\n    role: string;\n    tabIndex: number;\n    'aria-diabled': boolean;\n    'aria-roledescription': string;\n    'aria-describedby': string;\n  },\n  isDragging: boolean;\n  listeners: Record<SyntheticListenerName, Function> | undefined;\n  node: React.MutableRefObject<HTMLElement | null>;\n  over: {id: UniqueIdentifier} | null;\n  setNodeRef(HTMLElement | null): void;\n  setActivatorNodeRef(HTMLElement | null): void;\n  transform: {x: number, y: number, scaleX: number, scaleY: number} | null;\n}\n```\n\n### Active\n\n#### `active`\n\nIf there is currently an active draggable element within the [`DndContext`](../context-provider/) provider where the `useDraggable` hook is used, the `active` property will be defined with the corresponding `id`, `node` and `rect` of that draggable element.\n\nOtherwise, the `active` property will be set to `null`.\n\n#### `isDragging`\n\nIf the draggable element that is currently being dragged is the current one where `useDraggable` is used, the `isDragging` property will be `true`. Otherwise the `isDragging` property will be false.\n\nInternally, the `isActive` property just checks if the `active.id === id`.\n\n### Listeners\n\nThe `useDraggable` hook requires that you attach `listeners` to the DOM node that you would like to become the activator to start dragging.\n\nWhile we could have attached these listeners manually to the node provided to `setNodeRef`, there are actually a number of key advantages to forcing the consumer to manually attach the listeners.\n\n#### Flexibility\n\nWhile many drag and drop libraries need to expose the concept of \"drag handles\", creating a drag handle with the `useDraggable` hook is as simple as manually attaching the listeners to a different DOM element than the one that is set as the draggable source DOM node:\n\n```jsx\nimport {useDraggable} from '@dnd-kit/core';\n\nfunction Draggable() {\n  const {attributes, listeners, setNodeRef} = useDraggable({\n    id: 'unique-id',\n  });\n\n  return (\n    <div ref={setNodeRef}>\n      /* Some other content that does not activate dragging */\n      <button {...listeners} {...attributes}>\n        Drag handle\n      </button>\n    </div>\n  );\n}\n```\n\n<Info>\nWhen attaching the listeners to a different element than the node that is draggable, make sure you also attach the attributes to the same node that has the listeners attached so that it is still [accessible](../../guides/accessibility).\n</Info>\n\nYou can even have multiple drag handles if that makes sense in the context of your application:\n\n```jsx\nimport {useDraggable} from '@dnd-kit/core';\n\nfunction Draggable() {\n  const {attributes, listeners, setNodeRef} = useDraggable({\n    id: 'unique-id',\n  });\n\n  return (\n    <div ref={setNodeRef}>\n      <button {...listeners} {...attributes}>\n        Drag handle 1\n      </button>\n      /* Some other content that does not activate dragging */\n      <button {...listeners} {...attributes}>\n        Drag handle 2\n      </button>\n    </div>\n  );\n}\n```\n\n#### Performance\n\nThis strategy also means that we're able to use [React synthetic events](https://reactjs.org/docs/events.html), which ultimately leads to improved performance over manually attaching event listeners to each individual node.\\\n\\\nWhy? Because rather than having to attach individual event listeners for each draggable DOM node, React attaches a single event listener for every type of event we listen to on the `document`. Once click on one of the draggable nodes happens, React's listener on the document dispatches a SyntheticEvent back to the original handler.\n\n### Node\n\n**`setNodeRef`**\n\nIn order for the `useDraggable` hook to function properly, it needs the `setNodeRef` property to be attached to the HTML element you intend on turning into a draggable element so that @dnd-kit can measure that element to compute collisions:\n\n```jsx\nfunction Draggable(props) {\n  const {setNodeRef} = useDraggable({\n    id: props.id,\n  });\n\n  return <button ref={setNodeRef}>{/* ... */}</button>;\n}\n```\n\nKeep in mind that the `ref` should be assigned to the outer container that you want to become draggable, but this doesn't necessarily need to coincide with the container that the listeners are attached to.\n\n#### **`node`**\n\nA [ref](https://reactjs.org/docs/refs-and-the-dom.html) to the current node that is passed to `setNodeRef`\n\n### Activator\n\n**`setActivatorNodeRef`**\n\nIt's possible for the listeners to be attached to a different node than the one that `setNodeRef` is attached to.\n\nA common example of this is when implementing a drag handle and attaching the listeners to the drag handle:\n\n```jsx\nfunction Draggable(props) {\n  const {listeners, setNodeRef} = useDraggable({\n    id: props.id,\n  });\n\n  return (\n    <div ref={setNodeRef}>\n      {/* ... */}\n      <button {...listeners}>Drag handle</button>\n    </div>\n  );\n}\n```\n\nWhen the activator node differs from the draggable node, we recommend setting the activator node ref on the activator node:\n\n```jsx\nfunction Draggable(props) {\n  const {listeners, setNodeRef, setActivatorNodeRef} = useDraggable({\n    id: props.id,\n  });\n\n  return (\n    <div ref={setNodeRef}>\n      {/* ... */}\n      <button ref={setActivatorNodeRef} {...listeners}>\n        Drag handle\n      </button>\n    </div>\n  );\n}\n```\n\nThis helps @dnd-kit more accurately handle automatic focus management and can also be accessed by sensors for enhanced activation constraints.\n\n<Info>\nFocus management is automatically handled by [@dnd-kit](https://github.com/dnd-kit). When the activator event is a Keyboard event, focus will automatically be restored back to the first focusable node of the activator node.\n\nIf no activator node is set via `setActivatorNodeRef`, focus will automatically be restored on the first focusable node of the draggable node registered via `setNodeRef.`\n</Info>\n\n### Over\n\n#### **`over`**\n\nIf you'd like to change the appearance of the draggable element in response to it being dragged over a different droppable container, check whether the `over` value is defined.\n\nIf a draggable element is moved over a droppable area, the `over` property will be defined for all draggable elements, regardless of whether or not those draggable elements are active or not.\n\nIf you'd like to make changes to only the active draggable element in response to it being moved over a droppable area, check whether the `isDragging` property is `true`.\n\n### Transform\n\nAfter a draggable item is picked up, the `transform` property will be populated with the `translate` coordinates you'll need to move the item on the screen.\n\nThe `transform` object adheres to the following shape:\n\n```typescript\n{\n  x: number;\n  y: number;\n  scaleX: number;\n  scaleY: number;\n}\n```\n\nThe `x` and `y` coordinates represent the delta from the point of origin of your draggable element since it started being dragged.\n\nThe `scaleX` and `scaleY` properties represent the difference in scale between the element that is currently being dragged and the droppable it is currently over, which can be useful if the draggable item needs to be dynamically resized to the size of the droppable it is over.\n"
  },
  {
    "path": "apps/docs/legacy/api-documentation/draggable.mdx",
    "content": "---\ntitle: Draggable\ndescription: >-\n  Use the `useDraggable` hook turn DOM nodes into draggable sources that can be picked up, moved and dropped over [droppable](./droppable) containers.\nsidebarTitle: Overview\n---\n\n\n![Draggable](/images/legacy/draggable.png)\n\n\n## Usage\n\nThe `useDraggable` hook isn't particularly opinionated about how your app should be structured.\n\n### Node ref\n\nAt minimum though, you need to pass the `setNodeRef` function that is returned by the `useDraggable` hook to a DOM element so that it can access the underlying DOM node and keep track of it to [detect collisions and intersections](./context-provider/collision-detection-algorithms) with other [droppable](./droppable) elements.\n\n```jsx\nimport {useDraggable} from '@dnd-kit/core';\nimport {CSS} from '@dnd-kit/utilities';\n\nfunction Draggable() {\n  const {attributes, listeners, setNodeRef, transform} = useDraggable({\n    id: 'unique-id',\n  });\n  const style = {\n    transform: CSS.Translate.toString(transform),\n  };\n\n  return (\n    <button ref={setNodeRef} style={style} {...listeners} {...attributes}>\n      /* Render whatever you like within */\n    </button>\n  );\n}\n```\n\n<Info>\nAlways try to use the  DOM element that is most [semantic](https://developer.mozilla.org/en-US/docs/Glossary/Semantics) in the context of your app. \\\nCheck out our [Accessibility guide](../guides/accessibility) to learn more about how you can help provide a better experience for screen readers.\n</Info>\n\n### Identifier\n\nThe `id` argument is a string that should be a unique identifier, meaning there should be no other **draggable** elements that share that same identifier within a given [`DndContext`](./context-provider/) provider.\n\n### Listeners\n\nThe `useDraggable` hook requires that you attach `listeners` to the DOM node that you would like to become the activator to start dragging.\n\nWhile we could have attached these listeners manually to the node provided to `setNodeRef`, there are actually a number of key advantages to forcing the consumer to manually attach the listeners.\n\n#### Flexibility\n\nWhile many drag and drop libraries need to expose the concept of \"drag handles\", creating a drag handle with the `useDraggable` hook is as simple as manually attaching the listeners to a different DOM element than the one that is set as the draggable source DOM node:\n\n```jsx\nimport {useDraggable} from '@dnd-kit/core';\n\nfunction Draggable() {\n  const {attributes, listeners, setNodeRef} = useDraggable({\n    id: 'unique-id',\n  });\n\n  return (\n    <div ref={setNodeRef}>\n      /* Some other content that does not activate dragging */\n      <button {...listeners} {...attributes}>\n        Drag handle\n      </button>\n    </div>\n  );\n}\n```\n\n<Info>\nWhen attaching the listeners to a different element than the node that is draggable, make sure you also attach the attributes to the same node that has the listeners attached so that it is still [accessible](../guides/accessibility).\n</Info>\n\nYou can even have multiple drag handles if that makes sense in the context of your application:\n\n```jsx\nimport {useDraggable} from '@dnd-kit/core';\n\nfunction Draggable() {\n  const {attributes, listeners, setNodeRef} = useDraggable({\n    id: 'unique-id',\n  });\n\n  return (\n    <div ref={setNodeRef}>\n      <button {...listeners} {...attributes}>\n        Drag handle 1\n      </button>\n      /* Some other content that does not activate dragging */\n      <button {...listeners} {...attributes}>\n        Drag handle 2\n      </button>\n    </div>\n  );\n}\n```\n\n#### Performance\n\nThis strategy also means that we're able to use [React synthetic events](https://reactjs.org/docs/events.html), which ultimately leads to improved performance over manually attaching event listeners to each individual node.\\\n\\\nWhy? Because rather than having to attach individual event listeners for each draggable DOM node, React attaches a single event listener for every type of event we listen to on the `document`. Once click on one of the draggable nodes happens, React's listener on the document dispatches a SyntheticEvent back to the original handler.\n\n### Transforms\n\nIn order to actually see your draggable items move on screen, you'll need to move the item using CSS. You can use inline styles, CSS variables, or even CSS-in-JS libraries to pass the `transform` property as CSS to your draggable element.\n\n<Success>\nFor performance reasons, we strongly recommend you use the **`transform`** CSS property to move your draggable item on the screen, as other positional properties such as **`top`**, **`left`** or **`margin`** can cause expensive repaints. Learn more about [CSS transforms](https://developer.mozilla.org/en-US/docs/Web/CSS/transform).\n</Success>\n\nAfter an item starts being dragged, the `transform` property will be populated with the `translate` coordinates you'll need to move the item on the screen. The `transform` object adheres to the following shape: `{x: number, y: number, scaleX: number, scaleY: number}`\n\nThe `x` and `y` coordinates represent the delta from the point of origin of your draggable element since it started being dragged.\n\nThe `scaleX` and `scaleY` properties represent the difference in scale between the item that is dragged and the droppable container it is currently over. This is useful for building interfaces where the draggable item needs to adapt to the size of the droppable container it is currently over.\n\nThe `CSS` helper is entirely optional; it's a convenient helper for generating [CSS transform ](https://developer.mozilla.org/en-US/docs/Web/CSS/transform)strings, and is equivalent to manually constructing the string as such:\n\n```javascript\nCSS.Translate.toString(transform) ===\n  `translate3d(${translate.x}, ${translate.y}, 0)`;\n```\n\n### Attributes\n\nThe `useDraggable` hook \\*\\*\\*\\* provides a set of sensible default attributes for draggable items. We recommend you attach these to the HTML element you are attaching the draggable listeners to.\n\nWe encourage you to manually attach the attributes that you think make sense in the context of your application rather than using them all without considering whether it makes sense to do so.\n\nFor example, if the HTML element you are attaching the `useDraggable` `listeners` to is already a semantic `button`, although it's harmless to do so, there's no need to add the `role=\"button\"` attribute, since that is already the default role.\n\n| Attribute              | Default value             | Description                                                                                                                                                                                                                                                                                         |\n| ---------------------- | ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `role`                 | `\"button\"`                | <p>If possible, we recommend you use a semantic <code>&#x3C;button></code> element for the DOM element you plan on attaching draggable listeners to. </p><p></p><p>In case that's not possible, make sure you include the <code>role=\"button\"</code>attribute, which is the default value.</p>      |\n| `tabIndex`             | `\"0\"`                     | In order for your draggable elements to receive keyboard focus, they **need** to have the `tabindex` attribute set to `0` if they are not natively interactive elements (such as the HTML `button` element). For this reason, the `useDraggable` hook sets the `tabindex=\"0\"` attribute by default. |\n| `aria-roledescription` | `\"draggable\"`             | While `draggable` is a sensible default, we recommend you customize this value to something that is tailored to the use case you are building.                                                                                                                                                      |\n| `aria-describedby`     | `\"DndContext-[uniqueId]\"` | Each draggable item is provided a unique `aria-describedby` ID that points to the [screen reader instructions](./context-provider/#screen-reader-instructions) to be read out when a draggable item receives focus.                                                                                |\n\nTo learn more about the best practices for making draggable interfaces accessible, read the full accessibility guide:\n\n<Card href=\"../guides/accessibility\" horizontal icon=\"universal-access\" iconType=\"light\">\n  Accessibility\n</Card>\n\n### Recommendations\n\n#### `touch-action`\n\nWe highly recommend you specify the `touch-action` CSS property for all of your draggable elements.\n\n> The **`touch-action`** CSS property sets how an element's region can be manipulated by a touchscreen user (for example, by zooming features built into the browser).\\\n> \\\n> Source: [MDN](https://developer.mozilla.org/en-US/docs/Web/CSS/touch-action)\n\nIn general, we recommend you set the `touch-action` property to `none` for draggable elements in order to prevent scrolling on mobile devices.\n\n<Info>\nFor [Pointer Events,](./sensors/pointer) there is no way to prevent the default behaviour of the browser on touch devices when interacting with a draggable element from the pointer event listeners. Using `touch-action: none;` is the only way to reliably prevent scrolling for pointer events.\n\nFurther, using `touch-action: none;` is currently the only reliable way to prevent scrolling in iOS Safari for both Touch and Pointer events.\n</Info>\n\nIf your draggable item is part of a scrollable list, we recommend you use a drag handle and set `touch-action` to `none` only for the drag handle, so that the contents of the list can still be scrolled, but that initiating a drag from the drag handle does not scroll the page.\n\nOnce a `pointerdown` or `touchstart` event has been initiated, any changes to the `touch-action` value will be ignored. Programmatically changing the `touch-action` value for an element from `auto` to `none` after a pointer or touch event has been initiated will not result in the user agent aborting or suppressing any default behavior for that event for as long as that pointer is active (for more details, refer to the [Pointer Events Level 2 Spec](https://www.w3.org/TR/pointerevents2/#determining-supported-touch-behavior)).\n\n## Drag Overlay\n\nThe `<DragOverlay>` component provides a way to render a draggable overlay that is removed from the normal document flow and is positioned relative to the viewport.\n\n![Drag overlay](/images/legacy/dragoverlay.png)\n\nTo learn more about how to use drag overlays, read the in-depth guide:\n\n<Card href=\"./draggable/drag-overlay\" horizontal icon=\"send-backward\" iconType=\"light\">\n  Drag overlay\n</Card>\n"
  },
  {
    "path": "apps/docs/legacy/api-documentation/droppable/use-droppable.mdx",
    "content": "---\ntitle: useDroppable\n---\n\n## Arguments\n\n```typescript\ninterface UseDroppableArguments {\n  id: string | number;\n  disabled?: boolean;\n  data?: Record<string, any>;\n}\n```\n\n### Identifier\n\nThe `id` argument is a `string` or `number` that should be a unique identifier, meaning there should be no other **droppable** elements that share that same identifier within a given [`DndContext`](../context-provider/) provider.\n\nIf you're building a component that uses both the `useDroppable` and `useDraggable` hooks, they can both share the same identifier since droppable elements are stored in a different key-value store than draggable elements.\n\n### Disabled\n\nSince [hooks cannot be conditionally invoked](https://react.dev/reference/rules/rules-of-hooks), use the `disabled` argument and set it to `true` if you need to temporarily disable a `droppable` area.\n\n### Data\n\nThe `data` argument is for advanced use-cases where you may need access to additional data about the droppable element in event handlers, modifiers or custom sensors.\n\nFor example, if you were building a sortable preset, you could use the `data` attribute to store the index of the droppable element within a sortable list to access it within a custom sensor.\n\n```jsx\nconst {setNodeRef} = useDroppable({\n  id: props.id,\n  data: {\n    index: props.index,\n  },\n});\n```\n\nAnother more advanced example where the `data` argument can be useful is create relationships between draggable nodes and droppable areas, for example, to specify which types of draggable nodes your droppable accepts:\n\n```jsx\nimport {DndContext, useDraggable, useDroppable} from '@dnd-kit/core';\n\nfunction Droppable() {\n  const {setNodeRef} = useDroppable({\n    id: 'droppable',\n    data: {\n      accepts: ['type1', 'type2'],\n    },\n  });\n\n  /* ... */\n}\n\nfunction Draggable() {\n  const {attributes, listeners, setNodeRef, transform} = useDraggable({\n    id: 'draggable',\n    data: {\n      type: 'type1',\n    },\n  });\n\n  /* ... */\n}\n\nfunction App() {\n  return <DndContext onDragEnd={handleDragEnd}>/* ... */</DndContext>;\n\n  function handleDragEnd(event) {\n    const {active, over} = event;\n\n    if (over && over.data.current.accepts.includes(active.data.current.type)) {\n      // do stuff\n    }\n  }\n}\n```\n\n## Properties\n\n```typescript\n{\n  rect: React.MutableRefObject<LayoutRect | null>;\n  isOver: boolean;\n  node: React.RefObject<HTMLElement>;\n  over: {id: UniqueIdentifier} | null;\n  setNodeRef(element: HTMLElement | null): void;\n}\n```\n\n### Node\n\n#### `setNodeRef`\n\nIn order for the `useDroppable` hook to function properly, it needs the `setNodeRef` property to be attached to the HTML element you intend on turning into a droppable area:\n\n```jsx\nfunction Droppable(props) {\n  const {setNodeRef} = useDroppable({\n    id: props.id,\n  });\n\n  return <div ref={setNodeRef}>{/* ... */}</div>;\n}\n```\n\n#### `node`\n\nA [ref](https://reactjs.org/docs/refs-and-the-dom.html) to the current node that is passed to `setNodeRef`\n\n#### `rect`\n\nFor advanced use cases, if you need the bounding rect measurement of the droppable area.\n\n### Over\n\n#### `isOver`\n\nUse the `isOver` boolean returned by the `useDroppable` hook to change the appearance or content displayed when a `draggable` element is dragged over your droppable container.\n\n#### `over`\n\nIf you'd like to change the appearance of the droppable in response to a draggable being dragged over a different droppable container, check whether the `over` value is defined. Depending on your use-case, you can also read the `id` of the other droppable that the draggable item to make changes to the render output of your droppable component.\n\n####\n"
  },
  {
    "path": "apps/docs/legacy/api-documentation/droppable.mdx",
    "content": "---\ntitle: Droppable\ndescription: >-\n  Use the `useDroppable` hook to set up DOM nodes as droppable areas that [draggable](./draggable) elements can be dropped over.\nsidebarTitle: Overview\n---\n\n![Droppable](/images/legacy/droppable.png)\n\n## Usage\n\nThe `useDroppable` hook isn't opinionated about how you should structure your application.\n\nAt minimum though, you need to pass the `setNodeRef` function that is returned by the `useDroppable` hook to a DOM element so that it can register the underlying DOM node and keep track of it to detect collisions and intersections with other draggable elements.\n\n<Info>\n If the concept of `ref` is new to you, we recommend you first check out the [Refs and the DOM article](https://reactjs.org/docs/refs-and-the-dom.html#adding-a-ref-to-a-dom-element) on the React documentation website.\n</Info>\n\n```jsx\nimport {useDroppable} from '@dnd-kit/core';\n\nfunction Droppable() {\n  const {setNodeRef} = useDroppable({\n    id: 'unique-id',\n  });\n\n  return <div ref={setNodeRef}>/* Render whatever you like within */</div>;\n}\n```\n\nYou can set up as many droppable containers as you want, just make sure they all have a unique `id` so that they can be differentiated. Each droppable needs to have its own unique node though, so make sure you don't try to connect a single droppable to multiple refs.\n\nTo set up multiple droppable targets, simply use the `useDroppable` hook as many times as needed.\n\n```jsx\nfunction MultipleDroppables() {\n  const {setNodeRef: setFirstDroppableRef} = useDroppable({\n    id: 'droppable-1',\n  });\n  const {setNodeRef: setsecondDroppableRef} = useDroppable({\n    id: 'droppable-2',\n  });\n\n  return (\n    <section>\n      <div ref={setFirstDroppableRef}>\n        /* Render whatever you like within */\n      </div>\n      <div ref={setsecondDroppableRef}>\n        /* Render whatever you like within */\n      </div>\n    </section>\n  );\n}\n```\n\nIf you need to dynamically render a list of droppable containers, we recommend you create a re-usable Droppable component and render that component as many times as needed:\n\n```jsx\nfunction Droppable(props) {\n  const {setNodeRef} = useDroppable({\n    id: props.id,\n  });\n\n  return <div ref={setNodeRef}>{props.children}</div>;\n}\n\nfunction MultipleDroppables() {\n  const droppables = ['1', '2', '3', '4'];\n\n  return (\n    <section>\n      {droppables.map((id) => (\n        <Droppable id={id} key={id}>\n          Droppable container id: ${id}\n        </Droppable>\n      ))}\n    </section>\n  );\n}\n```\n\nFor more details usage of the `useDroppable` hook, refer to the API documentation section:\n\n<Card href=\"./droppable/use-droppable\">\n  useDroppable\n</Card>\n"
  },
  {
    "path": "apps/docs/legacy/api-documentation/modifiers.mdx",
    "content": "---\ntitle: Modifiers\ndescription: 'Transform and constrain drag movement.'\nicon: 'arrows-from-line'\n---\n\nModifiers let you dynamically modify the movement coordinates that are detected by sensors. They can be used for a wide range of use cases, for example:\n\n- Restricting motion to a single axis\n- Restricting motion to the draggable node container's bounding rectangle\n- Restricting motion to the draggable node's scroll container bounding rectangle\n- Applying resistance or clamping the motion\n\n## Installation\n\nTo start using modifiers, install the modifiers package via yarn or npm:\n\n```\nnpm install @dnd-kit/modifiers\n```\n\n## Usage\n\nThe modifiers repository contains a number of useful modifiers that can be applied on [`DndContext`](./context-provider/dnd-context) as well as [`DragOverlay`](./draggable/drag-overlay).\n\n```jsx\nimport {DndContext, DragOverlay} from '@dnd-kit';\nimport {\n  restrictToVerticalAxis,\n  restrictToWindowEdges,\n} from '@dnd-kit/modifiers';\n\nfunction App() {\n  return (\n    <DndContext modifiers={[restrictToVerticalAxis]}>\n      {/* ... */}\n      <DragOverlay modifiers={[restrictToWindowEdges]}>\n        {/* ... */}\n      </DragOverlay>\n    </DndContext>\n  )\n}\n```\n\nAs you can see from the example above, `DndContext` and `DragOverlay` can both have different modifiers.\n\n## Built-in modifiers\n\n<CardGroup cols={2}>\n  <Card title=\"restrictToHorizontalAxis\">\n    Restrict movement to only the horizontal axis.\n  </Card>\n  <Card title=\"restrictToVerticalAxis\">\n    Restrict movement to only the vertical axis.\n  </Card>\n</CardGroup>\n\n### Restrict motion to a container's bounding rectangle\n\n<CardGroup cols={2}>\n  <Card title=\"restrictToWindowEdges\">\n    Restrict movement to the edges of the window.\n  </Card>\n  <Card title=\"restrictToParentElement\">\n    Restrict movement to the parent element of the draggable item that is picked up.\n  </Card>\n  <Card title=\"restrictToFirstScrollableAncestor\">\n    Restrict movement to the first scrollable ancestor of the draggable item.\n  </Card>\n</CardGroup>\n\n### Snap to grid\n\n#### `createSnapModifier`\n\nFunction to create modifiers to snap to a given grid size.\n\n```javascript\nimport {createSnapModifier} from '@dnd-kit/modifiers';\n\nconst gridSize = 20; // pixels\nconst snapToGridModifier = createSnapModifier(gridSize);\n```\n\n## Building custom modifiers\n\nTo build your own custom modifiers, refer to the implementation of the built-in modifiers of `@dnd-kit/modifiers`: [https://github.com/clauderic/dnd-kit/tree/master/packages/modifiers/src](https://github.com/clauderic/dnd-kit/tree/master/packages/modifiers/src)\n\nFor example, here is an implementation to create a modifier to snap to grid:\n\n```javascript\nconst gridSize = 20;\n\nfunction snapToGrid(args) {\n  const {transform} = args;\n\n  return {\n    ...transform,\n    x: Math.ceil(transform.x / gridSize) * gridSize,\n    y: Math.ceil(transform.y / gridSize) * gridSize,\n  };\n }\n```\n\n\n\n"
  },
  {
    "path": "apps/docs/legacy/api-documentation/sensors/keyboard.mdx",
    "content": "---\ntitle: Keyboard\nicon: 'keyboard'\n---\n\nThe Keyboard sensor responds to [Keyboard events](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent). It is one of the default sensors used by the [DndContext](../context-provider/) provider if none are defined.\n\n<Warning>\nIn order for the Keyboard sensor to function properly, the activator element that receives the `useDraggable` [listeners](../draggable/use-draggable.md#listeners) **must** be able to receive focus. To learn more, read the in-depth [Accessibility guide](../../guides/accessibility).\n</Warning>\n\n### Activator\n\nThe keyboard activator is the `onKeyDown` event handler. The Keyboard sensor is initialized if the [`event.code`](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/code) property matches one of the `start` keys passed to `keyboardCodes` option of the Keyboard sensor.\n\nBy default, the keys that activate the Keyboard sensor are `Space` and `Enter`.\n\n### Options\n\n#### Keyboard codes\n\nThis option represents the keys that are associated with the drag `start`, `cancel` and `end` events. The `keyboardCodes` options adheres to the following interface:\n\n```typescript\ntype KeyboardCode = KeyboardEvent['code'];\n\ninterface KeyboardCodes {\n  start: KeyboardCode[];\n  cancel: KeyboardCode[];\n  end: KeyboardCode[];\n}\n```\n\nThe default values are:\n\n```javascript\nconst defaultKeyboardCodes = {\n  start: ['Space', 'Enter'],\n  cancel: ['Escape'],\n  end: ['Space', 'Enter'],\n};\n```\n\nYou can customize these values, but keep in mind that the [third rule of ARIA ](https://www.w3.org/TR/using-aria/#3rdrule)requires that a user **must** be able to activate the action associated with a draggable widget using **both** the `enter` \\(on Windows\\) or `return` \\(on macOS\\) and the `space` key. To learn more, read the in-depth [accessibility guide](../../guides/accessibility).\n\nKeep in mind that you should also customize the screen reader instructions using the `screenReaderInstructions` prop of [`<DndContext>`](../context-provider/) if you update these values, as the screen reader instructions assume that the Keyboard sensor is initialized with the default keyboard shortcuts.\n\nThe `move` keyboard codes are not a customizable option, because those are handled by the [coordinate getter function](./keyboard#coordinates-getter). To customize them, write a custom coordinate getter function.\n\n#### Coordinates getter\n\nBy default, the Keyboard sensor moves in any given direction by `25` pixels when any of the arrow keys are pressed while dragging.\n\nThis is an arbitrary sensible default that may or may not be suited to the use case you are building.\n\nThe `getNextCoordinates` option can be used to define a custom coordinate getter function that is passed the latest keyboard `event` along with the current coordinates:\n\n```javascript\nfunction customCoordinatesGetter(event, args) {\n  const {currentCoordinates} = args;\n  const delta = 50;\n\n  switch (event.code) {\n    case 'Right':\n      return {\n        ...currentCoordinates,\n        x: currentCoordinates.x + delta,\n      };\n    case 'Left':\n      return {\n        ...currentCoordinates,\n        x: currentCoordinates.x - delta,\n      };\n    case 'Down':\n      return {\n        ...currentCoordinates,\n        y: currentCoordinates.y + delta,\n      };\n    case 'Up':\n      return {\n        ...currentCoordinates,\n        y: currentCoordinates.y - delta,\n      };\n  }\n\n  return undefined;\n}\n```\n\nWhile the example above is fairly simple, you can build complex coordinate getters to support advanced use cases. The [Sortable](../../presets/sortable/) preset uses the `getNextCoordinates` option to build on top of the Keyboard sensor and move the active sortable item to its new index depending on the arrow key that is pressed.\n\n#### Scroll behavior\n\nThis option represents the [scroll behavior ](https://developer.mozilla.org/en-US/docs/Web/API/Window/scrollTo)that should be used when scrolling to new coordinates. The default value is `smooth`, which results in the scroll container being scrolled smoothly to the new coordinates.\n\nThe other possible value is `auto`, which results in the scroll container being scrolled directly to the new coordinates without any animation.\n"
  },
  {
    "path": "apps/docs/legacy/api-documentation/sensors/mouse.mdx",
    "content": "---\ntitle: Mouse\nicon: 'computer-mouse'\n---\n\nThe Mouse sensor responds to [Mouse events](https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent). Mouse events represent events that occur due to the user interacting with a pointing device \\(such as a mouse\\).\n\n### Activator\n\nThe mouse activator is the `onMouseDown` event handler. The Mouse sensor is initialized if the mouse down event was triggered by the left mouse button.\n\n### Activation constraints\n\nLike the [Pointer](./pointer) sensor, the Mouse sensor has two activation constraints:\n\n* Distance constraint\n* Delay constraint\n\nThese activation constraints are mutually exclusive and may not be used simultaneously.\n\n#### Distance\n\nThe distance constraint subscribes to the following interface:\n\n```typescript\ninterface DistanceConstraint {\n  distance: number;\n}\n```\n\nThe `distance` property represents the distance, in _pixels_, by which the mouse needs to be moved before a drag start event is emitted.\n\n#### Delay\n\nThe delay constraint subscribe to the following interface:\n\n```typescript\ninterface DelayConstraint {\n  delay: number;\n  tolerance: number;\n}\n```\n\nThe `delay` property represents the duration, in _milliseconds_, that a draggable item needs to be held by the mouse for before a drag start event is emitted.\n\nThe `tolerance` property represents the distance, in _pixels_, of motion that is tolerated before the drag operation is aborted. If the mouse is moved during the delay duration and the tolerance is set to zero, the drag operation will be immediately aborted. If a higher tolerance is set, for example, a tolerance of `5` pixels, the operation will only be aborted if the mouse is moved by more than 5 pixels during the delay.\n\n"
  },
  {
    "path": "apps/docs/legacy/api-documentation/sensors/pointer.mdx",
    "content": "---\ntitle: Pointer\nicon: 'arrow-pointer'\n---\n\nThe Pointer sensor responds to [Pointer events](https://developer.mozilla.org/en-US/docs/Web/API/Pointer_events). It is one of the default sensors used by the [DndContext](../context-provider/) provider if none are defined.\n\n> Pointer events are DOM events that are fired for a pointing device. They are designed to create a single DOM event model to handle pointing input devices such as a mouse, pen/stylus or touch (such as one or more fingers).\n>\n> The pointer is a hardware-agnostic device that can target a specific set of screen coordinates. Having a single event model for pointers can simplify creating Web sites and applications and provide a good user experience regardless of the user's hardware.\n>\n> – Source: [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Pointer_events)\n\n### Activator\n\nThe pointer activator is the `onPointerDown` event handler. The Pointer sensor is initialized if the pointer event was triggered by the [primary pointer](https://developer.mozilla.org/en-US/docs/Web/API/Pointer_events#Determining_the_Primary_Pointer).\n\nFor mouse there is only one pointer, so it will always be the primary pointer. For touch input, a pointer is considered primary if the user touched the screen when there were no other active touches. For pen and stylus input, a pointer is considered primary if the user's pen initially contacted the screen when there were no other active pens contacting the screen.\n\n### Activation constraints\n\nThe Pointer sensor has two activation constraints:\n\n- Distance constraint\n- Delay constraint\n\nThese activation constraints are mutually exclusive and may not be used simultaneously.\n\n#### Distance\n\nThe distance constraint subscribes to the following interface:\n\n```typescript\ninterface DistanceConstraint {\n  distance: number;\n}\n```\n\nThe `distance` property represents the distance, in _pixels_, by which the pointer needs to be moved before a drag start event is emitted.\n\n#### Delay\n\nThe delay constraint subscribe to the following interface:\n\n```typescript\ninterface DelayConstraint {\n  delay: number;\n  tolerance: number;\n}\n```\n\nThe `delay` property represents the duration, in _milliseconds_, that a draggable item needs to be held by the primary pointer for before a drag start event is emitted.\n\nThe `tolerance` property represents the distance, in _pixels_, of motion that is tolerated before the drag operation is aborted. If the pointer is moved during the delay duration and the tolerance is set to zero, the drag operation will be immediately aborted. If a higher tolerance is set, for example, a tolerance of `5` pixels, the operation will only be aborted if the pointer is moved by more than 5 pixels during the delay.\n\nThis property is particularly useful for touch input, where some tolerance should be accounted for when using a delay constraint, as touch input is less precise than mouse input.\n\n### Recommendations\n\n#### `touch-action`\n\nWe highly recommend you specify the `touch-action` CSS property for all of your draggable elements.\n\n> The **`touch-action`** CSS property sets how an element's region can be manipulated by a touchscreen user (for example, by zooming features built into the browser).\\\n> \\\n> Source: [MDN](https://developer.mozilla.org/en-US/docs/Web/CSS/touch-action)\n\nIn general, we recommend you set the `touch-action` property to `none` for draggable elements in order to prevent scrolling on mobile devices.\n\n<Warning>\nFor [Pointer Events,](./pointer) there is no way to prevent the default behaviour of the browser on touch devices when interacting with a draggable element from the pointer event listeners. Using `touch-action: none;` is the only way to reliably prevent scrolling for pointer events.\n</Warning>\n\nIf your draggable item is part of a scrollable list, we recommend you use a drag handle and set `touch-action` to `none` only for the drag handle, so that the contents of the list can still be scrolled, but that initiating a drag from the drag handle does not scroll the page.\n\n<Info>\nIf  the above recommendations are not suitable for your use-case, we recommend that you use both the [Mouse](./mouse) and [Touch](./touch) sensors instead, as Touch events do not suffer the same limitations as Pointer events, and it is possible to prevent the page from scrolling in `touchmove` events.\n</Info>\n\nOnce a `pointerdown` or `touchstart` event has been initiated, any changes to the `touch-action` value will be ignored. Programmatically changing the `touch-action` value for an element from `auto` to `none` after a pointer or touch event has been initiated will not result in the user agent aborting or suppressing any default behavior for that event for as long as that pointer is active (for more details, refer to the [Pointer Events Level 2 Spec](https://www.w3.org/TR/pointerevents2/#determining-supported-touch-behavior)).\n"
  },
  {
    "path": "apps/docs/legacy/api-documentation/sensors/touch.mdx",
    "content": "---\ntitle: Touch\nicon: 'hand-back-point-up'\n---\n\nThe Touch sensor responds to [Touch events](https://developer.mozilla.org/en-US/docs/Web/API/Touch_events). Touch events offer the ability to interpret finger or stylus activity on touch screens or trackpads.\n\n### Activator\n\nThe touch activator is the `onTouchStart` event handler. The Touch sensor is initialized if the there is no more than a single touch on the [`event.touches`](https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent/touches) property.\n\n### Activation constraints\n\nLike the [Pointer](./pointer) sensor, the Touch sensor has two activation constraints:\n\n- Distance constraint\n- Delay constraint\n\nThese activation constraints are mutually exclusive and may not be used simultaneously.\n\n#### Distance\n\nThe distance constraint subscribes to the following interface:\n\n```typescript\ninterface DistanceConstraint {\n  distance: number;\n}\n```\n\nThe `distance` property represents the distance, in _pixels_, by which the touch input needs to be moved before a drag start event is emitted.\n\n#### Delay\n\nThe delay constraint subscribe to the following interface:\n\n```typescript\ninterface DelayConstraint {\n  delay: number;\n  tolerance: number;\n}\n```\n\nThe `delay` property represents the duration, in _milliseconds_, that a draggable item needs to be held by the touch input before a drag start event is emitted.\n\nThe `tolerance` property represents the distance, in _pixels_, of motion that is tolerated before the drag operation is aborted. If the finger or stylus is moved during the delay duration and the tolerance is set to zero, the drag operation will be immediately aborted. If a higher tolerance is set, for example, a tolerance of `5` pixels, the operation will only be aborted if the finger is moved by more than 5 pixels during the delay.\n\nThis property is particularly useful for touch input, where some tolerance should be accounted for when using a delay constraint, as touch input is less precise than mouse input.\n\n### Recommendations\n\n#### `touch-action`\n\nWe highly recommend you specify the `touch-action` CSS property for all of your draggable elements.\n\n> The **`touch-action`** CSS property sets how an element's region can be manipulated by a touchscreen user (for example, by zooming features built into the browser).\\\n> \\\n> Source: [MDN](https://developer.mozilla.org/en-US/docs/Web/CSS/touch-action)\n\nIn general, we recommend you set the `touch-action` property to `manipulation` for draggable elements when using the Touch sensor.\n\n<Info>\nTouch events do not suffer the same limitations as Pointer events, and it is possible to prevent the page from scrolling in `touchmove` events.\n</Info>\n"
  },
  {
    "path": "apps/docs/legacy/api-documentation/sensors.mdx",
    "content": "---\ntitle: Sensors\ndescription: >-\n  Sensors are an abstraction to detect different input methods in order to initiate drag operations, respond to movement and end or cancel the operation.\nsidebarTitle: Overview\n---\n\n### Activators\n\nSensors may define one or multiple **activator events**. Activator events use React  [SyntheticEvent listeners](https://reactjs.org/docs/events.html), which leads to improved performance over manually adding event listeners to each individual draggable node.\n\nSensors are initialized once one of the activator events is detected.\n\n### Built-in sensors\n\nThe built-in sensors are:\n\n* [Pointer](./sensors/pointer)\n* [Mouse](./sensors/mouse)\n* [Touch](./sensors/touch)\n* [Keyboard](./sensors/keyboard)\n\n### Custom sensors\n\nIf necessary, you may also implement custom sensors to respond to other inputs or if the built-in sensors do not suit your needs. If you build a custom sensor and you think others could benefit, don't hesitate to open an RFC pull request.\n\n## Lifecycle\n\nThe lifecycle of a sensor is as follows:\n\n* Activator event detected, if the event is qualified, sensor class is initialized.\n* Sensor manually attaches new listeners to input methods upon initialization.\n* Sensor dispatches drag start event once constraints are met.\n* Sensor dispatches drag move events in response to input.\n* Sensor dispatches drag end or drag cancel event.\n* Sensor is torn down and cleans up manually attached event listeners.\n\nFrom an implementation perspective, Sensors are [classes](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes).\n\nThey are class-based rather than hooks because they need to be instantiated synchronously to respond to user interactions immediately, and it must be possible for them to be  conditionally invoked.\n\n## Hooks\n\n### useSensor\n\nBy default, `DndContext` uses the [Pointer](./sensors/pointer) and [Keyboard](./sensors/keyboard) sensors.\n\nIf you'd like to use other sensors, such as the Mouse and Touch sensors instead, initialize those sensors separately with the options you'd like to use using the `useSensor` hook\n\n```jsx\nimport {MouseSensor, TouchSensor, useSensor} from '@dnd-kit/core';\n\nfunction App() {\n  const mouseSensor = useSensor(MouseSensor, {\n    // Require the mouse to move by 10 pixels before activating\n    activationConstraint: {\n      distance: 10,\n    },\n  });\n  const touchSensor = useSensor(TouchSensor, {\n    // Press delay of 250ms, with tolerance of 5px of movement\n    activationConstraint: {\n      delay: 250,\n      tolerance: 5,\n    },\n  });\n}\n```\n\n### useSensors\n\nWhen initializing sensors with `useSensor`, make sure you pass the sensors to `useSensors` before passing them to `DndContext`:\n\n```jsx\nimport {\n  DndContext,\n  KeyboardSensor,\n  MouseSensor,\n  TouchSensor,\n  useSensor,\n  useSensors,\n} from '@dnd-kit/core';\n\nfunction App() {\n  const mouseSensor = useSensor(MouseSensor);\n  const touchSensor = useSensor(TouchSensor);\n  const keyboardSensor = useSensor(KeyboardSensor);\n\n  const sensors = useSensors(\n    mouseSensor,\n    touchSensor,\n    keyboardSensor,\n  );\n\n  return (\n    <DndContext sensors={sensors}>\n      {/* ... */}\n    </DndContext>\n  )\n}\n```\n\nIn other examples across the documentation, you may also see sensors initialized without intermediate variables, which is equivalent to the syntax above:\n\n```jsx\nimport {\n  DndContext,\n  KeyboardSensor,\n  MouseSensor,\n  TouchSensor,\n  useSensor,\n  useSensors,\n} from '@dnd-kit/core';\n\nfunction App() {\n  const sensors = useSensors(\n    useSensor(MouseSensor),\n    useSensor(TouchSensor),\n    useSensor(KeyboardSensor),\n  );\n\n  return (\n    <DndContext sensors={sensors}>\n      {/* ... */}\n    </DndContext>\n  )\n}\n```\n\n"
  },
  {
    "path": "apps/docs/legacy/guides/accessibility.mdx",
    "content": "---\ntitle: Accessibility\ndescription: >-\n  Learn how to make your drag and drop interfaces accessible with @dnd-kit/core\nicon: universal-access\n---\n\n## Introduction\n\nIf you're new to accessibility for the web, the _Web Almanac by HTTP Archive_ has an excellent primer on the subject and the state of web accessibility that you should read before diving into this guide: [https://almanac.httparchive.org/en/2021/accessibility](https://almanac.httparchive.org/en/2021/accessibility)\n\n> Web accessibility is about achieving feature and information parity and giving complete access to all aspects of an interface to disabled people.\n>\n> A digital product or website is simply not complete if it is not usable by everyone. If it excludes certain disabled populations, this is discrimination and potentially grounds for fines and/or lawsuits.\n>\n> – Source: [Web Almanac by HTTP Archive](https://almanac.httparchive.org/en/2020/accessibility#screen-reader-only-text)\n\nPeople with varying disabilities use different assistive technologies to help them experience the web.\n\nThe [Tools and Techniques](https://www.w3.org/WAI/people-use-web/tools-techniques/) article from the Web Accessibility Initiative (WAI) of the W3C covers how users can perceive, understand and interact with the web using different assistive technologies.\n\nSome assistive technologies for the web include:\n\n- Screen readers\n- Voice control\n- Screen magnifiers\n- Input devices (such as the keyboard, pointers and switch devices)\n\nWhen building accessible interfaces for the web, it's important to keep the three following questions in mind:\n\n1. **Identity:** What element is the user interacting with?\n2. **Operation:** How can the user interact with the element?\n3. **State:** What is the current state of the element?\n\nIn this guide, we'll focus on how to make drag and drop interfaces that are keyboard accessible and provide identity, operation instructions and live state updates for screen readers.\n\n## Building accessible drag and drop interfaces\n\nBuilding drag and drop interfaces that are accessible to everyone isn't easy, and requires thoughtful consideration.\n\nThe `@dnd-kit/core` library provides a number of sensible defaults to help you make your drag and drop interfaces accessible.\n\nThese sensible defaults should be seen as _starting points_ rather than something you can set and forget; there is no one-size-fits-all solution to web accessibility.\n\nYou know your application best, and while these sensible defaults will go a long way to help making your application more accessible, in most cases you'll want to customize these so that they are tailored to the context of your application.\n\nThe three main areas of focus for this guide to help you make your drag and drop interface more accessible are:\n\n- [Keyboard support](./accessibility#keyboard-support)\n- [Screen reader instructions](./accessibility#screen-reader-instructions)\n- [Live regions to provide screen reader announcements](./accessibility#screen-reader-announcements-using-live-regions)\n\n### Keyboard support\n\nOne of the[ five rules of ARIA](https://www.w3.org/TR/using-aria/#rule3) is that all interactive ARIA controls must be usable with the keyboard.\n\nWhen creating widgets that a user can click or tap, drag, and drop, a user must also be able to **navigate to the widget** and **perform an equivalent action using the keyboard**.\n\nFor drag and drop interfaces, this means that the activator element that initiates the drag action must:\n\n- Be able to receive focus\n- A user must be able to activate the action associated with the element using **both** the `enter` (on Windows) or `return` (on macOS) and the `space` key.\n\nBoth these guidelines should be respected to comply with the [third rule of ARIA](https://www.w3.org/TR/using-aria/#3rdrule).\n\nThe `@dnd-kit/core` library ships with a [Keyboard sensor ](../api-documentation/sensors/keyboard)that adheres to these guidelines. The keyboard sensor is one of the two sensors that are enabled by default on the [`<DndContext>`](../api-documentation/context-provider/) provider component.\n\n#### Focus\n\nIn order for the Keyboard sensor to function properly, the activator element that receives the `useDraggable` [listeners](../api-documentation/draggable/use-draggable#listeners) **must** be able to receive focus.\n\nThe `tabindex` attribute dictates the order in which focus moves throughout the document.\n\n- Natively interactive elements such as [buttons](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button), [anchor tags](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a) and[ form controls ](https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormControlsCollection)have a default `tabindex` value of `0`.\n- Custom elements that are intended to be interactive and receive keyboard focus need to have an explicitly assigned `tabindex=\"0\"`(for example, `div` and `li` elements)\n\nIn other words, in order for your draggable activator elements to be able to receive keyboard focus, they _need_ to have the `tabindex` attribute set to `0` **if** they are not natively interactive elements (such as the HTML `button` element).\n\nFor this reason, the `useDraggable` hook sets the `tabindex=\"0\"` attribute by default.\n\n#### Keyboard shortcuts\n\nOnce a draggable activator element receives focus, the `enter` (on Windows) or `return` (on macOS) and the `space` keys can be used to initiate a drag operation and pick up the draggable item.\n\nThe arrow keys are used to move the draggable item in any given direction.\n\nAfter an item is picked up, it can be dropped using the `enter` (on Windows) or `return` (on macOS) and the `space` keys.\n\nA drag operation can be cancelled using the `escape` key. It is recommended to allow users to cancel the drag operation using the `escape` key for all sensors, not just the Keyboard sensor.\n\nThe keyboard shortcuts of the Keyboard sensor can be [customized](../api-documentation/sensors/keyboard#keyboard-codes), but we discourage you to do so unless you maintain support for the `enter`, `return` and `space` keys to follow the guidelines set by the third rule of ARIA.\n\nBy default, the [Keyboard sensor](../api-documentation/sensors/keyboard) moves in any given direction by `25` pixels when the arrow keys are pressed while dragging.\n\nThis is an arbitrary default that is likely not suited for all use-cases. We encourage you to customize this behaviour and tailor it to the context of your application using the [`getNextCoordinates` option ](../api-documentation/sensors/keyboard#coordinates-getter)of the Keyboard sensor.\n\nFor example, the `useSortable` hook ships with an augmented version of the Keyboard sensor that uses the `getNextCoordinates` option behind the scenes to find the coordinates of the next sortable element in any given direction when an arrow key is pressed.\n\nIn order to let users learn how to interact with draggable elements using these keyboard shortcuts, it's important to provide screen reader instructions.\n\n### Screen reader instructions\n\nIn order to users know how to interact with draggable items using only the keyboard, it's important to provide information to the user that their focus is currently on a draggable item, along with clear instruction on how to pick up a a draggable item, how to move it, how to drop it and how to cancel the operation.\n\n#### Role\n\nTo let users know that their focus is currently on a draggable item, the [`useDraggable`](../api-documentation/draggable/use-draggable) hook provides the [`role`](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles) and [`aria-roledescription`](https://www.digitala11y.com/aria-roledescriptionproperties/), and [`aria-describedby`](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques/Using_the_aria-describedby_attribute) attributes by default:\n\n| Attribute              | Default value             | Description                                                                                                                                                                                                                                                                                                                                                                                                                                             |\n| ---------------------- | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `role`                 | `\"button\"`                | The ARIA <code>\"role\"</code> attribute lets you explicitly define the role for an element, which communicates its purpose to assistive technologies.<br/>If possible, we recommend you use a semantic <code>&#x3C;button></code> element for the DOM element you plan on attaching draggable listeners to. <br/><br/>In case that's not possible, make sure you include the <code>role=\"button\"</code>attribute, which is the default value. |\n| `aria-roledescription` | `\"draggable\"`             | Defines a human-readable, localized description for the role of an element that is read by screen readers.<br/>While <code>draggable</code> is a sensible default, we recommend you customize this value to something that is tailored to your use-case.                                                                                                                                                                                   |\n| `aria-describedby`     | `\"DndContext-[uniqueId]\"` | Each draggable item is provided a unique `aria-describedby` ID that points to the voiceover instructions to be read out when a draggable item receives focus                                                                                                                                                                                                                                                                                            |\n\nThe `role` and `aria-roledescription` attributes can be customized via the [options passed to the `useDraggable` hook](../api-documentation/draggable/use-draggable#arguments).\n\nTo customize the `aria-describedby` instructions, refer to the section below.\n\n#### Instructions\n\nBy default, each [`<DndContext>`](../api-documentation/context-provider/) component renders a unique HTML element that is rendered off-screen to be used to provide these instructions to screen readers.\n\nThe default instructions are:\n\n> To pick up a draggable item, press space or enter. \\\n> While dragging, use the arrow keys to move the item in any given direction.\\\n> Press space or enter again to drop the item in its new position, or press escape to cancel.\n\nWe recommend you customize and localize these instructions to your application and use-case using the `screenReaderInstructions` prop of [`<DndContext>`](../api-documentation/context-provider/dnd-context).\n\nFor example, if you were building a sortable grocery shopping list, you may want to tailor the instructions like so:\n\n> To pick up a grocery list item, press space or enter. \\\n> Use the up and down arrow keys to update the position of the item in the grocery list.\\\n> Press space or enter again to drop the item in its new position, or press escape to cancel.\n\nIf your application supports multiple languages, make sure you also translate these instructions. The `<DndContext>` component only ships with instructions in English due to bundle size concerns.\n\n### Screen reader announcements using live regions\n\n[Live regions](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Live_Regions) are used to notify screen readers of content changes.\n\nWhen building accessible drag and drop interfaces, live regions should be used to provide screen reader announcements in real-time of time-sensitive information of what is currently happening with draggable and droppable elements without having to move focus .\n\nBy default, each [`<DndContext>`](../api-documentation/context-provider/dnd-context) component renders a unique HTML element that is rendered off-screen to be used for live screen-reader announcements of events like when a drag operation has started, when a draggable item has been dragged over a droppable container, when a drag operation has ended, and when a drag operation has been cancelled.\n\nThese instructions can be customized using the `announcements` prop of `DndContext`.\n\nThe default announcements are:\n\n```javascript\nconst defaultAnnouncements = {\n  onDragStart({active}) {\n    return `Picked up draggable item ${active.id}.`;\n  },\n  onDragOver({active, over}) {\n    if (over) {\n      return `Draggable item ${active.id} was moved over droppable area ${over.id}.`;\n    }\n\n    return `Draggable item ${active.id} is no longer over a droppable area.`;\n  },\n  onDragEnd({active, over}) {\n    if (over) {\n      return `Draggable item ${active.id} was dropped over droppable area ${over.id}`;\n    }\n\n    return `Draggable item ${active.id} was dropped.`;\n  },\n  onDragCancel({active}) {\n    return `Dragging was cancelled. Draggable item ${active.id} was dropped.`;\n  },\n};\n```\n\nWhile these default announcements are sensible defaults that should cover most simple use cases, you know your application best, and we highly recommend that you customize these to provide a screen reader experience that is more tailored to the use case you are building.\n\n<Info>\nWhen authoring screen reader announcements that rely on an element's position (index) in a list, use positions rather than indices to describe the element's current position.\n\nHere's an example of index based announcements and why you should avoid them:\n\n> Item with index 0 was picked up. Item was moved to index 1 of 4.\n\nPosition based announcements are much more intuitive and natural:\n\n> Item at position 1 was picked up. Item was moved to position 2 of 5.\n\n</Info>\n\nFor example, when building a sortable list, you could write custom announcements that are tailored to that use-case using position based announcements:\n\n```javascript\nfunction App() {\n  const items = useState(['Apple', 'Orange', 'Strawberries', 'Raspberries']);\n  const getPosition = (id) => items.indexOf(id) + 1; // prefer position over index\n  const itemCount = items.length;\n\n  const announcements = {\n    onDragStart({active}) {\n      return `Picked up sortable item ${active.id}. Sortable item ${active.id} is in position ${getPosition(id)} of ${itemCount}`;\n    },\n    onDragOver({active, over}) {\n      if (over) {\n        return `Sortable item ${active.id} was moved into position ${getPosition(over.id)} of ${itemCount}`;\n      }\n    },\n    onDragEnd({active, over}) {\n      if (over) {\n        return `Sortable item ${active.id} was dropped at position ${getPosition(over.id)} of ${itemCount}`;\n      }\n    },\n    onDragCancel({active}) {\n      return `Dragging was cancelled. Sortable item ${active.id} was dropped.`;\n    },\n  };\n\n  return (\n    <DndContext\n      accessibility={\n        announcements,\n      }\n    >\n```\n\nThe example above assumes that the [`closestCenter` collision detection strategy](../api-documentation/context-provider/collision-detection-algorithms#closest-center) is used, so the `over` property should always be defined.\n\nIf your application supports multiple languages, make sure you also translate these announcements. The `<DndContext>` component only ships with announcements in English due to bundle size concerns.\n"
  },
  {
    "path": "apps/docs/legacy/introduction/getting-started.mdx",
    "content": "---\ntitle: Quickstart\ndescription: >-\n  Eager to get started? This quick start guide will help you familiarize\n  yourself with the core concepts of dnd kit.\n---\n\n\n<Info>\nBefore getting started, make sure you have followed the installation steps outlined in the [Installation guide](./installation).\n</Info>\n\n### Context provider\n\nFirst, we'll set up the general structure of the app. In order for the [`useDraggable`](../api-documentation/draggable/use-draggable) and [`useDroppable`](../api-documentation/droppable/use-droppable) hooks to function correctly, you'll need to ensure that the components where they are used are wrapped within a [`<DndContext />`](../api-documentation/context-provider/dnd-context) component:\n\n```jsx App.jsx\nimport React from 'react';\nimport {DndContext} from '@dnd-kit/core';\n\nimport {Draggable} from './Draggable';\nimport {Droppable} from './Droppable';\n\nfunction App() {\n  return (\n    <DndContext>\n      <Draggable />\n      <Droppable />\n    </DndContext>\n  );\n}\n```\n\n### Droppable\n\n![Droppable](/images/legacy/droppable.png)\n\nNext, let's set up your first **Droppable** component. To do so, we'll be using the `useDroppable` hook.\\\n\\\nThe `useDroppable` hook isn't opinionated about how your app should be structured. At minimum though, it requires you pass a [ref](https://reactjs.org/docs/refs-and-the-dom.html) to the DOM element that you would like to become droppable. You'll also need to provide a unique `id` attribute to all your droppable components.\n\nWhen a **draggable** element is moved over your droppable element, the `isOver` property will become true.\n\n```jsx Droppable.jsx\nimport React from 'react';\nimport {useDroppable} from '@dnd-kit/core';\n\nfunction Droppable(props) {\n  const {isOver, setNodeRef} = useDroppable({\n    id: 'droppable',\n  });\n  const style = {\n    color: isOver ? 'green' : undefined,\n  };\n\n  return (\n    <div ref={setNodeRef} style={style}>\n      {props.children}\n    </div>\n  );\n}\n```\n\n### Draggable\n\n![Draggable](/images/legacy/draggable.png)\n\nNext, let's take a look at implementing our first **Draggable** component. To do so, we'll be using the `useDraggable` hook.\n\nThe `useDraggable` hook isn't opinionated about how your app should be structured. It does however require you to be able to attach listeners and a ref to the DOM element that you would like to become draggable. You'll also need to provide a unique `id` attribute to all your draggable components.\n\nAfter a draggable item is picked up, the `transform` property will be populated with the `translate` coordinates you'll need to move the item on the screen.\n\nThe `transform` object adheres to the following shape: `{x: number, y: number, scaleX: number, scaleY: number}`\n\n```jsx Draggable.jsx\nimport React from 'react';\nimport {useDraggable} from '@dnd-kit/core';\n\nfunction Draggable(props) {\n  const {attributes, listeners, setNodeRef, transform} = useDraggable({\n    id: 'draggable',\n  });\n  const style = transform\n    ? {\n        transform: `translate3d(${transform.x}px, ${transform.y}px, 0)`,\n      }\n    : undefined;\n\n  return (\n    <button ref={setNodeRef} style={style} {...listeners} {...attributes}>\n      {props.children}\n    </button>\n  );\n}\n```\n\nAs you can see from the example above, it really only takes just a few lines to transform your existing components into draggable components.\n\n<Success>\n**Tips:**\n\n- For performance reasons, we recommend you use **`transform`** over other positional CSS properties to move the dragged element.\n- You'll likely want to alter the **`z-index`** of your Draggable component to ensure it appears on top of other elements.\n- If your item needs to move from one container to another, we recommend you use the [`<DragOverlay>`](../api-documentation/draggable/drag-overlay) component.\n</Success>\n\nConverting the `transform` object to a string can feel tedious. Fear not, you can avoid having to do this by hand by importing the `CSS` utility from the `@dnd-kit/utilities` package:\n\n```jsx\nimport {CSS} from '@dnd-kit/utilities';\n\n// Within your component that receives `transform` from `useDraggable`:\nconst style = {\n  transform: CSS.Translate.toString(transform),\n};\n```\n\n### Assembling all the pieces\n\nOnce you've set up your **Droppable** and **Draggable** components, you'll want to come back to where you set up your [`<DndContext>`](../api-documentation/context-provider/) component so you can add event listeners to be able to respond to the different events that are fired.\n\nIn this example, we'll assume you want to move your `<Draggable>` component from outside into your `<Droppable>` component:\n\n![A draggable item is moved towards a droppable container](/images/legacy/draggable-droppable.png)\n\nTo do so, you'll want to listen to the `onDragEnd` event of the `<DndContext>` to see if your draggable item was dropped over your droppable:\n\n<CodeGroup>\n\n```jsx App.jsx\nimport React, {useState} from 'react';\nimport {DndContext} from '@dnd-kit/core';\n\nimport {Droppable} from './Droppable';\nimport {Draggable} from './Draggable';\n\nfunction App() {\n  const [isDropped, setIsDropped] = useState(false);\n  const draggableMarkup = <Draggable>Drag me</Draggable>;\n\n  return (\n    <DndContext onDragEnd={handleDragEnd}>\n      {!isDropped ? draggableMarkup : null}\n      <Droppable>{isDropped ? draggableMarkup : 'Drop here'}</Droppable>\n    </DndContext>\n  );\n\n  function handleDragEnd(event) {\n    if (event.over && event.over.id === 'droppable') {\n    setIsDropped(true);\n  }\n}\n```\n\n```jsx Droppable.jsx\nimport React from 'react';\nimport {useDroppable} from '@dnd-kit/core';\n\nexport function Droppable(props) {\n  const {isOver, setNodeRef} = useDroppable({\n    id: 'droppable',\n  });\n  const style = {\n    color: isOver ? 'green' : undefined,\n  };\n\n  return (\n    <div ref={setNodeRef} style={style}>\n      {props.children}\n    </div>\n  );\n}\n```\n\n```jsx Draggable.jsx\nimport React from 'react';\nimport {useDraggable} from '@dnd-kit/core';\n\nexport function Draggable(props) {\n  const {attributes, listeners, setNodeRef, transform} = useDraggable({\n    id: 'draggable',\n  });\n  const style = transform\n    ? {\n        transform: `translate3d(${transform.x}px, ${transform.y}px, 0)`,\n      }\n    : undefined;\n\n  return (\n    <button ref={setNodeRef} style={style} {...listeners} {...attributes}>\n      {props.children}\n    </button>\n  );\n}\n```\n\n</CodeGroup>\n\nThat's it! You've set up your first [**Droppable**](../api-documentation/droppable) \\***\\* and [**Draggable\\*\\*](../api-documentation/draggable) components.\n\n### Pushing things a bit further\n\nThe example we've set up above is a bit simplistic. In a real world example, you may have multiple droppable containers, and you may also want to be able to drag your items back out of the droppable containers once they've been dragged within them.\n\nHere's a slightly more complex example that contains multiple **Droppable** containers:\n\n<CodeGroup>\n```jsx App.jsx\nimport React, {useState} from 'react';\nimport {DndContext} from '@dnd-kit/core';\n\nimport {Droppable} from './Droppable';\nimport {Draggable} from './Draggable';\n\nfunction App() {\n  const containers = ['A', 'B', 'C'];\n  const [parent, setParent] = useState(null);\n  const draggableMarkup = <Draggable id=\"draggable\">Drag me</Draggable>;\n\n  return (\n    <DndContext onDragEnd={handleDragEnd}>\n      {parent === null ? draggableMarkup : null}\n\n      {containers.map((id) => (\n        // We updated the Droppable component so it would accept an `id`\n        // prop and pass it to `useDroppable`\n        <Droppable key={id} id={id}>\n          {parent === id ? draggableMarkup : 'Drop here'}\n        </Droppable>\n      ))}\n    </DndContext>\n  );\n\n  function handleDragEnd(event) {\n    const {over} = event;\n\n    // If the item is dropped over a container, set it as the parent\n    // otherwise reset the parent to `null`\n    setParent(over ? over.id : null);\n  }\n}\n\n```\n\n```jsx Droppable.jsx\nimport React from 'react';\nimport {useDroppable} from '@dnd-kit/core';\n\nexport function Droppable(props) {\n  const {isOver, setNodeRef} = useDroppable({\n    id: props.id,\n  });\n  const style = {\n    color: isOver ? 'green' : undefined,\n  };\n\n  return (\n    <div ref={setNodeRef} style={style}>\n      {props.children}\n    </div>\n  );\n}\n```\n\n```jsx Draggable.jsx\nimport React from 'react';\nimport {useDraggable} from '@dnd-kit/core';\n\nexport function Draggable(props) {\n  const {attributes, listeners, setNodeRef, transform} = useDraggable({\n    id: props.id,\n  });\n  const style = transform\n    ? {\n        transform: `translate3d(${transform.x}px, ${transform.y}px, 0)`,\n      }\n    : undefined;\n\n  return (\n    <button ref={setNodeRef} style={style} {...listeners} {...attributes}>\n      {props.children}\n    </button>\n  );\n}\n```\n\n</CodeGroup>\n\nWe hope this quick start guide has given you a glimpse of the simplicity and power of @dnd-kit. There's much more to learn, and we encourage you to keep reading about all of the different options you can pass to `<DndContext>` , `useDroppable` and `useDraggable` by reading their respective API documentation.\n"
  },
  {
    "path": "apps/docs/legacy/introduction/installation.mdx",
    "content": "---\ntitle: Installation\ndescription: 'Installing @dnd-kit/core'\n---\n\n<Note>\nThere's a new version of **@dnd-kit** available. We recommend you use the [latest version](/overview) instead.\n</Note>\n\nTo get started with the legacy version of **@dnd-kit**, install the core library via `npm` or `yarn`:\n\n```\nnpm install @dnd-kit/core\n```\n\nYou'll also need to be make sure you have peer dependencies installed. Chances are you already have `react` and `react-dom` installed in your project, but if not, make sure to install them:\n\n```bash\nnpm install react react-dom\n```\n\n## Packages\n\n<Info>\n**@dnd-kit** is a [monorepo](https://en.wikipedia.org/wiki/Monorepo). Depending on your needs, you may also want to install other  sub-packages that are available under the `@dnd-kit` namespace.\n</Info>\n\n### Core library\n\nIn order to keep the core of the library small, `@dnd-kit/core` only ships with the main building blocks that the majority of users will need most of the time for building drag and drop experiences:\n\n* [Context provider](../api-documentation/context-provider/)\n* Hooks for:\n  * [Draggable](../api-documentation/draggable)\n  * [Droppable](../api-documentation/droppable)\n* [Drag Overlay](../api-documentation/draggable/drag-overlay)\n* Sensors for:\n  * [Pointer](../api-documentation/sensors/pointer)\n  * [Mouse](../api-documentation/sensors/mouse)\n  * [Touch](../api-documentation/sensors/touch)\n  * [Keyboard](../api-documentation/sensors/keyboard)\n* [Accessibility features](../guides/accessibility)\n\n### Modifiers\n\nModifiers let you dynamically modify the movement coordinates that are detected by sensors. They can be used for a wide range of use cases, for example:\n\n* Restricting motion to a single axis\n* Restricting motion to the draggable node container's bounding rectangle\n* Restricting motion to the draggable node's scroll container bounding rectangle\n* Applying resistance or clamping the motion\n\nThe modifiers repository contains a number of useful modifiers that can be applied on [`DndContext`](../api-documentation/context-provider/) as well as [`DraggableClone`](../api-documentation/draggable/drag-overlay).\n\nTo start using modifiers, install the modifiers package via yarn or npm:\n\n```\nnpm install @dnd-kit/modifiers\n```\n\n### Presets\n\n#### [Sortable](../presets/sortable/)\n\nThe `@dnd-kit/core` package provides all the building blocks you would need to build a sortable interface from scratch should you choose to, but thankfully you don't need to.\n\nIf you plan on building a sortable interface, we highly recommend you try out `@dnd-kit/sortable`, which is a small layer built on top of `@dnd-kit/core` and optimized for building silky smooth, flexible, and accessible sortable interfaces.\n\n```\nnpm install @dnd-kit/sortable\n```\n\n## Development releases\n\nEach commit merged into the @dnd-kit main branch will trigger a development build to be released to npm under the `next` tag.\n\nTo try a development release before the official release, install each @dnd-kit package you intend to use with the `@next`tag\n\n```\nnpm install @dnd-kit/core@next @dnd-kit/sortable@next\n```\n\n<Info>\nDevelopment releases can be unstable, we recommend you lock to a specific development release if you intend to use them in production.\n</Info>\n"
  },
  {
    "path": "apps/docs/legacy/presets/sortable/overview.mdx",
    "content": "---\ntitle: Sortable\nsidebarTitle: Overview\ndescription: >-\n  The sortable preset provides the building blocks to build  sortable\n  interfaces.\n---\n\n## Installation\n\nTo get started, install the sortable preset via `npm` or `yarn`:\n\n```bash\nnpm install @dnd-kit/sortable\n```\n\n## Overview\n\nIf you're eager to get started right away, here's the code you'll need:\n\n<CodeGroup>\n\n```jsx App.jsx\nimport React, {useState} from 'react';\nimport {\n  DndContext,\n  closestCenter,\n  KeyboardSensor,\n  PointerSensor,\n  useSensor,\n  useSensors,\n} from '@dnd-kit/core';\nimport {\n  arrayMove,\n  SortableContext,\n  sortableKeyboardCoordinates,\n  verticalListSortingStrategy,\n} from '@dnd-kit/sortable';\n\nimport {SortableItem} from './SortableItem';\n\nfunction App() {\n  const [items, setItems] = useState([1, 2, 3]);\n  const sensors = useSensors(\n    useSensor(PointerSensor),\n    useSensor(KeyboardSensor, {\n      coordinateGetter: sortableKeyboardCoordinates,\n    })\n  );\n\n  return (\n    <DndContext\n      sensors={sensors}\n      collisionDetection={closestCenter}\n      onDragEnd={handleDragEnd}\n    >\n      <SortableContext items={items} strategy={verticalListSortingStrategy}>\n        {items.map((id) => (\n          <SortableItem key={id} id={id} />\n        ))}\n      </SortableContext>\n    </DndContext>\n  );\n\n  function handleDragEnd(event) {\n    const {active, over} = event;\n\n    if (active.id !== over.id) {\n      setItems((items) => {\n        const oldIndex = items.indexOf(active.id);\n        const newIndex = items.indexOf(over.id);\n\n        return arrayMove(items, oldIndex, newIndex);\n      });\n    }\n  }\n}\n```\n\n```jsx SortableItem.jsx\nimport React from 'react';\nimport {useSortable} from '@dnd-kit/sortable';\nimport {CSS} from '@dnd-kit/utilities';\n\nexport function SortableItem(props) {\n  const {attributes, listeners, setNodeRef, transform, transition} =\n    useSortable({id: props.id});\n\n  const style = {\n    transform: CSS.Transform.toString(transform),\n    transition,\n  };\n\n  return (\n    <div ref={setNodeRef} style={style} {...attributes} {...listeners}>\n      {/* ... */}\n    </div>\n  );\n}\n```\n\n</CodeGroup>\n\nFor most sortable lists, we recommend you use a [`DragOverlay`](../../api-documentation/draggable/drag-overlay) if your sortable list is scrollable or if the contents of the scrollable list are taller than the viewport of the window. Check out the[ sortable drag overlay guide](./#drag-overlay) below to learn more.\n\n## Architecture\n\nThe sortable preset builds on top of the primitives exposed by `@dnd-kit/core` to help building sortable interfaces.\n\nThe sortable preset exposes two main concepts: [`SortableContext`](#sortable-context) and the [`useSortable`](#usesortable) hook:\n\n- The `SortableContext` provides information via context that is consumed by the `useSortable` hook.\n- The `useSortable` hook is an abstraction that composes the [`useDroppable`](../../api-documentation/droppable) and [`useDraggable`](../../api-documentation/draggable) hooks:\n\n![The useSortable hook](/images/legacy/use-sortable.png)\n\n### Single container\n\nAt a high level, the application structure to implement a **sortable list with a single container** looks as follows:\n\n![A single container sortable list](/images/legacy/sortable-list.png)\n\n### Multiple containers\n\nTo implement sortable list with items that can be dropped within **multiple containers**, the application structure is the same, but we add as many `SortableContext` providers as we have containers:\n\n![A multiple container sortable list](/images/legacy/sortable-multiple-containers-example.png)\n\nIn this example, we would use the `onDragOver` callback of `DndContext` to detect when a draggable element is moved over a different container to insert it in that new container while dragging.\n\nIf you paid close attention to the illustration above, you may also have noticed that we added a droppable zone around each sortable context. This isn't required, but will likely be the behaviour most people want. If you move all sortable items from one column into the other, you will need a droppable zone for the empty column so that you may drag sortable items back into that empty column:\n\n![A multiple container sortable list with an empty column](/images/legacy/sortable-multiple-containers-empty-column.png)\n\n## Concepts\n\n### Sortable Context\n\nIn addition to the [`DndContext` provider](../../introduction/getting-started.md#context-provider), the Sortable preset requires its own context provider that contains the **sorted** array of the unique identifiers associated to each sortable item:\n\n```jsx\nimport React, {useState} from 'react';\nimport {DndContext} from '@dnd-kit/core';\nimport {SortableContext} from '@dnd-kit/sortable';\n\nfunction App() {\n  const [items] = useState(['1', '2', '3']);\n\n  return (\n    <DndContext>\n      <SortableContext items={items}>{/* ... */}</SortableContext>\n    </DndContext>\n  );\n}\n```\n\nThe `SortableContext` provides information via context that is consumed by the `useSortable` hook, which is covered in greater detail in the next section.\n\n<Info>\nIt's important that the `items` prop passed to `SortableContext` be sorted in the same order in which the items are rendered, otherwise you may see unexpected results.\n</Info>\n\nIt does not expose any callback props. To know when a sortable (draggable) item is being picked or moved over another sortable (droppable) item, use the callback props of `DndContext`:\n\n```jsx\nimport React, {useState} from 'react';\nimport {DndContext} from '@dnd-kit/core';\nimport {SortableContext} from '@dnd-kit/sortable';\n\nfunction App() {\n  const [items] = useState(['1', '2', '3']);\n\n  return (\n    <DndContext onDragEnd={handleDragEnd}>\n      <SortableContext items={items}>{/* ... */}</SortableContext>\n    </DndContext>\n  );\n\n  function handleDragEnd(event) {\n    /* ... */\n  }\n}\n```\n\n<Warning>\nIn order for the `SortableContext` component to function properly, make sure it is a descendant of a `DndContext` provider. You may nest multiple `SortableContext` components within the same parent `DndContext`.\n</Warning>\n\n### useSortable\n\nAs outlined above, the `useSortable` hook combines both the [`useDraggable`](../../api-documentation/draggable) and [`useDroppable`](../../api-documentation/droppable) hooks to connect elements as both draggable sources and drop targets:\n\n<Info>\nIn most cases, the draggable and droppable hooks will be attached to the same node, and therefore be identical in size. They are represented as different nodes for illustration purposes above.\n</Info>\n\nIf you're already familiar with the [`useDraggable`](../../api-documentation/draggable) hook, the [`useSortable`](./use-sortable) hook should look very familiar, since, it is an abstraction on top of it.\n\nIn addition to the `attributes`, `listeners`,`transform` and `setNodeRef` properties, which you should already be familiar with if you've used the `useDraggable` hook before, you'll notice that the `useSortable` hook also provides a `transition` property.\n\nThe `transform` property for `useSortable` represents the displacement and change of scale transformation that a sortable item needs to apply to transition to its new position without needing to update the DOM order.\n\nThe `transform` property for the `useSortable` hook behaves similarly to the [`transform`](../../api-documentation/draggable/#transforms) property of the [`useDraggable`](../../api-documentation/draggable) hook for the active sortable item, when there is no [`DragOverlay`](../../api-documentation/draggable/drag-overlay) being used.\n\n<CodeGroup>\n```jsx SortableItem.jsx\nimport React from 'react';\nimport {useSortable} from '@dnd-kit/sortable';\nimport {CSS} from '@dnd-kit/utilities';\n\nfunction SortableItem(props) {\n  const {\n    attributes,\n    listeners,\n    setNodeRef,\n    transform,\n    transition\n  } = useSortable({id: props.id});\n\n  const style = {\n    transform: CSS.Transform.toString(transform),\n    transition,\n  };\n\n  return (\n    <div ref={setNodeRef} style={style} {...attributes} {...listeners}>\n      ...\n    </div>\n  );\n}\n\n```\n\n</CodeGroup>\n\nThe default transition is `250` milliseconds, with an easing function set to `ease`, but you can customize this and pass any valid [CSS transition timing function](https://developer.mozilla.org/en-US/docs/Web/CSS/transition-timing-function), or set the transition argument to `null` to disable transitions entirely:\n\n```javascript\nconst {transition} = useSortable({\n  id: props.id,\n  transition: {\n    duration: 150, // milliseconds\n    easing: 'cubic-bezier(0.25, 1, 0.5, 1)',\n  },\n});\n```\n\nFor more details on the `useSortable` hook, read the full [API documentation](./use-sortable).\n\n### Sensors\n\nSensors are an abstraction to manage and listen to different input methods. If you're unfamiliar with the concept of sensors, we recommend you read the [introduction to sensors](../../api-documentation/sensors/) first.\n\nBy default, the [Keyboard](../../api-documentation/sensors/keyboard) sensor moves the active draggable item by `25` pixels in the direction of the arrow key that was pressed. This is an arbitrary default, and can be customized using the `coordinateGetter` option of the keyboard sensor.\n\nThe sortable preset ships with a custom coordinate getter function for the keyboard sensor that moves the active draggable to the closest sortable element in a given direction within the same `DndContext`.\n\nTo use it, import the `sortableKeyboardCoordinates` coordinate getter function provided by `@dnd-kit/sortable`, and pass it to the `coordiniateGetter` option of the Keyboard sensor.\n\nIn this example, we'll also be setting up the [Pointer](../../api-documentation/sensors/pointer) sensor, which is the other sensor that is enabled by default on `DndContext` if none are defined. We use the `useSensor` and `useSensors` hooks to initialize the sensors:\n\n```jsx\nimport {\n  DndContext,\n  KeyboardSensor,\n  PointerSensor,\n  useSensor,\n  useSensors,\n} from '@dnd-kit/core';\nimport {SortableContext, sortableKeyboardCoordinates} from '@dnd-kit/sortable';\n\nfunction App() {\n  const [items] = useState(['1', '2', '3']);\n  const sensors = useSensors(\n    useSensor(PointerSensor),\n    useSensor(KeyboardSensor, {\n      coordinateGetter: sortableKeyboardCoordinates,\n    })\n  );\n\n  return (\n    <DndContext sensors={sensors}>\n      <SortableContext items={items}>{/* ... */}</SortableContext>\n    </DndContext>\n  );\n}\n```\n\nIf you'd like to use the [Mouse](../../api-documentation/sensors/mouse) and [Touch](../../api-documentation/sensors/touch) sensors instead of the [Pointer](../../api-documentation/sensors/pointer) sensor, simply initialize those sensors instead:\n\n```jsx\nimport {\n  DndContext,\n  KeyboardSensor,\n  MouseSensor,\n  TouchSensor,\n  useSensor,\n  useSensors,\n} from '@dnd-kit/core';\nimport {SortableContext, sortableKeyboardCoordinates} from '@dnd-kit/sortable';\n\nfunction App() {\n  const [items] = useState(['1', '2', '3']);\n  const sensors = useSensors(\n    useSensor(MouseSensor, {\n      // Require the mouse to move by 10 pixels before activating\n      activationConstraint: {\n        distance: 10,\n      },\n    }),\n    useSensor(TouchSensor, {\n      // Press delay of 250ms, with tolerance of 5px of movement\n      activationConstraint: {\n        delay: 250,\n        tolerance: 5,\n      },\n    }),\n    useSensor(KeyboardSensor, {\n      coordinateGetter: sortableKeyboardCoordinates,\n    })\n  );\n\n  return (\n    <DndContext sensors={sensors}>\n      <SortableContext items={items}>{/* ... */}</SortableContext>\n    </DndContext>\n  );\n}\n```\n\nTo learn more about sensors, read the in-depth documentation on sensors:\n\n<Card href=\"../../api-documentation/sensors\" icon=\"signal-stream\" horizontal>\nSensors\n</Card>\n\n### Sorting strategies\n\nThe supported use cases of the Sortable preset include vertical lists, horizontal lists, grids, and virtualized lists. Because of the wide variety of use cases supported, it would be difficult to write a single strategy to cover all of these different use cases. Instead, the sortable preset exposes a number of different strategies you can use, that are tailored to these various use cases:\n\n- `rectSortingStrategy`: This is the default value, and is suitable for most use cases. This strategy does not support virtualized lists.\n- `verticalListSortingStrategy`: This strategy is optimized for vertical lists, and supports virtualized lists.\n- `horizontalListSortingStrategy`: This strategy is optimized for horizontal lists, and supports virtualized lists.\n- `rectSwappingStrategy`: Use this strategy to achieve swappable functionality.\n\nMake sure to use the sorting strategy that is the most adapted to the use case you are building for.\n\n### Collision detection algorithm\n\nThe default collision detection algorithm of `DndContext` is the [rectangle intersection](../../api-documentation/context-provider/collision-detection-algorithms.md#rectangle-intersection) algorithm. While the rectangle intersection strategy is well suited for many use cases, it can be unforgiving, since it requires both the draggable and droppable bounding rectangles to come into direct contact and intersect.\n\nFor sortable lists, we recommend using a more forgiving collision detection strategy such as the [closest center](../../api-documentation/context-provider/collision-detection-algorithms.md#closest-center) or [closest corners](../../api-documentation/context-provider/collision-detection-algorithms.md#closest-corners) algorithms.\n\nIn this example, we'll be using the closest center algorithm:\n\n```jsx\nimport {DndContext, closestCenter} from '@dnd-kit/core';\nimport {SortableContext} from '@dnd-kit/sortable';\n\nfunction App() {\n  const [items] = useState(['1', '2', '3']);\n\n  return (\n    <DndContext collisionDetection={closestCenter}>\n      <SortableContext items={items}>{/* ... */}</SortableContext>\n    </DndContext>\n  );\n}\n```\n\nTo learn more about collision detection algorithms and when to use one over the other, read our guide on collision detection algorithms:\n\n<Card href=\"../../api-documentation/context-provider/collision-detection-algorithms\" icon=\"diagram-venn\" horizontal>\nCollision Detection Algorithms\n</Card>\n\n## Connecting all the pieces\n\nFirst, let's go ahead and render all of our sortable items:\n\n<CodeGroup>\n```jsx App.jsx\nimport React, {useState} from 'react';\nimport {DndContext} from '@dnd-kit/core';\nimport {SortableContext} from '@dnd-kit/sortable';\n\nimport {SortableItem} from './SortableItem';\n\nfunction App() {\nconst [items] = useState(['1', '2', '3']);\n\nreturn (\n<DndContext>\n<SortableContext items={items}>\n{items.map((id) => (\n<SortableItem key={id} id={id} />\n))}\n</SortableContext>\n</DndContext>\n);\n}\n\n```\n\n```jsx SortableItem.jsx\nimport React from 'react';\nimport {useSortable} from '@dnd-kit/sortable';\nimport {CSS} from '@dnd-kit/utilities';\n\nfunction SortableItem(props) {\n  const {attributes, listeners, setNodeRef, transform, transition} =\n    useSortable({id: props.id});\n\n  const style = {\n    transform: CSS.Transform.toString(transform),\n    transition,\n  };\n\n  return (\n    <div ref={setNodeRef} style={style} {...attributes} {...listeners}>\n      {/* ... */}\n    </div>\n  );\n}\n```\n\n</CodeGroup>\n\nNext, let's wire up the custom sensors for `DndContext` and add a custom collision detection strategy:\n\n<CodeGroup>\n\n```jsx App.jsx\nimport React, {useState} from 'react';\nimport {\n  DndContext,\n  closestCenter,\n  KeyboardSensor,\n  PointerSensor,\n  useSensor,\n  useSensors,\n} from '@dnd-kit/core';\nimport {SortableContext, sortableKeyboardCoordinates} from '@dnd-kit/sortable';\n\nimport {SortableItem} from './SortableItem';\n\nfunction App() {\n  const [items] = useState(['1', '2', '3']);\n  const sensors = useSensors(\n    useSensor(PointerSensor),\n    useSensor(KeyboardSensor, {\n      coordinateGetter: sortableKeyboardCoordinates,\n    })\n  );\n\n  return (\n    <DndContext sensors={sensors} collisionDetection={closestCenter}>\n      <SortableContext items={items}>\n        {items.map((id) => (\n          <SortableItem key={id} id={id} />\n        ))}\n      </SortableContext>\n    </DndContext>\n  );\n}\n```\n\n```jsx SortableItem.jsx\nimport {useSortable} from '@dnd-kit/sortable';\nimport {CSS} from '@dnd-kit/utilities';\n\nexport function SortableItem(props) {\n  const {attributes, listeners, setNodeRef, transform, transition} =\n    useSortable({id: props.id});\n\n  const style = {\n    transform: CSS.Transform.toString(transform),\n    transition,\n  };\n\n  return (\n    <div ref={setNodeRef} style={style} {...attributes} {...listeners}>\n      {/* ... */}\n    </div>\n  );\n}\n```\n\n</CodeGroup>\n\nIn this example, we'll be building a vertical sortable list, so we will be using the `verticalListSortingStrategy` sorting strategy:\n\n```jsx\nimport React, {useState} from 'react';\nimport {\n  DndContext,\n  closestCenter,\n  KeyboardSensor,\n  PointerSensor,\n  useSensor,\n  useSensors,\n} from '@dnd-kit/core';\nimport {\n  SortableContext,\n  sortableKeyboardCoordinates,\n  verticalListSortingStrategy,\n} from '@dnd-kit/sortable';\n\nimport {SortableItem} from './SortableItem';\n\nfunction App() {\n  const [items] = useState(['1', '2', '3']);\n  const sensors = useSensors(\n    useSensor(PointerSensor),\n    useSensor(KeyboardSensor, {\n      coordinateGetter: sortableKeyboardCoordinates,\n    })\n  );\n\n  return (\n    <DndContext sensors={sensors} collisionDetection={closestCenter}>\n      <SortableContext items={items} strategy={verticalListSortingStrategy}>\n        {items.map((id) => (\n          <SortableItem key={id} id={id} />\n        ))}\n      </SortableContext>\n    </DndContext>\n  );\n}\n```\n\nFinally, we'll need to set up event handlers on the `DndContext` provider in order to update the order of the items on drag end.\n\n```jsx\nimport React, {useState} from 'react';\nimport {\n  DndContext,\n  closestCenter,\n  KeyboardSensor,\n  PointerSensor,\n  useSensor,\n  useSensors,\n} from '@dnd-kit/core';\nimport {\n  arrayMove,\n  SortableContext,\n  sortableKeyboardCoordinates,\n  verticalListSortingStrategy,\n} from '@dnd-kit/sortable';\n\nimport {SortableItem} from './SortableItem';\n\nfunction App() {\n  const [items, setItems] = useState(['1', '2', '3']);\n  const sensors = useSensors(\n    useSensor(PointerSensor),\n    useSensor(KeyboardSensor, {\n      coordinateGetter: sortableKeyboardCoordinates,\n    })\n  );\n\n  return (\n    <DndContext\n      sensors={sensors}\n      collisionDetection={closestCenter}\n      onDragEnd={handleDragEnd}\n    >\n      <SortableContext items={items} strategy={verticalListSortingStrategy}>\n        {items.map((id) => (\n          <SortableItem key={id} id={id} />\n        ))}\n      </SortableContext>\n    </DndContext>\n  );\n\n  function handleDragEnd(event) {\n    const {active, over} = event;\n\n    if (active.id !== over.id) {\n      setItems((items) => {\n        const oldIndex = items.indexOf(active.id);\n        const newIndex = items.indexOf(over.id);\n\n        return arrayMove(items, oldIndex, newIndex);\n      });\n    }\n  }\n}\n```\n\n### Drag Overlay\n\nFor most sortable lists, we recommend you use a [`DragOverlay`](../../api-documentation/draggable/drag-overlay) if your sortable list is scrollable or if the contents of the scrollable list are taller than the viewport of the window.\n\nThe `<DragOverlay>` component provides a way to render a draggable overlay that is removed from the normal document flow and is positioned relative to the viewport. The drag overlay also implements drop animations.\n\nA **common pitfall** when using the `DragOverlay` component is rendering the same component that calls `useSortable` inside the `DragOverlay`. This will lead to unexpected results, since there will be an `id` collision between the two components both calling `useDraggable` with the same `id`, since `useSortable` is an abstraction on top of `useDraggable`.\n\nInstead, create a presentational version of your component that you intend on rendering in the drag overlay, and another version that is sortable and renders the presentational component. There are two recommended patterns for this, either using [wrapper nodes](../../api-documentation/draggable/drag-overlay.md#wrapper-nodes) or[ ref forwarding](../../api-documentation/draggable/drag-overlay.md#ref-forwarding).\n\nIn this example, we'll use the [ref forwarding](../../api-documentation/draggable/drag-overlay.md#ref-forwarding) pattern to avoid introducing wrapper nodes:\n\n<CodeGroup>\n\n```jsx App.jsx\nimport React, {useState} from 'react';\nimport {\n  closestCenter,\n  DndContext,\n  DragOverlay,\n  KeyboardSensor,\n  PointerSensor,\n  useSensor,\n  useSensors,\n} from '@dnd-kit/core';\nimport {\n  arrayMove,\n  SortableContext,\n  sortableKeyboardCoordinates,\n  verticalListSortingStrategy,\n} from '@dnd-kit/sortable';\n\nimport {SortableItem} from './SortableItem';\nimport {Item} from './Item';\n\nfunction App() {\n  const [activeId, setActiveId] = useState(null);\n  const [items, setItems] = useState(['1', '2', '3']);\n  const sensors = useSensors(\n    useSensor(PointerSensor),\n    useSensor(KeyboardSensor, {\n      coordinateGetter: sortableKeyboardCoordinates,\n    })\n  );\n\n  return (\n    <DndContext\n      sensors={sensors}\n      collisionDetection={closestCenter}\n      onDragStart={handleDragStart}\n      onDragEnd={handleDragEnd}\n    >\n      <SortableContext items={items} strategy={verticalListSortingStrategy}>\n        {items.map((id) => (\n          <SortableItem key={id} id={id} />\n        ))}\n      </SortableContext>\n      <DragOverlay>{activeId ? <Item id={activeId} /> : null}</DragOverlay>\n    </DndContext>\n  );\n\n  function handleDragStart(event) {\n    const {active} = event;\n\n    setActiveId(active.id);\n  }\n\n  function handleDragEnd(event) {\n    const {active, over} = event;\n\n    if (active.id !== over.id) {\n      setItems((items) => {\n        const oldIndex = items.indexOf(active.id);\n        const newIndex = items.indexOf(over.id);\n\n        return arrayMove(items, oldIndex, newIndex);\n      });\n    }\n\n    setActiveId(null);\n  }\n}\n```\n\n```jsx SortableItem.jsx\nimport React from 'react';\nimport {useSortable} from '@dnd-kit/sortable';\nimport {CSS} from '@dnd-kit/utilities';\n\nimport Item from './Item';\n\nexport function SortableItem(props) {\n  const {attributes, listeners, setNodeRef, transform, transition} =\n    useSortable({id: props.id});\n\n  const style = {\n    transform: CSS.Transform.toString(transform),\n    transition,\n  };\n\n  return (\n    <Item ref={setNodeRef} style={style} {...attributes} {...listeners}>\n      {value}\n    </Item>\n  );\n}\n```\n\n```jsx Item.jsx\nimport React, {forwardRef} from 'react';\n\nexport const Item = forwardRef(({id, ...props}, ref) => {\n  return (\n    <div {...props} ref={ref}>\n      {id}\n    </div>\n  );\n});\n```\n\n</CodeGroup>\n"
  },
  {
    "path": "apps/docs/legacy/presets/sortable/sortable-context.mdx",
    "content": "---\ntitle: Sortable Context\nsidebarTitle: <SortableContext>\n---\n\nThe `SortableContext` provides information via context that is consumed by the [`useSortable`](./use-sortable) hook.\n\n## Props\n\n### Items\n\nIt requires that you pass it a sorted array of the unique identifiers associated with the elements that use the `useSortable` hook within it.\n\n```jsx\nimport React, {useState} from 'react';\nimport {DndContext} from '@dnd-kit/core';\nimport {SortableContext} from '@dnd-kit/sortable';\n\nfunction App() {\n  const [items] = useState([1, 2, 3]);\n\n  return (\n    <DndContext>\n      <SortableContext items={items}>{/* ... */}</SortableContext>\n    </DndContext>\n  );\n}\n```\n\n<Info>\nIt's important that the `items` prop passed to `SortableContext` be sorted in the same order in which the items are rendered, otherwise you may see unexpected results.\n</Info>\n\n### Strategy\n\nThe `SortableContext` component also accepts different [sorting strategies](./#sorting-strategies) to compute transforms for the `useSortable` hook. The built in strategies include:\n\n- `rectSortingStrategy`: This is the default value, and is suitable for most use cases. This strategy does not support virtualized lists.\n- `verticalListSortingStrategy`: This strategy is optimized for vertical lists, and supports virtualized lists.\n- `horizontalListSortingStrategy`: This strategy is optimized for horizontal lists, and supports virtualized lists.\n- `rectSwappingStrategy`: Use this strategy to achieve swappable functionality.\n\nMake sure to use the sorting strategy that is the most adapted to the use case you are building for.\n\nFor advanced use cases, you may also build custom sorting strategies. To do so, make sure that the custom strategy you are building accepts the arguments that are passed to a sorting strategy and adheres to the return values that are expected. For more details on this, refer to the implementation of the built-in sorting strategies.\n\n### Identifier\n\nThe `SortableContext` component also optionally accepts an `id` prop. If an `id` is not provided, one will be auto-generated for you. The `id` prop is for advanced use cases. If you're building custom sensors, you'll have access to each sortable element's `data` prop, which will contain the `containerId` associated to that sortable context.\n\n## Usage\n\n<Info>\nIn order for the `SortableContext` component to function properly, make sure it is a descendant of a `DndContext` provider.\n</Info>\n\nYou may nest multiple `SortableContext` providers within the same parent `DndContext` provider.\n\nYou may also nest `SortableContext` providers within other `SortableContext` providers, either all under the same `DndContext` provider or each with their own individual `DndContext` providers if you would like to configure them with different options:\n\n```jsx\n// Bad, missing parent <DndContext>\n<SortableContext>\n  {/* ... */}\n</SortableContext>\n\n// Good, basic setup\n<DndContext>\n  <SortableContext>\n    {/* ... */}\n  </SortableContext>\n</DndContext>\n\n// Good, multiple sibling Sortable contexts\n<DndContext>\n  <SortableContext>\n    {/* ... */}\n  </SortableContext>\n  <SortableContext>\n    {/* ... */}\n  </SortableContext>\n</DndContext>\n\n// Good, nested DndContexts\n<DndContext>\n  <SortableContext items={[\"A, \"B\", \"C\"]}>\n    <DndContext>\n      <SortableContext items={[\"A, \"B\", \"C\"]}>\n        {/* ... */}\n      </SortableContext>\n    </DndContext>\n  </SortableContext>\n</DndContext>\n\n// Bad, nested Sortable contexts with `id` collisions\n<DndContext>\n  <SortableContext items={[\"A, \"B\", \"C\"]}>\n    <SortableContext items={[\"A, \"B\", \"C\"]}>\n      {/* ... */}\n    </SortableContext>\n  </SortableContext>\n</DndContext>\n\n// Good, nested Sortable contexts with unique `id`s\n<DndContext>\n  <SortableContext items={[\"A, \"B\", \"C\"]}>\n    <SortableContext items={[1, 2, 3]}>\n      {/* ... */}\n    </SortableContext>\n  </SortableContext>\n</DndContext>\n\n```\n"
  },
  {
    "path": "apps/docs/legacy/presets/sortable/use-sortable.mdx",
    "content": "---\ntitle: useSortable\n---\n\nThe `useSortable` hook is an abstraction that composes the [`useDroppable`](../../api-documentation/droppable) and [`useDraggable`](../../api-documentation/draggable) hooks.\n\n<Info>\nTo function properly, the `useSortable` hook needs to be used within a descendant of a [`SortableContext`](./sortable-context) provider higher up in the tree.\n</Info>\n\n## Usage\n\nIf you're already familiar with the [`useDraggable`](../../api-documentation/draggable) hook, the `useSortable` hook should look very familiar, since, it is an abstraction on top of it.\n\nIn addition to the `attributes`, `listeners`,`transform` and `setNodeRef` arguments, which you should already be familiar with if you've used the `useDraggable` hook before, you'll notice that the `useSortable` hook also provides a [`transition`](#transform) argument.\n\n```jsx\nimport React from 'react';\nimport {useSortable} from '@dnd-kit/sortable';\nimport {CSS} from '@dnd-kit/utilities';\n\nfunction SortableItem(props) {\n  const {attributes, listeners, setNodeRef, transform, transition} =\n    useSortable({id: props.id});\n\n  const style = {\n    transform: CSS.Transform.toString(transform),\n    transition,\n  };\n\n  return (\n    <li ref={setNodeRef} style={style} {...attributes} {...listeners}>\n      {/* ... */}\n    </li>\n  );\n}\n```\n\n## Properties\n\n### Listeners\n\nThe `listeners` property contains the [activator event handlers](../../api-documentation/sensors/#activators) for each [Sensor](../../api-documentation/sensors/) that is defined on the parent [`DndContext`](../../api-documentation/context-provider/#props) provider.\n\nIt should be attached to the node(s) that you wish to use as the activator to begin a sort event. In most cases, that will be the same node as the one passed to `setNodeRef`, though not necessarily. For instance, when implementing a sortable element with a \"drag handle\", the ref should be attached to the parent node that should be sortable, but the listeners can be attached to the handle node instead.\n\nFor additional details on the [`listeners`](../../api-documentation/draggable/#listeners) property, refer to the [`useDraggable`](../../api-documentation/draggable) documentation.\n\n### Attributes\n\nThe `useSortable` hook provides a set of sensible default attributes for draggable items. We recommend you attach these to your draggable elements, though nothing will break if you don't.\n\nFor additional details on the [`attributes`](../../api-documentation/draggable/#attributes) property, refer to the [`useDraggable`](../../api-documentation/draggable) documentation.\n\n### Transform\n\nThe `transform` property represents the displacement and change of scale transformation that a sortable item needs to apply to transition to its new position without needing to update the DOM order.\n\nThe `transform` property for the `useSortable` hook behaves similarly to the [`transform`](../../api-documentation/draggable/#transforms) property of the [`useDraggable`](../../api-documentation/draggable) hook for the active sortable item, when there is no [`DragOverlay`](../../api-documentation/draggable/drag-overlay) being used.\n\n### Node ref\n\nIn order for the `useSortable` hook to function properly, it needs the `setNodeRef` property to be attached to the HTML element you intend on turning into a sortable element:\n\n```jsx\nfunction SortableItem(props) {\n  const {setNodeRef} = useDraggable({\n    id: props.id,\n  });\n\n  return <li ref={setNodeRef}>{/* ... */}</li>;\n}\n```\n\nKeep in mind that the `ref` should be assigned to the outer container that you want to become draggable, but this doesn't necessarily need to coincide with the container that the listeners are attached to:\n\n```jsx\nfunction SortableItem(props) {\n  const {arguments, listeners, setNodeRef} = useDraggable({\n    id: props.id,\n  });\n\n  return (\n    <li ref={setNodeRef}>\n      {/* ... */}\n      <button {...listeners} {...arguments}>\n        Drag handle\n      </button>\n    </li>\n  );\n}\n```\n\nSince the `useSortable` hook is simply an abstraction on top of the [`useDraggable`](../../api-documentation/draggable/use-draggable) and [`useDroppable`](../../api-documentation/droppable/use-droppable) hooks, in some advanced use cases, you may also use the `setDroppableNodeRef` and `setDraggableNodeRef` properties to connect them to different nodes. For example, if you want the draggable element to have a different dimension than the droppable element that will be sortable:\n\n```jsx\nfunction SortableItem(props) {\n  const {setDraggableNodeRef, setDroppableNodeRef} = useDraggable({\n    id: props.id,\n  });\n\n  return (\n    <li ref={setDroppableNodeRef}>\n      {/* ... */}\n      <button ref={setDraggableNodeRef}>Drag me</button>\n    </li>\n  );\n}\n```\n\n### Activator\n\n**`setActivatorNodeRef`**\n\nIt's possible for the listeners to be attached to a different node than the one that `setNodeRef` is attached to.\n\nA common example of this is when implementing a drag handle and attaching the listeners to the drag handle:\n\n```jsx\nfunction SortableItem(props) {\n  const {listeners, setNodeRef} = useSortable({\n    id: props.id,\n  });\n\n  return (\n    <li ref={setNodeRef}>\n      {/* ... */}\n      <button {...listeners}>Drag handle</button>\n    </li>\n  );\n}\n```\n\nWhen the activator node differs from the draggable node, we recommend setting the activator node ref on the activator node:\n\n```jsx\nfunction SortableItem(props) {\n  const {listeners, setNodeRef, setActivatorNodeRef} = useSortable({\n    id: props.id,\n  });\n\n  return (\n    <li ref={setNodeRef}>\n      {/* ... */}\n      <button ref={setActivatorNodeRef} {...listeners}>\n        Drag handle\n      </button>\n    </li>\n  );\n}\n```\n\nThis helps @dnd-kit more accurately handle automatic focus management and can also be accessed by sensors for enhanced activation constraints.\n\n<Info>\nFocus management is automatically handled by [@dnd-kit](https://github.com/dnd-kit). When the activator event is a Keyboard event, focus will automatically be restored back to the first focusable node of the activator node.\n\nIf no activator node is set via `setActivatorNodeRef`, focus will automatically be restored on the first focusable node of the draggable node registered via `setNodeRef.`\n</Info>\n\n### Transition\n\nRefer to the [`transition` argument](#transition) documentation below.\n\n## Arguments\n\n### Identifier\n\nThe `id` argument is a `string` or `number` that should be unique.\n\nSince the `useSortable` is an abstraction on top of the `useDroppable` and `useDraggable` hooks, which both require a unique identifier, the `useSortable` hook also requires a unique identifier.\n\nThe argument passed to the `id` argument of `useSortable` should match the `id` passed in the `items` array of the parent [`SortableContext`](./sortable-context) provider.\n\n### Disabled\n\nIf you'd like to temporarily disable a sortable item from being interactive, set the `disabled` argument to `true`.\n\n### Transition\n\nThe transition argument controls the value of the `transition` property for you. It conveniently disables transform transitions while not dragging, but ensures that items transition back to their final positions when the drag operation is ended or cancelled.\n\nIt also disables transitions for the active sortable element that is being dragged, unless there is a [`DragOverlay`](../../api-documentation/draggable/drag-overlay) being used.\n\nThe default transition is `250` milliseconds, with an easing function set to `ease`, but you can customize this and pass any valid [CSS transition timing function](https://developer.mozilla.org/en-US/docs/Web/CSS/transition-timing-function).\n\n```javascript\nconst {transition} = useSortable({\n  transition: {\n    duration: 150, // milliseconds\n    easing: 'cubic-bezier(0.25, 1, 0.5, 1)',\n  },\n});\n```\n\nMake sure you pass the `transition` style property to the same node that has the `transform` property applied:\n\n```jsx\nimport React from 'react';\nimport {useSortable} from '@dnd-kit/sortable';\nimport {CSS} from '@dnd-kit/utilities';\n\nfunction SortableItem(props) {\n  const {transform, transition} = useSortable({id: props.id});\n\n  const style = {\n    transform: CSS.Transform.toString(transform),\n    transition,\n  };\n\n  return <li style={style}>{/* ... */}</li>;\n}\n```\n\nIf you prefer, you may also use CSS variables to manage the `transform` and `transition` properties:\n\n```jsx\nimport React from 'react';\nimport {useSortable} from '@dnd-kit/sortable';\nimport {CSS} from '@dnd-kit/utilities';\n\nfunction SortableItem(props) {\n  const {transform, transition} = useSortable({id: props.id});\n\n  const style = {\n    '--translate-x': transform ? transform.x : 0,\n    '--translate-y': transform ? transform.y : 0,\n    '--transition': transition,\n  };\n\n  return <li style={style}>{/* ... */}</li>;\n}\n```\n\nTo disable transitions entirely, set the `transition` argument to `null`:\n\n```javascript\nconst {transition} = useSortable({\n  transition: null,\n});\n```\n\nIf you prefer to manage transitions yourself, you may also choose to do so, but this isn't something we recommend.\n\n### Sorting strategy\n\nOptionally, you can pass a local sorting strategy that differs from the [global sorting strategy](./sortable-context#strategy) passed to the parent `SortableContext` provider.\n"
  },
  {
    "path": "apps/docs/overview.mdx",
    "content": "---\ntitle: Overview\ndescription: 'Learn how to build drag and drop interfaces with <span class=\"inline-logo\">**dnd kit**</span>'\nseo:\n  title: 'dnd kit – The toolkit for building drag and drop interfaces'\n  description: 'A lightweight, performant, accessible and extensible drag and drop toolkit for React, Vue, Svelte, SolidJS, and vanilla JavaScript.'\n---\n\n<img\n  className=\"block hero-image\"\n  src=\"/images/hero.svg\"\n  alt=\"A modular toolkit for building drag and drop interfaces\"\n  noZoom\n/>\n\n## Key features\n- **Framework agnostic**: First-class support for React, Vue, Svelte, Solid, and Vanilla\n- **Batteries included**: Drag, drop, sort, and reorder in any layout or direction\n- **Fully extensible**: Plugins, sensors, and modifiers for complete control\n- **Production ready**: Built for performance, accessibility, and reliability\n\n## Getting started\n\nChoose your preferred framework to get started:\n\n<CardGroup cols={2}>\n  <Card\n    title=\"Vanilla\"\n    icon=\"js\"\n    href=\"/quickstart\"\n  >\n    Build drag and drop interfaces using plain JavaScript\n  </Card>\n  <Card\n    title=\"React\"\n    icon=\"react\"\n    href=\"react/quickstart\"\n  >\n    Build drag and drop interfaces using React components and hooks\n  </Card>\n  <Card\n    title=\"Vue\"\n    icon=\"vuejs\"\n    href=\"vue/quickstart\"\n  >\n    Build drag and drop interfaces using Vue composables and components\n  </Card>\n  <Card\n    title=\"Svelte\"\n    icon=\"svelte\"\n    href=\"svelte/quickstart\"\n  >\n    Build drag and drop interfaces using Svelte primitives and components\n  </Card>\n  <Card\n    title=\"Solid\"\n    icon=\"solidjs\"\n    href=\"solid/quickstart\"\n  >\n    Build drag and drop interfaces using SolidJS hooks and components\n  </Card>\n</CardGroup>\n\n## Core Concepts\n\nLearn the essential building blocks:\n\n<CardGroup cols={2}>\n  <Card\n    title=\"Manager\"\n    icon=\"sitemap\"\n    href=\"concepts/drag-drop-manager\"\n  >\n    The central orchestrator that coordinates drag and drop operations\n  </Card>\n  <Card\n    title=\"Draggable\"\n    icon=\"bullseye-pointer\"\n    href=\"concepts/draggable\"\n  >\n    Elements that can be picked up and dragged to new locations\n  </Card>\n  <Card\n    title=\"Droppable\"\n    icon=\"expand\"\n    href=\"concepts/droppable\"\n  >\n    Target areas where draggable elements can be dropped\n  </Card>\n  <Card\n    title=\"Sortable\"\n    icon=\"layer-group\"\n    href=\"concepts/sortable\"\n  >\n    Draggable elements that can be reordered within and across lists\n  </Card>\n</CardGroup>\n\n## Extend and customize\n\nMake it your own with powerful extension points:\n\n<CardGroup cols={2}>\n  <Card\n    title=\"Plugins\"\n    icon=\"cube\"\n    href=\"extend/plugins\"\n  >\n    Add new features and behaviors with the plugin system\n  </Card>\n  <Card\n    title=\"Sensors\"\n    icon=\"signal-stream\"\n    href=\"extend/sensors\"\n  >\n    Support different input methods like mouse, touch, and keyboard\n  </Card>\n  <Card\n    title=\"Modifiers\"\n    icon=\"arrows-from-line\"\n    href=\"extend/modifiers\"\n  >\n    Modify drag behavior with constraints and transformations\n  </Card>\n</CardGroup>\n\n\n\n## Sponsors\n\n<div className=\"sponsors\">\n  <Frame>\n    <a href=\"https://sentry.io/\" target=\"_blank\">\n      <img className=\"dark:hidden\" src=\"/images/sponsors/sentry-logo.svg\" style={{width: 180, height: 80, pointerEvents: \"none\"}} />\n      <img className=\"hidden dark:block\" src=\"/images/sponsors/sentry-logo-dark.svg\" style={{width: 180, height: 80, pointerEvents: \"none\"}} />\n    </a>\n  </Frame>\n  <Frame>\n    <a href=\"https://www.any.do/\" target=\"_blank\">\n      <img className=\"dark:hidden\" src=\"/images/sponsors/any-do-logo.svg\" style={{width: 120, height: 80, pointerEvents: \"none\"}} />\n      <img className=\"hidden dark:block\" src=\"/images/sponsors/any-do-logo-dark.svg\" style={{width: 120, height: 80, pointerEvents: \"none\"}} />\n    </a>\n  </Frame>\n  <Frame>\n    <a href=\"https://doist.com/\" target=\"_blank\">\n      <img className=\"dark:hidden\" src=\"/images/sponsors/doist-logo.svg\" style={{width: 90, height: 80, pointerEvents: \"none\"}} />\n      <img className=\"hidden dark:block\" src=\"/images/sponsors/doist-logo-dark.svg\" style={{width: 90, height: 80, pointerEvents: \"none\"}} />\n    </a>\n  </Frame>\n  <Frame>\n    <a href=\"https://puckeditor.com/\" target=\"_blank\" style={{position: \"relative\", top: 4}}>\n      <img className=\"dark:hidden\" src=\"/images/sponsors/puck-logo.svg\" style={{width: 130, height: 80, pointerEvents: \"none\"}} />\n      <img className=\"hidden dark:block\" src=\"/images/sponsors/puck-logo-dark.svg\" style={{width: 130, height: 80, pointerEvents: \"none\"}} />\n    </a>\n  </Frame>\n  <Frame>\n    <a href=\"https://httpie.io/\" target=\"_blank\">\n      <img className=\"dark:hidden\" src=\"/images/sponsors/httpie-logo.svg\" style={{width: 120, height: 80, pointerEvents: \"none\"}} />\n      <img className=\"hidden dark:block\" src=\"/images/sponsors/httpie-logo-dark.svg\" style={{width: 120, height: 80, pointerEvents: \"none\"}} />\n    </a>\n  </Frame>\n  <Frame>\n    <a href=\"https://mintlify.com/\" target=\"_blank\">\n      <img className=\"dark:hidden\" src=\"/images/sponsors/mintlify-logo.svg\" style={{width: 140, height: 80, pointerEvents: \"none\"}} />\n      <img className=\"hidden dark:block\" src=\"/images/sponsors/mintlify-logo-dark.svg\" style={{width: 140, height: 80, pointerEvents: \"none\"}} />\n    </a>\n  </Frame>\n</div>\n"
  },
  {
    "path": "apps/docs/quickstart.mdx",
    "content": "---\ntitle: 'Quickstart'\ndescription: 'Start building drag and drop interfaces with plain JavaScript in minutes.'\nicon: 'rocket'\n---\n\nimport Intro from '/snippets/quickstart/intro.mdx';\nimport {Story} from '/snippets/story.mdx';\n\nimport {CodeSandbox} from '/snippets/sandbox.mdx';\nimport {draggableStyles, droppableStyles} from '/snippets/code.mdx';\n\n<Intro />\n\n## Installation\n\nInstall `@dnd-kit/dom` in your project:\n\n<CodeGroup>\n  ```bash npm\n  npm install @dnd-kit/dom\n  ```\n\n  ```bash yarn\n  yarn add @dnd-kit/dom\n  ```\n\n  ```bash pnpm\n  pnpm add @dnd-kit/dom\n  ```\n\n  ```bash bun\n  bun add @dnd-kit/dom\n  ```\n</CodeGroup>\n\n## Creating draggable elements\n\nLet's get started by creating draggable elements that can be dropped over droppable targets.\n\nIn this example, we'll be using the [Draggable](/concepts/draggable) class to create a draggable element. We'll also need to create a [DragDropManager](/concepts/drag-drop-manager) instance to manage the drag and drop interactions.\n\nexport const draggableCode = `\nfunction createDraggable(manager) {\n  // Create a DOM element (or use an existing one)\n  const element = document.createElement('button');\n  element.innerText = 'draggable';\n  element.classList.add('btn');\n\n  // Make the element draggable\n  return new Draggable({id: 'draggable-button', element}, manager);\n}\n`.trim();\n\nexport const draggableExample = `\nimport {Draggable, DragDropManager} from '@dnd-kit/dom';\n\n${draggableCode}\n\nexport default function App() {\n  // Create a manager to coordinate drag and drop\n  const manager = new DragDropManager();\n\n  // Create a draggable element\n  const draggable = createDraggable(manager);\n\n  // Add the draggable element to the DOM\n  document.body.append(draggable.element);\n}\n`.trim();\n\n<CodeSandbox files={{\n  'index.js': {code: `import './styles.css';\\nimport App from './app.js';\\n\\nApp();`, hidden: true},\n  'app.js': {code: draggableExample, active: true},\n  'styles.css': {code: draggableStyles, hidden: true},\n}} height={475} previewHeight={200} template=\"vanilla\" />\n\n<ParamField path=\"options\" type=\"object\" required>\n  Configuration for the draggable element:\n  - `id` (required): Unique identifier\n  - `element`: The DOM element to make draggable\n  - `handle`: Optional drag handle element\n  - `disabled`: Whether dragging is disabled\n</ParamField>\n\n## Creating droppable targets\n\nIn order for our draggable elements to have targets where they can be dropped, we need to create droppable elements. To do so, we'll be using the Droppable class.\n\nLike the [Draggable](/concepts/draggable) class, the [Droppable](/concepts/droppable) class requires an element and an id as arguments.\n\nexport const droppableCode = `\nimport {Droppable, DragDropManager} from '@dnd-kit/dom';\n\nexport function createDroppable(manager) {\n  const element = document.createElement('div');\n  element.classList.add('droppable');\n\n  const droppable = new Droppable({\n    element,\n    id: 'droppable-container', // Required - must be unique\n    effects(){\n      return [\n        () => droppable.isDropTarget\n          ? element.classList.add('active')\n          : element.classList.remove('active')\n      ];\n    }\n  }, manager);\n\n  return droppable;\n}\n`.trim();\n\nexport const appCode = `\nimport {DragDropManager} from '@dnd-kit/dom';\n\nimport {createDraggable} from './Draggable.js';\nimport {createDroppable} from './Droppable.js';\n\nexport default function App() {\n  const manager = new DragDropManager();\n  const app = document.getElementById('app');\n\n  const draggable = createDraggable(manager);\n  const droppable = createDroppable(manager);\n\n  app.append(draggable.element, droppable.element);\n}\n`.trim();\n\n<CodeSandbox files={{\n  'index.js': {code: `import './styles.css';\\nimport App from './App.js';\\n\\nApp();`, hidden: true},\n  'App.js': {code: appCode},\n  'Droppable.js': {code: droppableCode, active: true},\n  'Draggable.js': {code: `import {Draggable} from '@dnd-kit/dom';\\n\\nexport ${draggableCode}`},\n  'styles.css': {code: `${draggableStyles}\\n${droppableStyles}`, hidden: true},\n}} height={480} previewHeight={420} template=\"vanilla\" showTabs />\n\n\n<ParamField path=\"options\" type=\"object\" required>\n  Configuration for the droppable target:\n  - `id` (required): Unique identifier\n  - `element`: The DOM element to make droppable\n  - `accepts`: Types of draggable elements to accept\n  - `disabled`: Whether dropping is disabled\n</ParamField>\n\nIn order to move the draggable element into the droppable target, we need to monitor the drag and drop events and update the DOM accordingly.\n\nexport const finalAppCode = `\nimport {DragDropManager} from '@dnd-kit/dom';\n\nimport {createDraggable} from './Draggable.js';\nimport {createDroppable} from './Droppable.js';\n\nexport default function App() {\n  const manager = new DragDropManager();\n  const app = document.getElementById('app');\n\n  const draggable = createDraggable(manager);\n  const droppable = createDroppable(manager);\n\n  manager.monitor.addEventListener('dragend', (event) => {\n    const {operation, canceled} = event;\n    const {source, target} = operation;\n\n    // Skip if drag operation was canceled (e.g. if escape key was pressed)\n    if (canceled) return;\n\n    // Move element to drop target if dropped on droppable\n    if (target && target.id === droppable.id) {\n      droppable.element.append(source.element);\n    } else {\n      app.prepend(source.element);\n    }\n  });\n\n  app.append(draggable.element, droppable.element);\n}\n`.trim();\n\n<CodeSandbox files={{\n  'index.js': {code: `import './styles.css';\\nimport App from './App.js';\\n\\nApp();`, hidden: true},\n  'App.js': {code: finalAppCode, active: true},\n  'Droppable.js': {code: droppableCode},\n  'Draggable.js': {code: `import {Draggable} from '@dnd-kit/dom';\\n\\nexport ${draggableCode}`},\n  'styles.css': {code: `${draggableStyles}\\n${droppableStyles}`, hidden: true},\n}} height={660} previewHeight={420} template=\"vanilla\" showTabs />\n\n## Next steps\n\nNow that you have a basic understanding of how to make elements draggable and droppable, you can explore the concepts covered in this quickstart guide in more detail:\n\n<CardGroup>\n  <Card title=\"Manager\" icon=\"sitemap\" href=\"/concepts/drag-drop-manager\">\n    Create drag and drop contexts for your draggable and droppable elements.\n  </Card>\n\n  <Card title=\"Draggable\" icon=\"bullseye-pointer\" href=\"/concepts/draggable\">\n    Learn how to make elements draggable with the `Draggable` class.\n  </Card>\n\n  <Card title=\"Droppable\" icon=\"expand\" href=\"/concepts/droppable\">\n    Learn how to create droppable targets with the `Droppable` class.\n  </Card>\n\n  <Card title=\"Sortable\" icon=\"layer-group\" href=\"/concepts/sortable\">\n    Learn how to create sortable elements with the `Sortable` class.\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "apps/docs/react/components/drag-drop-provider.mdx",
    "content": "---\ntitle: 'DragDropProvider'\ndescription: 'Enable drag and drop interactions in your React application.'\nicon: 'sitemap'\n---\n\n## Overview\n\nThe `DragDropProvider` component creates a context that enables drag and drop interactions for its children. It manages the drag and drop state and coordinates between draggable and droppable elements.\n\n## Basic Usage\n\nWrap your application or a section with `DragDropProvider`:\n\n```jsx\nimport {DragDropProvider} from '@dnd-kit/react';\n\nfunction App() {\n  return (\n    <DragDropProvider>\n      <YourDraggableContent />\n    </DragDropProvider>\n  );\n}\n```\n\n## Event Handling\n\nListen to drag and drop events to respond to user interactions:\n\n```jsx\nfunction App() {\n  return (\n    <DragDropProvider\n      onBeforeDragStart={({source, event}) => {\n        // Optionally prevent dragging\n        if (shouldPreventDrag(source)) {\n          event.preventDefault();\n        }\n      }}\n      onDragStart={({source}) => {\n        console.log('Started dragging', source.id);\n      }}\n      onDragMove={({operation}) => {\n        const {position} = operation;\n        console.log('Current position:', position);\n      }}\n      onDragOver={({source, target}) => {\n        console.log(`${source.id} is over ${target.id}`);\n      }}\n      onDragEnd={({source, target}) => {\n        if (target) {\n          console.log(`Dropped ${source.id} onto ${target.id}`);\n        }\n      }}\n    >\n      <YourDraggableContent />\n    </DragDropProvider>\n  );\n}\n```\n\n## Multiple Contexts\n\nYou can create multiple independent drag and drop contexts:\n\n```jsx\nfunction App() {\n  return (\n    <div>\n      <DragDropProvider>\n        <FileList /> {/* Files can only be dropped in this context */}\n      </DragDropProvider>\n\n      <DragDropProvider>\n        <TaskList /> {/* Tasks can only be dropped in this context */}\n      </DragDropProvider>\n    </div>\n  );\n}\n```\n\n## Configuration\n\nCustomize behavior with plugins, sensors, and modifiers. Each accepts either an array (which replaces the defaults) or a function that receives the defaults.\n\n### Extending defaults\n\nUse the function form to add to or configure the defaults without replacing them:\n\n```jsx\nimport {DragDropProvider} from '@dnd-kit/react';\nimport {Feedback} from '@dnd-kit/dom';\nimport {RestrictToWindow} from '@dnd-kit/dom/modifiers';\n\nfunction App() {\n  return (\n    <DragDropProvider\n      // Add a plugin alongside defaults\n      plugins={(defaults) => [\n        ...defaults,\n        Feedback.configure({ dropAnimation: null }),\n      ]}\n      // Add a modifier\n      modifiers={(defaults) => [...defaults, RestrictToWindow]}\n    >\n      <YourDraggableContent />\n    </DragDropProvider>\n  );\n}\n```\n\n### Replacing defaults\n\nPass an array to fully replace the defaults:\n\n```jsx\nimport {DragDropProvider} from '@dnd-kit/react';\nimport {PointerSensor, KeyboardSensor} from '@dnd-kit/dom';\n\nfunction App() {\n  return (\n    <DragDropProvider\n      sensors={[\n        PointerSensor,\n        KeyboardSensor,\n      ]}\n      plugins={[\n        AutoScroller,\n        Accessibility,\n      ]}\n      modifiers={[\n        RestrictToWindow,\n      ]}\n    >\n      <YourDraggableContent />\n    </DragDropProvider>\n  );\n}\n```\n\n## API Reference\n\n### Props\n\n<ParamField path=\"children\" type=\"ReactNode\" required>\n  Content where drag and drop should be enabled.\n</ParamField>\n\n<ParamField path=\"manager\" type=\"DragDropManager\">\n  Optional custom manager instance. If not provided, one will be created.\n</ParamField>\n\n### Events\n\n<ParamField path=\"onBeforeDragStart\" type=\"(event: BeforeDragStartEvent, manager: DragDropManager) => void\">\n  Called before dragging starts. Call `event.preventDefault()` to cancel.\n</ParamField>\n\n<ParamField path=\"onDragStart\" type=\"(event: DragStartEvent, manager: DragDropManager) => void\">\n  Called when dragging begins.\n</ParamField>\n\n<ParamField path=\"onDragMove\" type=\"(event: DragMoveEvent, manager: DragDropManager) => void\">\n  Called when the dragged element moves.\n</ParamField>\n\n<ParamField path=\"onDragOver\" type=\"(event: DragOverEvent, manager: DragDropManager) => void\">\n  Called when dragging over a droppable target. Call `event.preventDefault()` to prevent the default behavior of plugins that respond to this event.\n</ParamField>\n\n<ParamField path=\"onDragEnd\" type=\"(event: DragEndEvent, manager: DragDropManager) => void\">\n  Called when dragging ends, whether dropped on a target or not.\n</ParamField>\n\n<ParamField path=\"onCollision\" type=\"(event: CollisionEvent, manager: DragDropManager) => void\">\n  Called when collisions are detected. Call `event.preventDefault()` to prevent automatic target selection.\n</ParamField>\n\n### Configuration\n\n<ParamField path=\"sensors\" type=\"Sensor[] | (defaults: Sensor[]) => Sensor[]\">\n  [Sensors](/extend/sensors) for detecting user input. Pass an array to replace defaults, or a function to extend them.\n</ParamField>\n\n<ParamField path=\"plugins\" type=\"Plugin[] | (defaults: Plugin[]) => Plugin[]\">\n  [Plugins](/extend/plugins) to extend functionality. Pass an array to replace defaults, or a function to extend them.\n</ParamField>\n\n<ParamField path=\"modifiers\" type=\"Modifier[] | (defaults: Modifier[]) => Modifier[]\">\n  [Modifiers](/extend/modifiers) to customize drag behavior. Pass an array to replace defaults, or a function to extend them.\n</ParamField>\n"
  },
  {
    "path": "apps/docs/react/components/drag-overlay.mdx",
    "content": "---\ntitle: 'DragOverlay'\ndescription: 'Render a custom element as visual feedback during drag operations.'\nicon: 'clone'\n---\n\n## Overview\n\nThe `DragOverlay` component renders a custom overlay element while a drag operation is in progress. This allows you to display a completely different element than the one being dragged, which is useful for rendering a styled clone, a preview, or a simplified representation of the dragged element.\n\n<img src=\"/images/draggable/drag-overlay.png\" />\n\n## Usage\n\nImport and place the `DragOverlay` component inside a [`DragDropProvider`](/react/components/drag-drop-provider). Its children will only be rendered when a drag operation is active.\n\n```jsx\nimport {useDraggable, DragOverlay} from '@dnd-kit/react';\n\nfunction Draggable() {\n  const {ref} = useDraggable({id: 'draggable'});\n\n  return (\n    <>\n      <button ref={ref}>Draggable</button>\n      <DragOverlay>\n        <div>I will be rendered while dragging...</div>\n      </DragOverlay>\n    </>\n  );\n}\n```\n\n<Warning>\n  You should only render the `DragOverlay` component once per [DragDropProvider](/react/components/drag-drop-provider) component.\n</Warning>\n\n### Rendering based on the drag source\n\nTo get around the fact that the `DragOverlay` component should only be rendered once, you can pass a function as a child, which will receive the `source` as an argument. This is useful for rendering different content depending on which element is being dragged.\n\n```jsx\nimport {DragDropProvider, DragOverlay} from '@dnd-kit/react';\n\nfunction App() {\n  return (\n    <DragDropProvider>\n      <Draggable id=\"foo\" />\n      <Draggable id=\"bar\" />\n      <DragOverlay>\n        {source => (\n          <div>Dragging {source.id}</div>\n        )}\n      </DragOverlay>\n    </DragDropProvider>\n  );\n}\n```\n\n### Customizing the drop animation\n\nBy default, when a drag operation ends, the overlay animates back to the position of the source element. You can customize or disable this animation using the `dropAnimation` prop.\n\n```jsx\n{/* Disable the drop animation */}\n<DragOverlay dropAnimation={null}>\n  <div>No animation on drop</div>\n</DragOverlay>\n\n{/* Customize the animation timing */}\n<DragOverlay dropAnimation={{ duration: 150, easing: 'ease-out' }}>\n  <div>Fast drop animation</div>\n</DragOverlay>\n\n{/* Provide a custom animation function */}\n<DragOverlay dropAnimation={async ({ element, feedbackElement, translate }) => {\n  // Custom animation logic using Web Animations API, GSAP, etc.\n}}>\n  <div>Custom animation</div>\n</DragOverlay>\n```\n\n## Props\n\n<ParamField path=\"children\" type=\"ReactNode | ((source: Draggable) => ReactNode)\">\n  The content to render as the drag overlay. Only rendered when a drag operation is in progress. Can be a React node or a function that receives the drag `source` as an argument.\n</ParamField>\n\n<ParamField path=\"tag\" type=\"string\" default=\"'div'\">\n  The HTML tag to render as the overlay wrapper element.\n</ParamField>\n\n<ParamField path=\"disabled\" type=\"boolean | ((source: Draggable | null) => boolean)\">\n  Whether the drag overlay is disabled. Can be a boolean or a function that receives the current drag source.\n</ParamField>\n\n<ParamField path=\"dropAnimation\" type=\"DropAnimation | null\" optional>\n  Customize or disable the drop animation that plays when a drag operation ends.\n\n  - `undefined` – use the default animation (`250ms` ease)\n  - `null` – disable the drop animation entirely\n  - `{duration, easing}` – customize the animation timing\n  - `(context) => Promise<void> | void` – provide a fully custom animation function\n</ParamField>\n\n<ParamField path=\"className\" type=\"string\" optional>\n  CSS class name for the overlay wrapper element.\n</ParamField>\n\n<ParamField path=\"style\" type=\"React.CSSProperties\" optional>\n  Inline styles for the overlay wrapper element.\n</ParamField>\n"
  },
  {
    "path": "apps/docs/react/guides/migration.mdx",
    "content": "---\ntitle: 'Migration guide'\ndescription: 'A comprehensive guide to migrate from `@dnd-kit/core` to `@dnd-kit/react`'\nicon: 'swap-arrows'\nmode: 'wide'\n---\n\n<Steps>\n  <Step title=\"Update dependencies\">\n    Update your `package.json` and install the new packages:\n\n    ```diff\n      \"dependencies\": {\n    -   \"@dnd-kit/core\": \"^x.x.x\"\n    -   \"@dnd-kit/sortable\": \"^x.x.x\"\n    -   \"@dnd-kit/utilities\": \"^x.x.x\"\n    +   \"@dnd-kit/react\": \"^x.x.x\"\n    +   \"@dnd-kit/helpers\": \"^x.x.x\"\n      }\n    ```\n\n    After updating your package.json, install the new dependencies with your package manager of choice.\n  </Step>\n\n  <Step title=\"Migrate context provider\">\n    Update your context provider. The new [DragDropProvider](/react/components/drag-drop-provider) replaces the legacy `DndContext`:\n\n    <CodeGroup>\n    ```tsx Before\n    import {DndContext} from '@dnd-kit/core';\n\n    function App() {\n      return (\n        <DndContext\n          onDragStart={({active}) => {\n            console.log(`Started dragging ${active.id}`);\n          }}\n          onDragEnd={({active, over}) => {\n            if (over) {\n              console.log(`Dropped ${active.id} over ${over.id}`);\n            }\n          }}\n          onDragCancel={({active}) => {\n            console.log(`Cancelled dragging ${active.id}`);\n          }}\n        >\n          <YourComponents />\n        </DndContext>\n      );\n    }\n    ```\n\n    ```tsx After {1,6-8,10-24}\n    import {DragDropProvider} from '@dnd-kit/react';\n\n    function App() {\n      return (\n        <DragDropProvider\n          onDragStart={(event, manager) => {\n            const {operation} = event;\n            console.log(`Started dragging ${operation.source.id}`);\n          }}\n          onDragEnd={(event, manager) => {\n            const {operation, canceled} = event;\n            const {source, target} = operation;\n\n            if (canceled) {\n              // Replaces onDragCancel\n              console.log(`Cancelled dragging ${source.id}`);\n              return;\n            }\n\n            if (target) {\n              console.log(`Dropped ${source.id} over ${target.id}`);\n              // Access rich data\n              console.log('Source data:', source.data);\n              console.log('Drop position:', operation.position.current);\n            }\n          }}\n        >\n          <YourComponents />\n        </DragDropProvider>\n      );\n    }\n    ```\n    </CodeGroup>\n\n    <Info>\n      The new provider gives you access to the `manager` instance in event handlers, enabling more advanced control over the drag and drop system.\n    </Info>\n  </Step>\n\n  <Step title=\"Update draggable components\">\n    Update your [draggable](/concepts/draggable) components using the new [useDraggable](/react/hooks/use-draggable) hook:\n\n    <CodeGroup>\n    ```tsx Before\n    function DraggableItem({id}) {\n      const {\n        attributes,\n        listeners,\n        setNodeRef,\n        transform\n      } = useDraggable({\n        id\n      });\n\n      return (\n        <div\n          ref={setNodeRef}\n          {...listeners}\n          {...attributes}\n          style={{\n            transform: CSS.Transform.toString(transform)\n          }}\n        >\n          Item {id}\n        </div>\n      );\n    }\n    ```\n\n    ```tsx After {2-4,7-8}\n    function DraggableItem({id}) {\n      const draggable = useDraggable({\n        id,\n      });\n\n      return (\n        <div\n          ref={draggable.ref}\n          className={isDragging ? 'dragging' : ''}\n        >\n          Item {id}\n        </div>\n      );\n    }\n    ```\n    </CodeGroup>\n  </Step>\n\n  <Step title=\"Update droppable components\">\n    Update your [droppable](/concepts/droppable) components using the new [useDroppable](/react/hooks/use-droppable) hook:\n\n    <CodeGroup>\n    ```tsx Before\n    function Dropzone() {\n      const {setNodeRef, isOver} = useDroppable({\n        id: 'drop-zone'\n      });\n\n      return (\n        <div\n          ref={setNodeRef}\n          style={{\n            background: isOver ? 'lightblue' : 'white'\n          }}\n        >\n          Drop here\n        </div>\n      );\n    }\n    ```\n\n    ```tsx After {2,8,10}\n    function Dropzone() {\n      const droppable = useDroppable({\n        id: 'drop-zone'\n      });\n\n      return (\n        <div\n          ref={droppable.ref}\n          style={{\n            background: droppable.isDropTarget ? 'green' : 'white'\n          }}\n        >\n          Drop here\n        </div>\n      );\n    }\n    ```\n    </CodeGroup>\n  </Step>\n\n  <Step title=\"Update drag overlay\">\n    The [DragOverlay](/react/components/drag-overlay) component has been simplified:\n\n    <CodeGroup>\n    ```tsx Before\n    function App() {\n      const [activeId, setActiveId] = useState(null);\n\n      return (\n        <DndContext\n          onDragStart={() => setActiveId('item')}\n          onDragEnd={() => setActiveId(null)}\n        >\n          <Draggable id=\"item\" />\n          <DragOverlay>\n            {activeId ? <Item id={activeId} /> : null}\n          </DragOverlay>\n        </DndContext>\n      );\n    }\n    ```\n\n    ```tsx After {2,5,7-9}\n    function App() {\n      return (\n        <DragDropProvider>\n          <Draggable id=\"item\" />\n          <DragOverlay>\n            {source => (\n              <Item id={source.id} />\n            )}\n          </DragOverlay>\n        </DragDropProvider>\n      );\n    }\n    ```\n    </CodeGroup>\n\n    <Warning>\n      Only render the `DragOverlay` component once per `DragDropProvider`. The hooks have no effect when used within the overlay.\n    </Warning>\n  </Step>\n\n  <Step title=\"Migrate sortable components\">\n    Update your sortable components using the new [useSortable](/react/hooks/use-sortable) hook:\n\n    <CodeGroup>\n    ```tsx Before\n    import {useSortable} from '@dnd-kit/sortable';\n\n    function SortableItem({id, index}) {\n      const {\n        attributes,\n        listeners,\n        setNodeRef,\n        transform,\n        transition\n      } = useSortable({\n        id,\n        index\n      });\n\n      return (\n        <div\n          ref={setNodeRef}\n          {...attributes}\n          {...listeners}\n          style={{\n            transform: CSS.Transform.toString(transform),\n            transition\n          }}\n        >\n          Item {id}\n        </div>\n      );\n    }\n    ```\n\n    ```tsx After {1,4-7,10-11}\n    import {useSortable} from '@dnd-kit/react/sortable';\n\n    function SortableItem({id, index}) {\n      const sortable = useSortable({\n        id,\n        index\n      });\n\n      return (\n        <div\n          ref={sortable.ref}\n          className={sortable.isDragging ? 'dragging' : undefined}\n        >\n          Item {id}\n        </div>\n      );\n    }\n    ```\n    </CodeGroup>\n\n    Use the array manipulation helpers from `@dnd-kit/helpers` to handle reordering.\n  </Step>\n</Steps>\n\n## Next steps\n\n<CardGroup cols={2}>\n  <Card\n    title=\"Quickstart guide\"\n    icon=\"rocket\"\n    href=\"/react/quickstart\"\n  >\n    Build beautiful drag and drop interfaces in minutes with the new dnd kit\n  </Card>\n  <Card\n    title=\"Draggable elements\"\n    icon=\"bullseye-pointer\"\n    href=\"/concepts/draggable\"\n  >\n    Learn how to make elements draggable with the new API\n  </Card>\n  <Card\n    title=\"Droppable targets\"\n    icon=\"expand\"\n    href=\"/concepts/droppable\"\n  >\n    Create drop zones and handle collision detection\n  </Card>\n  <Card\n    title=\"Sortable lists\"\n    icon=\"layer-group\"\n    href=\"/concepts/sortable\"\n  >\n    Build sortable interfaces with array manipulation helpers\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "apps/docs/react/guides/multiple-sortable-lists.mdx",
    "content": "---\ntitle: 'Multiple sortable lists'\ndescription: 'Learn how to reorder sortable elements across multiple lists.'\nicon: 'columns-3'\nmode: \"wide\"\n---\n\nimport {Story} from '/snippets/story.mdx';\nimport {CodeSandbox} from '/snippets/sandbox.mdx';\n\n<Story id=\"react-sortable-multiple-lists--hero\" height=\"400\" hero />\n\n## Overview\n\nIn this guide, you'll learn how to reorder sortable elements across multiple lists. This is useful when you have multiple lists and you want to move elements between them.\n\nBefore getting started, make sure you familiarize yourself with the [useSortable](/react/hooks/use-sortable) hook.\n\nWe'll be setting up three columns, and each column will have its own list of items. You'll be able to drag and drop items between the columns.\n\n## Setup\n\nFirst, let's set up the initial setup for the columns and items. We'll be creating three files, `App.js`, `Column.js`, and `Item.js`, and applying some basic styles in the `Styles.css` file.\n\n<CodeSandbox height=\"560\" previewHeight=\"260\" files={{\n  \"App.js\": App,\n  \"Column.js\": Column,\n  \"Item.js\": Item,\n  \"styles.css\": Styles\n}} showTabs />\n\n## Adding drag and drop functionality\n\nNow, let's add drag and drop functionality to the items. We'll be using the [useSortable](/react/hooks/use-sortable) hook to make the items sortable. Let's modify the `Item` component to make it sortable:\n\n<CodeSandbox height=\"435\" previewHeight=\"260\" files={{\n  ...files,\n  \"Item.js\": {code: SortableItem, active: true},\n}} showTabs />\n\nAs you can see, we've added the `useSortable` hook to the `Item` component. We've also passed the `id`, `index`, `type`, `accept`, and `group` props to the hook.\n\nThis creates an uncontrolled list of sortable items that can be sorted within each column, and across columns thanks to the `group` property. However, in order to be able to move items to an empty column, we need to add some additional logic.\n\n## Moving items between columns\n\nTo move items to empty columns, we need to add make each column droppable.\n\nWe'll be using the [useDroppable](/react/hooks/use-droppable) hook to create a drop target for each column. Let's modify the `Column` component to make it droppable:\n\n<CodeSandbox height=\"455\" previewHeight=\"260\" files={{\n  ...files,\n  \"Column.js\": {code: DroppableColumn, active: true},\n}} showTabs />\n\n<Note>We're setting the `collisionPriority` to `CollisionPriority.Low` to prioritize collisions of items over collisions of columns. Learn more about [detecting collisions](/concepts/droppable#detecting-collisions).</Note>\n\nThis will allow us to drop items into each column. However, we still need to handle the logic for moving items between columns.\n\nWe'll be using the [DragDropProvider](/react/components/drag-drop-provider) component to listen and respond to the drag and drop events. Let's modify the `App` component to add the `DragDropProvider`. We'll be using the `move` helper function from `@dnd-kit/helpers` to help us mutate the array of items between columns:\n\n<CodeSandbox height=\"455\" previewHeight=\"260\" files={{\n  ...files,\n  \"App.js\": {code: AppDroppableColumns, active: true},\n  \"Column.js\": {code: DroppableColumn},\n}} showTabs />\n\nAs you can see, we've added the `DragDropProvider` component to the `App` component. We've also added an `onDragOver` event handler to listen for drag and drop events.\n\nWhen an item is dragged over a column, the `onDragOver` event handler will be called. We'll use the `move` helper function to move the item between columns.\n\nThe result is a sortable list of items that can be moved between columns.\n\n### Making the columns sortable\n\nIf you want to make the columns themselves sortable, you can use the `useSortable` hook in the `Column` component.\nHere's how you can modify the `Column` component to make it sortable:\n\n<CodeSandbox height=\"455\" previewHeight=\"260\" files={{\n  ...files,\n  \"App.js\": {code: AppSortableColumns},\n  \"Column.js\": {code: SortableColumn, active: true},\n}} showTabs />\n\n<Info>You'll also need to pass the column `index` prop to the `Column` component in the `App` component.</Info>\n\nIf we want to control the state of the columns in React, we can update the `App` component to handle the column order in the `onDragEnd` callback:\n\n```jsx App.js\nexport function App() {\n  const [items, setItems] = useState({\n    A: ['A0', 'A1', 'A2'],\n    B: ['B0', 'B1'],\n    C: [],\n  });\n  const [columnOrder, setColumnOrder] = useState(() => Object.keys(items));\n\n  return (\n    <DragDropProvider\n      onDragOver={(event) => {\n        const {source, target} = event.operation;\n\n        if (source?.type === 'column') return;\n\n        setItems((items) => move(items, event));\n      }}\n      onDragEnd={(event) => {\n        const {source, target} = event.operation;\n\n        if (event.canceled || source.type !== 'column') return;\n\n        setColumnOrder((columns) => move(columns, event));\n      }}\n    >\n      <div className=\"Root\">\n        {columnOrder.map((column, columnIndex) => (\n          <Column key={column} id={column} index={columnIndex}>\n            {items[column].map((id, index) => (\n              <Item key={id} id={id} index={index} column={column} />\n            ))}\n          </Column>\n        ))}\n      </div>\n    </DragDropProvider>\n  );\n}\n```\n\nWe're using the `onDragEnd` event handler instead of the `onDragOver` event handler to handle the column order. This allows us to only update the order of the columns in React when the drag operation is completed, while letting `@dnd-kit` optimistically update the order of the columns during the drag operation, without causing unnecessary re-renders.\nIf we wanted more control over the drag and drop operation, we could also handle the event in the `onDragOver` callback.\n\n## Handling canceled drag operations\n\nIt's possible for a drag operation to be canceled. For example, users can cancel a drag operation initiated by the [Pointer sensor](/extend/sensors/pointer-sensor) by pressing the `Escape` key.\n\nWhen you update the order of items in the `onDragOver` callback, you should make sure to check if the user decided to abort the drag operation in the `onDragEnd` callback. If the drag operation was canceled, you should revert the order of items to the state before the drag operation started.\n\nFor example, here is how we would update our app to handle this case for the order of items:\n\n```jsx App.js\nimport React, {useRef, useState} from 'react';\nimport {DragDropProvider} from '@dnd-kit/react';\nimport {move} from '@dnd-kit/helpers';\nimport \"./styles.css\";\n\nimport {Column} from './Column';\nimport {Item} from './Item';\n\nexport function App({style = styles}) {\n  const [items, setItems] = useState({\n    A: ['A0', 'A1', 'A2'],\n    B: ['B0', 'B1'],\n    C: [],\n  });\n  const previousItems = useRef(items);\n  const [columnOrder, setColumnOrder] = useState(() => Object.keys(items));\n\n  return (\n    <DragDropProvider\n      onDragStart={() => {\n        previousItems.current = items;\n      }}\n      onDragOver={(event) => {\n        const {source, target} = event.operation;\n\n        if (source?.type === 'column') return;\n\n        setItems((items) => move(items, event));\n      }}\n      onDragEnd={(event) => {\n        const {source, target} = event.operation;\n\n        if (event.canceled) {\n          if (source.type === 'item') {\n            setItems(previousItems.current);\n          }\n\n          return;\n        }\n\n        if (source.type === 'column') {\n          setColumnOrder((columns) => move(columns, event));\n        }\n      }}\n    >\n      <div className=\"Root\">\n        {columnOrder.map((column, columnIndex) => (\n          <Column key={column} id={column} index={columnIndex}>\n            {items[column].map((id, index) => (\n              <Item key={id} id={id} index={index} column={column} />\n            ))}\n          </Column>\n        ))}\n      </div>\n    </DragDropProvider>\n  );\n}\n```\n\n<Note>Optimistic updates performed by `@dnd-kit` are automatically reverted when a drag operation is canceled.</Note>\n\nexport const App = `import React, {useState} from 'react';\nimport {Column} from './Column.js';\nimport {Item} from './Item.js';\nimport './styles.css';\n\nexport default function App() {\n  const [items] = useState({\n    A: ['A0', 'A1', 'A2'],\n    B: ['B0', 'B1'],\n    C: [],\n  });\n\n  return (\n    <div className=\"Root\">\n      {Object.entries(items).map(([column, items]) => (\n        <Column key={column} id={column}>\n          {items.map((id, index) => (\n            <Item key={id} id={id} index={index} column={column} />\n          ))}\n        </Column>\n      ))}\n    </div>\n  );\n}`;\n\nexport const AppDroppableColumns = `import React, {useState} from 'react';\nimport {DragDropProvider} from '@dnd-kit/react';\nimport {move} from '@dnd-kit/helpers';\nimport {Column} from './Column.js';\nimport {Item} from './Item.js';\nimport './styles.css';\n\nexport default function App() {\n  const [items, setItems] = useState({\n    A: ['A0', 'A1', 'A2'],\n    B: ['B0', 'B1'],\n    C: [],\n  });\n\n  return (\n    <DragDropProvider\n      onDragOver={(event) => {\n        setItems((items) => move(items, event));\n      }}\n    >\n      <div className=\"Root\">\n        {Object.entries(items).map(([column, items]) => (\n          <Column key={column} id={column}>\n            {items.map((id, index) => (\n              <Item key={id} id={id} index={index} column={column} />\n            ))}\n          </Column>\n        ))}\n      </div>\n    </DragDropProvider>\n  );\n}`;\n\nexport const AppSortableColumns = `import React, {useState} from 'react';\nimport {DragDropProvider} from '@dnd-kit/react';\nimport {move} from '@dnd-kit/helpers';\nimport {Column} from './Column.js';\nimport {Item} from './Item.js';\nimport './styles.css';\n\nexport default function App() {\n  const [items, setItems] = useState({\n    A: ['A0', 'A1', 'A2'],\n    B: ['B0', 'B1'],\n    C: [],\n  });\n\n  return (\n    <DragDropProvider\n      onDragOver={(event) => {\n        const {source} = event.operation;\n\n        if (source.type === 'column') return;\n\n        setItems((items) => move(items, event));\n      }}\n    >\n      <div className=\"Root\">\n        {Object.entries(items).map(([column, items], index) => (\n          <Column key={column} id={column} index={index}>\n            {items.map((id, index) => (\n              <Item key={id} id={id} index={index} column={column} />\n            ))}\n          </Column>\n        ))}\n      </div>\n    </DragDropProvider>\n  );\n}`;\n\nexport const Column = `import React from 'react';\n\nexport function Column({children, id}) {\n  return (\n    <div className=\"Column\">\n      {children}\n    </div>\n  );\n}`;\n\nexport const DroppableColumn = `import React from 'react';\nimport {useDroppable} from '@dnd-kit/react';\nimport {CollisionPriority} from '@dnd-kit/abstract';\n\nexport function Column({children, id}) {\n  const {isDropTarget, ref} = useDroppable({\n    id,\n    type: 'column',\n    accept: 'item',\n    collisionPriority: CollisionPriority.Low,\n  });\n  const style = isDropTarget ? {background: '#00000030'} : undefined;\n\n  return (\n    <div className=\"Column\" ref={ref} style={style}>\n      {children}\n    </div>\n  );\n}`;\n\nexport const SortableColumn = `import React from 'react';\nimport {CollisionPriority} from '@dnd-kit/abstract';\nimport {useSortable} from '@dnd-kit/react/sortable';\n\nexport function Column({children, id, index}) {\n  const {ref} = useSortable({\n    id,\n    index,\n    type: 'column',\n    collisionPriority: CollisionPriority.Low,\n    accept: ['item', 'column'],\n  });\n\n  return (\n    <div className=\"Column\" ref={ref}>\n      {children}\n    </div>\n  );\n}`;\n\nexport const Item = `import React from 'react';\n\nexport function Item({id, index}) {\n  return (\n    <button className=\"Item\">\n      {id}\n    </button>\n  );\n}`;\n\nexport const SortableItem = `import React from 'react';\nimport {useSortable} from '@dnd-kit/react/sortable';\n\nexport function Item({id, index, column}) {\n  const {ref, isDragging} = useSortable({\n    id,\n    index,\n    type: 'item',\n    accept: 'item',\n    group: column\n  });\n\n  return (\n    <button className=\"Item\" ref={ref} data-dragging={isDragging}>\n      {id}\n    </button>\n  );\n}`;\n\nexport const Styles = `\n.Root {\n  display: flex;\n  flex-direction: row;\n  gap: 20px;\n  flex-wrap: wrap;\n}\n\n.Column {\n  display: flex;\n  flex-direction: column;\n  gap: 10px;\n  padding: 20px;\n  min-width: 175px;\n  min-height: 200px;\n  background-color: rgba(0, 0, 0, 0.1);\n  border: 1px solid rgba(0, 0, 0, 0.1);\n  border-radius: 10px;\n}\n\n.Item {\n  appearance: none;\n  background: #FFF;\n  color: #666;\n  padding: 12px 20px;\n  border: none;\n  border-radius: 5px;\n  cursor: grab;\n  transition: transform 0.2s ease, box-shadow 0.2s ease;\n  transform: scale(1);\n  box-shadow: inset 0px 0px 1px rgba(0,0,0,0.4), 0 0 0 calc(1px / var(--scale-x, 1)) rgba(63, 63, 68, 0.05), 0px 1px calc(2px / var(--scale-x, 1)) 0 rgba(34, 33, 81, 0.05);\n}\n\n.Item[data-dragging=\"true\"] {\n  transform: scale(1.02);\n  box-shadow: inset 0px 0px 1px rgba(0,0,0,0.5), -1px 0 15px 0 rgba(34, 33, 81, 0.01), 0px 15px 15px 0 rgba(34, 33, 81, 0.25)\n}`;\n\nexport const files = {\n  \"Item.js\": {code: SortableItem, hidden: true},\n  \"App.js\": {code: App, hidden: true},\n  \"Column.js\": {code: Column, hidden: true},\n  \"styles.css\": {code: Styles, hidden: true}\n};\n"
  },
  {
    "path": "apps/docs/react/guides/sortable-state-management.mdx",
    "content": "---\ntitle: 'Managing sortable state'\ndescription: 'Learn how to manage sortable state with and without the move helper.'\nicon: 'sliders'\n---\n\n## Overview\n\nWhen building sortable interfaces, you need to keep your application state in sync with drag operations. There are two approaches:\n\n1. **Using the `move` helper** from `@dnd-kit/helpers` — a convenience function that takes your items and a drag event and returns a new array with the item moved to its new position. It supports flat arrays and grouped records, handles canceled drags, and works with optimistic sorting out of the box. This is covered in the [Multiple sortable lists](/react/guides/multiple-sortable-lists) guide.\n2. **Manual state management** — using the sortable properties and type guards for full control over state updates.\n\nThis guide covers the second approach. Before reading this guide, make sure you're familiar with [optimistic sorting](/concepts/sortable#optimistic-sorting), which is enabled by default and affects how `source` and `target` behave during drag operations.\n\n## Understanding optimistic sorting\n\nThe `OptimisticSortingPlugin` is enabled by default for all sortable items. It optimistically reorders DOM elements during a drag so the UI feels responsive without requiring React re-renders on every `dragover` event.\n\nA key consequence is that **`source` and `target` in the drag operation will refer to the same element** during a drag. This means you cannot compare `source.id` and `target.id` to determine what moved.\n\nInstead, use the sortable-specific properties on the source:\n\n| Property | Description |\n|----------|-------------|\n| `index` | The current position (updated as the item moves) |\n| `initialIndex` | The position when the drag started |\n| `group` | The current group |\n| `initialGroup` | The group when the drag started |\n\n<Note>\n  These properties are available on the `source` when it is a sortable element. Use the `isSortable` type guard to narrow the type.\n</Note>\n\n<Tip>\n  You can call `event.preventDefault()` in `onDragOver` to prevent the `OptimisticSortingPlugin` from optimistically updating for that specific event. This is useful when you want to conditionally block certain moves (for example, preventing items from being dragged into a specific group).\n</Tip>\n\n## Single list without the move helper\n\nWith optimistic sorting, you only need to handle `onDragEnd`. The `OptimisticSortingPlugin` takes care of visual feedback during the drag.\n\n```tsx\nimport {useState} from 'react';\nimport {DragDropProvider} from '@dnd-kit/react';\nimport {useSortable, isSortable} from '@dnd-kit/react/sortable';\n\nfunction SortableItem({id, index}) {\n  const {ref} = useSortable({id, index});\n\n  return <li ref={ref}>{id}</li>;\n}\n\nexport default function App() {\n  const [items, setItems] = useState([1, 2, 3, 4, 5]);\n\n  return (\n    <DragDropProvider\n      onDragEnd={(event) => {\n        if (event.canceled) return;\n\n        const {source} = event.operation;\n\n        if (isSortable(source)) {\n          const {initialIndex, index} = source;\n\n          if (initialIndex !== index) {\n            setItems((items) => {\n              const newItems = [...items];\n              const [removed] = newItems.splice(initialIndex, 1);\n              newItems.splice(index, 0, removed);\n              return newItems;\n            });\n          }\n        }\n      }}\n    >\n      <ul>\n        {items.map((id, index) => (\n          <SortableItem key={id} id={id} index={index} />\n        ))}\n      </ul>\n    </DragDropProvider>\n  );\n}\n```\n\n## Multiple lists without the move helper\n\nFor multiple lists, use `initialGroup` and `group` to detect whether the item stayed in the same list or moved to a different one:\n\n```tsx\nimport {useState, useRef} from 'react';\nimport {DragDropProvider} from '@dnd-kit/react';\nimport {useSortable, isSortable} from '@dnd-kit/react/sortable';\n\nfunction SortableItem({id, index, column}) {\n  const {ref} = useSortable({\n    id,\n    index,\n    group: column,\n    type: 'item',\n    accept: 'item',\n  });\n\n  return <li ref={ref}>{id}</li>;\n}\n\nexport default function App() {\n  const [items, setItems] = useState({\n    A: ['A1', 'A2', 'A3'],\n    B: ['B1', 'B2'],\n    C: [],\n  });\n  const snapshot = useRef(structuredClone(items));\n\n  return (\n    <DragDropProvider\n      onDragStart={() => {\n        snapshot.current = structuredClone(items);\n      }}\n      onDragEnd={(event) => {\n        if (event.canceled) {\n          setItems(snapshot.current);\n          return;\n        }\n\n        const {source} = event.operation;\n\n        if (isSortable(source)) {\n          const {initialIndex, index, initialGroup, group} = source;\n\n          if (initialGroup == null || group == null) return;\n\n          setItems((items) => {\n            if (initialGroup === group) {\n              // Same group: reorder within the list\n              const groupItems = [...items[group]];\n              const [removed] = groupItems.splice(initialIndex, 1);\n              groupItems.splice(index, 0, removed);\n              return {...items, [group]: groupItems};\n            }\n\n            // Cross-group transfer\n            const sourceItems = [...items[initialGroup]];\n            const [removed] = sourceItems.splice(initialIndex, 1);\n            const targetItems = [...items[group]];\n            targetItems.splice(index, 0, removed);\n            return {\n              ...items,\n              [initialGroup]: sourceItems,\n              [group]: targetItems,\n            };\n          });\n        }\n      }}\n    >\n      {Object.entries(items).map(([column, columnItems]) => (\n        <ul key={column}>\n          {columnItems.map((id, index) => (\n            <SortableItem key={id} id={id} index={index} column={column} />\n          ))}\n        </ul>\n      ))}\n    </DragDropProvider>\n  );\n}\n```\n\n<Note>\n  When updating state in `onDragOver` (rather than `onDragEnd`), save a snapshot in `onDragStart` so you can revert if the drag is canceled.\n</Note>\n\n## Comparison with the move helper\n\n| | `move` helper | Manual state management |\n|---|---|---|\n| **Setup** | One line: `setItems(items => move(items, event))` | More code, but full control |\n| **When to update** | Typically in `onDragOver` or `onDragEnd` | Typically in `onDragEnd` only |\n| **ID matching** | Matches items by `item === id` or `item.id === id` | You control the logic entirely |\n| **Optimistic sorting** | Works with and without | Best with optimistic sorting enabled |\n| **Custom data structures** | Limited to arrays and records of arrays | Any data structure |\n\nUse the `move` helper when your data structure matches its expectations (flat arrays or `Record<string, array>`). Use manual state management when you need more control, have custom data structures, or use computed IDs.\n\n## Type guards\n\n### `isSortable`\n\nChecks whether a `Draggable` or `Droppable` is a sortable instance, narrowing the type to expose `index`, `initialIndex`, `group`, and `initialGroup`:\n\n```tsx\nimport {isSortable} from '@dnd-kit/react/sortable';\n\nconst {source, target} = event.operation;\n\nif (isSortable(source)) {\n  source.index;        // number\n  source.initialIndex; // number\n  source.group;        // string | number | undefined\n  source.initialGroup; // string | number | undefined\n}\n```\n\n### `isSortableOperation`\n\nNarrows both `source` and `target` of a drag operation at once:\n\n```tsx\nimport {isSortableOperation} from '@dnd-kit/react/sortable';\n\nconst {operation} = event;\n\nif (isSortableOperation(operation)) {\n  operation.source.initialIndex; // typed\n  operation.target.index;        // typed\n}\n```\n"
  },
  {
    "path": "apps/docs/react/hooks/use-drag-drop-monitor.mdx",
    "content": "---\ntitle: 'useDragDropMonitor'\ndescription: 'Monitor drag and drop events in your React components.'\nicon: 'signal-stream'\n---\n\n## Usage\n\nThe `useDragDropMonitor` hook allows you to monitor drag and drop events within a `DragDropProvider`:\n\n```tsx\nimport {useDragDropMonitor} from '@dnd-kit/react';\n\nfunction DragMonitor() {\n  useDragDropMonitor({\n    onBeforeDragStart(event, manager) {\n      // Optionally prevent dragging\n      if (shouldPreventDrag(event.operation.source)) {\n        event.preventDefault();\n      }\n    },\n    onDragStart(event, manager) {\n      console.log('Started dragging', event.operation.source);\n    },\n    onDragMove(event, manager) {\n      console.log('Current position:', event.operation.position);\n    },\n    onDragOver(event, manager) {\n      console.log('Over droppable:', event.operation.target);\n    },\n    onDragEnd(event, manager) {\n      const {operation, canceled} = event;\n\n      if (canceled) {\n        console.log('Drag cancelled');\n        return;\n      }\n\n      if (operation.target) {\n        console.log(`Dropped ${operation.source.id} onto ${operation.target.id}`);\n      }\n    },\n    onCollision(event, manager) {\n      console.log('Collisions:', event.collisions);\n    }\n  });\n\n  return null;\n}\n```\n\n<Warning>\nMake sure to use the `useDragDropMonitor` hook within a component that is wrapped in a [`DragDropProvider` component](/react/core/drag-drop-provider).\n</Warning>\n\n## Events\n\n| Event | Description | Preventable | Data |\n|-------|-------------|-------------|------|\n| `beforeDragStart` | Fires before drag begins | Yes | `operation` |\n| `dragStart` | Fires when drag starts | No | `operation`, `nativeEvent` |\n| `dragMove` | Fires during movement | Yes | `operation`, `to`, `by`, `nativeEvent` |\n| `dragOver` | Fires when over a droppable | Yes | `operation` |\n| `collision` | Fires on droppable collision | Yes | `collisions` |\n| `dragEnd` | Fires when drag ends | No | `operation`, `canceled`, `nativeEvent` |\n\n## Notes\n\n- The hook must be used within a `DragDropProvider`\n- Event handlers receive both the event data and the manager instance\n- Use `event.preventDefault()` on preventable events to stop their default behavior\n- The `dragEnd` event includes a `canceled` property that replaces the old `onDragCancel` event\n"
  },
  {
    "path": "apps/docs/react/hooks/use-draggable.mdx",
    "content": "---\ntitle: 'useDraggable'\ndescription: 'Use the `useDraggable` hook to make draggable elements that can dropped over droppable targets.'\nicon: 'bullseye-pointer'\n---\n\nimport {Story} from '/snippets/story.mdx';\nimport {CodeSandbox} from '/snippets/sandbox.mdx';\nimport {draggableStyles} from '/snippets/code.mdx';\n\n<CodeSandbox files={{\n  'App.js': {code: app, hidden: true},\n  'Draggable.js': {code, active: true},\n  'styles.css': {code: draggableStyles, hidden: true},\n}} height={220} previewHeight={200} hero />\n\nThe `useDraggable` hook requires an `id` and accepts all the same options as the `Draggable` class. Refer to the [Input](#input) section below for more information.\n\n## API Reference\n\n<Note>\n  The `useDraggable` hook is a thin wrapper around the [Draggable](/concepts/draggable) class that makes it easier to create draggable elements in React. It therefore accepts all of the same input arguments.\n</Note>\n\n### Input\n\nThe `useDraggable` hook accepts the following arguments:\n\n<ParamField path=\"id\" type=\"string | number\" required>\n  The identifier of the draggable element. Should be unique within the same [drag and drop context provider](/react/components/drag-drop-provider).\n</ParamField>\n\n<ParamField path=\"type\" type=\"string | number | Symbol\">\n  Optionally supply a type to only allow this draggable element to be dropped over droppable targets that [accept](/concepts/droppable) this `type`.\n</ParamField>\n\n<ParamField path=\"element\" type=\"Element | Ref<Element>\">\n  If you already have a reference to the element, you can pass it to the `element` option instead of using the `ref` that is returned by the `useDraggable` hook to connect the draggable source element.\n</ParamField>\n\n<ParamField path=\"handle\" type=\"Element | Ref<Element>\">\n  If you already have a reference to the drag handle element, you can pass it to the `handle` option instead of using the `handleRef` that is returned by the `useDraggable` hook to connect the drag handle element.\n</ParamField>\n\n<ParamField path=\"disabled\" type=\"boolean\">\n  Set to `true` to prevent the draggable element from being draggable.\n</ParamField>\n\n<ParamField path=\"plugins\" type=\"PluginDescriptor[]\">\n  An array of plugin descriptors for per-entity plugin configuration. Use `Plugin.configure()` to create descriptors. For example, `Feedback.configure({ feedback: 'clone' })`.\n</ParamField>\n\n<ParamField path=\"modifiers\" type=\"Modifier[]\">\n  An array of [modifiers](/extend/modifiers) that can be used to modify or restrict the behavior of the draggable element.\n</ParamField>\n\n<ParamField path=\"sensors\" type=\"Sensors[]\">\n  An array of [sensors](/extend/sensors) that can be bound to the draggable element to detect drag interactions.\n</ParamField>\n\n<ParamField path=\"data\" type=\"{[key: string]: any}\">\n  The data argument is for advanced use-cases where you may need access to additional data about the draggable element in event handlers, modifiers, sensors or custom plugins.\n</ParamField>\n\n<ParamField path=\"effects\" type=\"() => Effect[]\">\n  <Info>This is an advanced feature and should not need to be used by most consumers.</Info>\n  You can supply a function that returns an array of reactive effects that can be set up and automatically cleaned up when the component invoking the `useDraggable` hook element is unmounted.\n</ParamField>\n\n### Output\n\nThe `useDraggable` hook returns an object containing the following properties:\n\n<ResponseField name=\"ref\" type=\"(element: Element) => void\">\n  A [ref callback function](https://react.dev/reference/react-dom/components/common#ref-callback) that can be attached to the element that you want to make draggable.\n</ResponseField>\n\n<ResponseField name=\"handleRef\" type=\"(element: Element) => void\">\n  A [ref callback function](https://react.dev/reference/react-dom/components/common#ref-callback) that can be attached to an element to create a drag handle.\n</ResponseField>\n\n<ResponseField name=\"isDragSource\" type=\"boolean\">\n  A boolean value that indicates whether the draggable is the source of the drag operation that is in progress.\n</ResponseField>\n\n<ResponseField name=\"isDragging\" type=\"boolean\">\n  A boolean value that indicates whether the draggable is currently being dragged.\n</ResponseField>\n\n<ResponseField name=\"isDropping\" type=\"boolean\">\n  A boolean value that indicates whether the draggable is being dropped. This can be used to style the draggable element differently during the drop animation.\n</ResponseField>\n\n<ResponseField name=\"draggable\" type=\"Draggable\">\n  The [draggable](concepts/draggable) instance that is created by the `useDraggable` hook.\n</ResponseField>\n\n## Guides\n\n### Specifying a drag handle\n\nTo specify a drag handle, provide a reference to an element and pass it as the `handle` argument to the `useDraggable` hook. Alternatively, you can consume the `handleRef` ref callback to connect the drag handle element.\n\n```jsx\nimport {useDraggable} from '@dnd-kit/react';\n\nfunction Draggable(props) {\n  const {ref, handleRef} = useDraggable({\n    id: props.id,\n  });\n\n  return (\n    <div ref={ref}>\n      Draggable\n      <button ref={handleRef}>Drag handle</button>\n    </div>\n  );\n}\n```\n\n<Note>\n  When you connect a drag handle element, only the element that is connected to the `handleRef` will initiate the drag operation.\n</Note>\n\n<Story id=\"react-draggable-drag-handles--drag-handle\" />\n\n### Restricting dragging using modifiers\n\nUse [modifiers](/extend/modifiers) to modify or restrict the behavior of draggable elements.\n\nModifiers let you dynamically modify the movement coordinates that are detected by sensors. They can be used for a wide range of use cases, for example:\n\n- Restricting motion to a single axis\n- Restricting motion to the draggable node container's bounding rectangle\n- Restricting motion to the draggable node's scroll container bounding rectangle\n- Applying resistance or clamping the motion\n\nModifiers can be applied globally on the [&lt;DragDropProvider&gt;](/react/components/drag-drop-provider) component or locally on individual draggable elements.\n\nHere is an example of how to restrict dragging to the horizontal axis:\n\n```jsx\nimport {useDraggable} from '@dnd-kit/react';\nimport {RestrictToHorizontalAxis} from '@dnd-kit/abstract/modifiers';\n\nfunction Draggable({id}) {\n  const {ref} = useDraggable({\n    id,\n    modifiers: [RestrictToHorizontalAxis],\n  });\n}\n```\n\n<Story id=\"react-draggable-modifiers--horizontal-axis\" height=\"130\" />\n\nAnd here is an example of how to restrict dragging to the container element of the draggable:\n\n```jsx\nimport {useDraggable} from '@dnd-kit/react';\nimport {RestrictToElement} from '@dnd-kit/dom/modifiers';\n\nfunction Draggable({id}) {\n  const {ref} = useDraggable({\n    id,\n    modifiers: [RestrictToElement.configure({element: document.body})],\n  });\n}\n```\n\n<Story id=\"react-draggable-modifiers--container-modifier\" height=\"500\" />\n\nexport const app = `\nimport {Draggable} from './Draggable.js';\nimport './styles.css';\n\nexport default function App() {\n  return <Draggable id=\"draggable\"/>;\n}\n`.trim();\n\nexport const code = `\nimport {useDraggable} from '@dnd-kit/react';\n\nexport function Draggable(props) {\n  const {ref} = useDraggable({\n    id: props.id,\n  });\n\n  return <button ref={ref} className=\"btn\">draggable</button>;\n}\n`.trim();\n\n### Rendering a drag overlay\n\nYou can render a completely different element while the draggable element is being dragged by using the [`<DragOverlay>`](/react/components/drag-overlay) component.\n\n<img src=\"/images/draggable/drag-overlay.png\" />\n\n```jsx\nimport {useDraggable, DragOverlay} from '@dnd-kit/react';\n\nfunction Draggable() {\n  const {ref} = useDraggable({\n    id: 'draggable',\n  });\n\n  return (\n    <>\n      <button ref={ref}>\n        Draggable\n      </button>\n      <DragOverlay>\n        <div>I will be rendered while dragging...</div>\n      </DragOverlay>\n    </>\n  );\n}\n```\n\nThe `<DragOverlay>` component will only render its children when a drag operation is in progress. This can be useful for rendering a completely different element while the draggable element is being dragged.\n\n<Warning>\n You should only render the `<DragOverlay>` component once per [DragDropProvider](/react/components/drag-drop-provider) component.\n</Warning>\n\nTo get around the fact that the `<DragOverlay>` component should only rendered once, you can also pass a function as a child to the `<DragOverlay>` component, which will receive the `source` as an argument. This can be useful for rendering a clone of the source element while it is being dragged.\n\n```jsx\nimport {useDraggable, DragOverlay} from '@dnd-kit/react';\n\nfunction App(props) {\n  return (\n    <DragDropProvider>\n      <Draggable id=\"foo\" />\n      <Draggable id=\"bar\" />\n      <DragOverlay>\n        {source => (\n          <div>\n            Dragging {source.id}\n          </div>\n        )}\n      </DragOverlay>\n    </DragDropProvider>\n  );\n}\n```\n\n"
  },
  {
    "path": "apps/docs/react/hooks/use-droppable.mdx",
    "content": "---\ntitle: 'useDroppable'\ndescription: 'Use the `useDroppable` hook to create droppable targets for draggable elements.'\nicon: 'expand'\n---\n\nimport {CodeSandbox} from '/snippets/sandbox.mdx';\nimport {draggableStyles, droppableStyles} from '/snippets/code.mdx';\n\n<CodeSandbox files={{\n  'App.js': {code: app, hidden: true},\n  'Droppable.js': {code: droppableCode, active: true},\n  'styles.css': {code: draggableStyles + '\\n\\n' + droppableStyles + '\\n\\n' + containerStyles, hidden: true},\n}} height={255} previewHeight={400} hero />\n\n## Usage\n\nThe `useDroppable` hook requires an `id` and accepts all the same options as the `Droppable` class. Refer to the [Input](#input) section below for more information.\n\n```jsx\nimport {useDroppable} from '@dnd-kit/react';\n\nfunction Droppable(props) {\n  const {isDropTarget, ref} = useDroppable({\n    id: props.id,\n  });\n\n  return (\n    <div ref={ref}>\n      {isDropTarget ? 'Draggable element is over me' : 'Drag something over me'}\n    </div>\n  );\n}\n```\n\n## API Reference\n\n<Note>\n  The `useDroppable` hook is a thin wrapper around the [Droppable](/concepts/droppable) class that makes it easier to create droppable targets in React. It therefore accepts all of the same input arguments.\n</Note>\n\n\n### Input\n\nThe `useDroppable` hook accepts the following arguments:\n\n<ParamField path=\"id\" type=\"string | number\" required>\n  The identifier of the droppable element. Should be unique within the same [drag and drop context provider](/react/components/drag-drop-provider).\n</ParamField>\n\n<ParamField path=\"element\" type=\"Element | Ref<Element>\">\n  If you already have a reference to the element, you can pass it to the `element` option instead of using the `ref` that is returned by the `useDraggable` hook to connect the draggable source element.\n</ParamField>\n\n<ParamField path=\"accepts\" type=\"string | number | Symbol | (type: string | number | Symbol) => boolean\">\n  Optionally supply a type of draggable element to only allow it to be dropped over certina droppable targets that [accept](#) this `type`.\n</ParamField>\n\n<ParamField path=\"collisionDetector\" type=\"(input: CollisionDetectorInput) => Collision | null\">\n  Optionally supply a [collision detector](/concepts/droppable#detecting-collisions) function can be used to detect collisions between the droppable element and draggable elements.\n</ParamField>\n\n<ParamField path=\"collisionPriority\" type=\"number\">\n  Optionally supply a number to set the collision priority of the droppable element. The higher the number, the higher the priority when detecting collisions. This can be useful if there are multiple droppable elements that overlap.\n</ParamField>\n\n<ParamField path=\"disabled\" type=\"boolean\">\n  Set to `true` to prevent the droppable element from being a drop target.\n</ParamField>\n\n<ParamField path=\"data\" type=\"{[key: string]: any}\">\n  The data argument is for advanced use-cases where you may need access to additional data about the droppable element in event handlers, modifiers, sensors or custom plugins.\n</ParamField>\n\n<ParamField path=\"effects\" type=\"() => Effect[]\">\n  <Info>This is an advanced feature and should not need to be used by most consumers.</Info>\n  You can supply a function that returns an array of reactive effects that can be set up and automatically cleaned up when the component invoking the `useDraggable` hook element is unmounted.\n</ParamField>\n\n### Output\n\nThe `useDroppable` hook returns an object containing the following properties:\n\n<ResponseField name=\"ref\" type=\"(element: Element) => void\">\n  A [ref callback function](https://react.dev/reference/react-dom/components/common#ref-callback) that can be attached to the element that you want to use as a droppable target.\n</ResponseField>\n\n<ResponseField name=\"isDropTarget\" type=\"boolean\">\n  A boolean value that indicates whether the element is currently being dragged.\n</ResponseField>\n\n<ResponseField name=\"droppable\" type=\"Droppable\">\n  The [droppable](concepts/droppable) instance that is created by the `useDroppable` hook.\n</ResponseField>\n\nexport const app = `\nimport {useState} from 'react';\nimport {DragDropProvider, useDraggable} from '@dnd-kit/react';\nimport {Droppable} from './Droppable';\nimport './styles.css';\n\nfunction Draggable() {\n  const {ref} = useDraggable({id: 'draggable'});\n  return <button ref={ref} className=\"btn\">draggable</button>;\n}\n\nexport default function App() {\n  const [parent, setParent] = useState(undefined);\n  return (\n    <DragDropProvider\n      onDragEnd={(event) => {\n        if (event.canceled) return;\n        setParent(event.operation.target?.id);\n      }}\n    >\n      <div className=\"container\">\n        {parent == null ? <Draggable /> : null}\n        <Droppable>\n          {parent === 'droppable' ? <Draggable /> : null}\n        </Droppable>\n      </div>\n    </DragDropProvider>\n  );\n}\n`.trim();\n\nexport const droppableCode = `\nimport {useDroppable} from '@dnd-kit/react';\n\nexport function Droppable({children}) {\n  const {isDropTarget, ref} = useDroppable({id: 'droppable'});\n\n  return (\n    <div ref={ref} className={isDropTarget ? \"droppable active\" : \"droppable\"}>\n      {children}\n    </div>\n  );\n}\n`.trim();\n\nexport const containerStyles = `\n.container {\n  display: grid;\n  grid-template-columns: 2fr 1fr;\n  grid-gap: 20px;\n  align-items: center;\n  max-width: 700px;\n  margin: 0 auto;\n}\n`.trim();\n"
  },
  {
    "path": "apps/docs/react/hooks/use-sortable.mdx",
    "content": "---\ntitle: 'useSortable'\ndescription: 'Use the `useSortable` hook to reorder elements in a list or across multiple lists.'\nicon: 'layer-group'\n---\n\nimport {Story} from '/snippets/story.mdx';\nimport {CodeSandbox} from '/snippets/sandbox.mdx';\nimport {sortableStyles} from '/snippets/code.mdx';\n\n<Story id=\"react-sortable--example\" height=\"320\" hero />\n\n## Usage\n\nThe `useSortable` hook requires an `id` and an `index`. It accepts all the same options as the `Sortable` class. Refer to the [Input](#input) section below for more information.\n\nexport const code = `\nimport {useSortable} from '@dnd-kit/react/sortable';\n\nfunction Sortable({id, index}) {\n  const {ref} = useSortable({id, index});\n\n  return (\n    <li ref={ref} className=\"item\">Item {id}</li>\n  );\n}\n\nexport default function App() {\n  const items = [1, 2, 3, 4];\n\n  return (\n    <ul className=\"list\">\n      {items.map((id, index) =>\n        <Sortable key={id} id={id} index={index} />\n      )}\n    </ul>\n  );\n}\n`.trim();\n\n<CodeSandbox files={{\n  'App.js': {code, active: true},\n  'styles.css': {code: sortableStyles, hidden: true},\n}} height={455} previewHeight={180} />\n\n## API Reference\n\n<Note>\n  The `useSortable` hook is a thin wrapper around the [Sortable](/concepts/sortable) class that makes it easier to create sortable elements in React. It therefore accepts all of the same input arguments.\n</Note>\n\n### Input\n\nThe `useSortable` hook accepts all of the same arguments as the [useDraggable](/react/hooks/use-draggable) hook and [useDroppable](/react/hooks/use-droppable) hooks, as well as additional arguments that are specific to sortable elements.\n\n<ParamField path=\"id\" type=\"string | number\" required>\n  The identifier of the sortable element. Should be unique within the same [drag and drop context provider](/react/components/drag-drop-provider).\n</ParamField>\n\n<ParamField path=\"index\" type=\"number\" required>\n  The index of the sortable element. This is used to determine the position of the element in the list.\n</ParamField>\n\n<ParamField path=\"transition\" type=\"{duration?: number; easing?: string: idle: boolean} | null\">\n  Optionally supply a transition to animate the sortable element when it is being sorted.\n\n  <Expandable>\n    <ParamField path=\"duration\" type=\"number\">\n      The duration of the transition in milliseconds.\n    </ParamField>\n\n    <ParamField path=\"easing\" type=\"string\">\n      The easing function to use for the transition.\n    </ParamField>\n\n    <ParamField path=\"idle\" type=\"boolean\">\n      Whether the sortable item should transition to its new position when its index changes, but there is no drag operation in progress.\n    </ParamField>\n  </Expandable>\n</ParamField>\n\n<ParamField path=\"element\" type=\"Element | Ref<Element>\">\n  If you already have a reference to the element, you can pass it to the `element` option instead of using the `ref` that is returned by the `useSortable` hook to connect the sortable element.\n</ParamField>\n\n<ParamField path=\"handle\" type=\"Element | Ref<Element>\">\n  If you already have a reference to the drag handle element, you can pass it to the `handle` option instead of using the `handleRef` that is returned by the `useSortable` hook to connect the sortable handle element.\n</ParamField>\n\n<ParamField path=\"modifiers\" type=\"Modifier[]\">\n  An array of [modifiers](/extend/modifiers) that can be used to modify or restrict the behavior of the sortable element.\n</ParamField>\n\n<ParamField path=\"sensors\" type=\"Sensors[]\">\n  An array of [sensors](/extend/sensors) that can be bound to the sortable element to detect drag interactions.\n</ParamField>\n\n<ParamField path=\"target\" type=\"Element | Ref<Element>\">\n  If you already have a reference to the element you want to use as the droppable target for this sortable element, you can pass it to the `target` option instead of using the `targetRef` that is returned by the `useSortable` hook.\n</ParamField>\n\n<ParamField path=\"accepts\" type=\"string | number | Symbol | (type: string | number | Symbol) => boolean\">\n  Optionally supply a type of draggable element to only allow it to be dropped over certain droppable targets that [accept](#) this `type`.\n</ParamField>\n\n<ParamField path=\"collisionDetector\" type=\"(input: CollisionDetectorInput) => Collision | null\">\n  Optionally supply a [collision detector](/concepts/droppable#detecting-collisions) function can be used to detect collisions between the droppable element and draggable elements.\n</ParamField>\n\n<ParamField path=\"collisionPriority\" type=\"number\">\n  Optionally supply a number to set the collision priority of the droppable target of this sortable element. The higher the number, the higher the priority when detecting collisions. This can be useful if there are multiple droppable elements that overlap.\n</ParamField>\n\n<ParamField path=\"disabled\" type=\"boolean\">\n  Set to `true` to prevent the sortable element from being sortable.\n</ParamField>\n\n<ParamField path=\"plugins\" type=\"PluginDescriptor[]\">\n  An array of plugin descriptors for per-entity plugin configuration. Use `Plugin.configure()` to create descriptors. For example, `Feedback.configure({ feedback: 'clone' })`.\n</ParamField>\n\n<ParamField path=\"data\" type=\"{[key: string]: any}\">\n  The data argument is for advanced use-cases where you may need access to additional data about the sortable element in event handlers, modifiers, sensors or custom plugins.\n</ParamField>\n\n<ParamField path=\"effects\" type=\"() => Effect[]\">\n  <Info>This is an advanced feature and should not need to be used by most consumers.</Info>\n  You can supply a function that returns an array of reactive effects that can be set up and automatically cleaned up when the component invoking the `useSortable` hook element is unmounted.\n</ParamField>\n\n### Output\n\nThe `useSortable` hook returns an object containing the following properties:\n\n<ParamField path=\"ref\" type=\"Ref<Element>\">\n  A React ref that can be assigned to the element you want to connect as the draggable element and droppable target for this sortable instance.\n</ParamField>\n\n<ParamField path=\"targetRef\" type=\"Ref<Element>\">\n  A React ref that can be assigned to the element you want to use as the droppable target for this sortable element.\n</ParamField>\n\n<ParamField path=\"sourceRef\" type=\"Ref<Element>\">\n  A React ref that can be assigned to the element you want to use as the draggable source element for this sortable element.\n</ParamField>\n\n<ParamField path=\"handleRef\" type=\"Ref<Element>\">\n  A React ref that can be assigned to the element you want to use as the drag handle element for this sortable element.\n</ParamField>\n\n<ParamField path=\"isDropTarget\" type=\"boolean\">\n  A boolean value that indicates whether the sortable element is currently a drop target.\n</ParamField>\n\n<ParamField path=\"isDragSource\" type=\"boolean\">\n  A boolean value that indicates whether the sortable is the source of the drag operation that is in progress.\n</ParamField>\n\n<ResponseField name=\"isDragging\" type=\"boolean\">\n  A boolean value that indicates whether the sortable is currently being dragged.\n</ResponseField>\n\n<ResponseField name=\"isDropping\" type=\"boolean\">\n  A boolean value that indicates whether the sortable is being dropped. This can be used to style the sortable element differently during the drop animation.\n</ResponseField>\n"
  },
  {
    "path": "apps/docs/react/quickstart.mdx",
    "content": "---\ntitle: 'Quickstart'\ndescription: 'Start building drag and drop interfaces with React in minutes.'\nicon: 'rocket'\n---\n\nimport {Story} from '/snippets/story.mdx';\nimport Intro from '/snippets/quickstart/intro.mdx';\n\n<Intro />\n\n## Overview\n\nThe `@dnd-kit/react` package provides a set of React components and hooks that you can use to build drag and drop interfaces. It is thin React integration layer built on top of the [vanilla](/overview) library, so all of the same concepts are shared and can be used. You can refer to the vanilla documentation of these concepts, such as [plugins](/extend/plugins), [modifiers](/extend/modifiers), and [sensors](/extend/sensors).\n\n## Installation\nBefore getting started, make sure you install `@dnd-kit/react` in your project:\n\n<CodeGroup>\n  ```bash npm\n  npm install @dnd-kit/react\n  ```\n\n  ```bash yarn\n  yarn add @dnd-kit/react\n  ```\n\n  ```bash pnpm\n  pnpm add @dnd-kit/react\n  ```\n\n  ```bash bun\n  bun add @dnd-kit/react\n  ```\n</CodeGroup>\n\n## Making elements draggable\n\nLet's get started by creating draggable elements that can be dropped over droppable targets. To do so, we'll be using the `useDraggable` hook.\n\nThe `useDraggable` hook requires a unique `id`, and returns a `ref` that you can attach to any element to make it draggable.\n\n```jsx\nimport {useDraggable} from '@dnd-kit/react';\n\nfunction Draggable() {\n  const {ref} = useDraggable({\n    id: 'draggable',\n  });\n\n  return (\n    <button ref={ref}>\n      Draggable\n    </button>\n  );\n}\n```\n\n<Story id=\"react-draggable--example\" />\n\n## Creating droppable elements\n\nIn order for our draggable elements to have targets where they can be dropped, we need to create droppable elements.\nTo do so, we'll be using the `useDroppable` hook.\n\nLike the `useDraggable` hook, the `useDroppable` hook requires a unique `id`, and returns a `ref` that you can attach to any element to make it droppable.\n\nThis time, we'll accept the `id` argument as a prop of the `Droppable` component.\n\n```jsx\nimport {useDroppable} from '@dnd-kit/react';\n\nfunction Droppable({id, children}) {\n  const {ref} = useDroppable({\n    id,\n  });\n\n  return (\n    <div ref={ref} style={{width: 300, height: 300}}>\n      {children}\n    </div>\n  );\n}\n```\n\n## Putting all the pieces together\n\nNow that we have both draggable and droppable elements, we can put them together to create a simple drag and drop interaction.\n\nWe'll be using the `DragDropProvider` component to wrap our draggable and droppable elements.\nThis component handles the drag and drop interactions between our draggable and droppable elements and allow us listen to drag and drop events.\n\n<CodeGroup>\n```jsx App.js\nimport {DragDropProvider} from '@dnd-kit/react';\nimport Draggable from './Draggable';\nimport Droppable from './Droppable';\n\nfunction App() {\n  const [isDropped, setIsDropped] = useState(false);\n\n  return (\n    <DragDropProvider\n      onDragEnd={(event) => {\n        if (event.canceled) return;\n\n        const {target} = event.operation;\n        setIsDropped(target?.id === 'droppable');\n      }}\n    >\n      {!isDropped && <Draggable />}\n\n      <Droppable id=\"droppable\">\n        {isDropped && <Draggable />}\n      </Droppable>\n    </DragDropProvider>\n  );\n}\n```\n```jsx Draggable.js\nimport {useDraggable} from '@dnd-kit/react';\n\nexport function Draggable() {\n  const {ref} = useDraggable({\n    id: 'draggable',\n  });\n\n  return (\n    <button ref={ref}>\n      Draggable\n    </button>\n  );\n}\n```\n```jsx Droppable.js\nimport {useDroppable} from '@dnd-kit/react';\n\nfunction Droppable({id, children}) {\n  const {ref} = useDroppable({\n    id,\n  });\n\n  return (\n    <div ref={ref} style={{width: 300, height: 300}}>\n      {children}\n    </div>\n  );\n}\n```\n</CodeGroup>\n\n<div class=\"mt-8\">\n  <Story id=\"react-droppable--example\" height=\"390\" />\n</div>\n\nWe now have a simple drag and drop interaction set up. You can now build on top of this to create more complex interactions.\n\nFor example, you can render multiple draggable elements and droppable targets, and listen to drag and drop events to move elements around.\n\nLet's try adding more droppable targets to our example:\n\n```jsx App.js\nimport React, {useState} from 'react';\nimport {DndContext} from '@dnd-kit/core';\n\nimport {Droppable} from './Droppable';\nimport {Draggable} from './Draggable';\n\nfunction App() {\n  const targets = ['A', 'B', 'C'];\n  const [target, setTarget] = useState();\n  const draggable = (\n    <Draggable id=\"draggable\">Drag me</Draggable>\n  );\n\n  return (\n    <DragDropProvider\n      onDragEnd={(event) => {\n        if (event.canceled) return;\n\n        setTarget(event.operation.target?.id);\n      }}\n    >\n      {!target ? draggable : null}\n\n      {targets.map((id) => (\n        <Droppable key={id} id={id}>\n          {target === id ? draggable : `Droppable ${id}`}\n        </Droppable>\n      ))}\n    </DragDropProvider>\n  );\n};\n```\n\n<Story id=\"react-droppable-multiple-drop-targets--example\" height=\"740\" />\n\n## Next steps\n\nNow that you have a basic understanding of how to make elements draggable and droppable, you can explore the concepts covered in this quickstart guide in more detail:\n\n<CardGroup>\n  <Card title=\"DragDropProvider\" icon=\"sitemap\" href=\"/react/components/drag-drop-provider\">\n    Create drag and drop contexts for your draggable and droppable elements.\n  </Card>\n\n  <Card title=\"useDraggable\" icon=\"bullseye-pointer\" href=\"/react/hooks/use-draggable\">\n    Learn how to make elements draggable with the `useDraggable` hook.\n  </Card>\n\n  <Card title=\"useDroppable\" icon=\"expand\" href=\"/react/hooks/use-droppable\">\n    Learn how to create droppable targets with the `useDroppable` hook.\n  </Card>\n\n  <Card title=\"useSortable\" icon=\"layer-group\" href=\"/react/hooks/use-sortable\">\n    Learn how to create sortable elements with the `useSortable` hook.\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "apps/docs/sandpack.js",
    "content": "const importMap = {\n  imports: {\n    react: 'https://esm.sh/react@19.2.3',\n    'react/': 'https://esm.sh/react@19.2.3/',\n    'react-dom': 'https://esm.sh/react-dom@19.2.3',\n    'react-dom/': 'https://esm.sh/react-dom@19.2.3/',\n    '@codesandbox/sandpack-react':\n      'https://esm.sh/@codesandbox/sandpack-react@2.20.0?external=react,react-dom',\n  },\n};\n\nconst importMapScript = document.createElement('script');\nimportMapScript.type = 'importmap';\nimportMapScript.textContent = JSON.stringify(importMap);\n\ndocument.head.appendChild(importMapScript);\n\nconst script = document.createElement('script');\n\nconst code = `\nimport React from \"react\";\nimport {createRoot} from \"react-dom/client\";\nimport {Sandpack} from \"@codesandbox/sandpack-react\";\n\nconst theme = {\n  colors: {\n    surface1: '#0a0a0c',\n    surface2: 'transparent',\n    surface3: '#f7f7f710',\n    clickable: '#969696',\n    base: '#808080',\n    disabled: '#4D4D4D',\n    hover: '#596dff',\n    accent: '#596dff',\n    error: '#ffcdca',\n    errorSurface: '#811e18',\n  },\n  syntax: {\n    plain: '#d6deeb',\n    comment: {\n      color: '#999999',\n    },\n    keyword: {\n      color: '#c792ea',\n    },\n    tag: '#569cd6',\n    punctuation: '#d4d4d4',\n    definition: '#dcdcaa',\n    property: {\n      color: '#9cdcfe',\n    },\n    static: '#f78c6c',\n    string: '#ce9178',\n  },\n  font: {\n    body: '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\"',\n    mono: '\"Fira Mono\", \"DejaVu Sans Mono\", Menlo, Consolas, \"Liberation Mono\", Monaco, \"Lucida Console\", monospace',\n    size: '14px',\n    lineHeight: '20px',\n  },\n};\n\nclass SandpackElement extends HTMLElement {\n  connectedCallback() {\n    const root = createRoot(this);\n    let files = {};\n    const height = parseInt(this.getAttribute(\"height\"));\n    const showTabs = Boolean(this.getAttribute(\"showTabs\"));\n    const template = this.getAttribute(\"template\") || \"react\";\n    const isSolid = template === \"solid\";\n    const sharedDependencies = {\n      \"@dnd-kit/helpers\": \"beta\",\n    }\n    const templateDependencies = {\n      react: {\"@dnd-kit/react\": \"beta\"},\n      vue: {\"@dnd-kit/vue\": \"beta\"},\n      solid: {\"@dnd-kit/solid\": \"beta\"},\n      svelte: {\"@dnd-kit/svelte\": \"beta\"},\n    };\n    const dependencies = {\n      ...sharedDependencies,\n      ...(templateDependencies[template] || {\"@dnd-kit/dom\": \"beta\"}),\n    };\n\n    try {\n      files = JSON.parse(this.getAttribute(\"files\"));\n    } catch {}\n\n    if (isSolid) {\n      dependencies[\"solid-js\"] = \"^1.9.0\";\n      dependencies[\"babel-preset-solid\"] = \"latest\";\n\n      const solidInfraFiles = {\n        '/index.html': {\n          code: \\`<!DOCTYPE html>\n<html>\n<head>\n  <title>Solid Demo</title>\n  <meta charset=\"UTF-8\" />\n</head>\n<body>\n  <div id=\"app\"></div>\n  <script src=\"src/index.js\"><\\\\/script>\n</body>\n</html>\\`,\n          hidden: true,\n        },\n        '/index.ts': {\n          code: 'import \"./styles.css\";\\\\nimport {render} from \"solid-js/web\";\\\\nimport App from \"./App\";\\\\n\\\\nrender(App, document.getElementById(\"app\"));',\n          hidden: true,\n        },\n        '/.babelrc': {\n          code: JSON.stringify({presets: [\"babel-preset-solid\"]}, null, 2),\n          hidden: true,\n        },\n        '/tsconfig.json': {\n          code: JSON.stringify({compilerOptions: {jsx: \"preserve\", jsxImportSource: \"solid-js\", noEmit: true}}, null, 2),\n          hidden: true,\n        },\n      };\n      files = { ...solidInfraFiles, ...files };\n    }\n\n    const sandpackComponent = React.createElement(Sandpack, {\n      files,\n      template: isSolid ? \"vanilla-ts\" : template,\n      theme,\n      options: {\n        showTabs,\n        resizablePanels: false,\n        editorHeight: height || undefined,\n      },\n      customSetup: { dependencies },\n    }, null);\n    root.render(sandpackComponent);\n  }\n}\n\ncustomElements.define(\"code-sandbox\", SandpackElement);\n`;\n\nscript.type = 'module';\nscript.textContent = code;\n\ndocument.head.appendChild(script);\n"
  },
  {
    "path": "apps/docs/snippets/code.mdx",
    "content": "export const draggableStyles = `\nbody {\n  padding: 1em;\n  font-family: system-ui, sans-serif;\n  -webkit-font-smoothing: antialiased;\n}\n\n.btn {\n  display: flex;\n  width: min-content;\n  height: min-content;\n  align-items: center;\n  gap: 6px;\n  font-size: 20px;\n  font-weight: 900;\n  cursor: grab;\n  padding: 14px 18px;\n  background: #000;\n  color: #FFF;\n  border-radius: 10px;\n  border: none;\n  transition: transform 0.25s ease, box-shadow 0.2s ease;\n}\n\n.btn::before {\n  content: '';\n  display: inline-block;\n  width: 34px;\n  height: 34px;\n  background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='43' height='43' viewBox='0 0 43 43' fill='none'%3E%3Cpath d='M4.55229 25.6017L20.5499 20.8985C21.4951 20.6173 22.3778 21.5001 22.1044 22.4532L17.402 38.4532C17.0817 39.5392 15.5897 39.672 15.082 38.6563L12.8401 34.1798C12.7855 34.0782 12.723 33.9767 12.6449 33.8907L5.77086 40.7657C4.79444 41.7423 3.20873 41.7423 2.23231 40.7657C1.2559 39.7892 1.2559 38.2032 2.23231 37.2267L9.10631 30.3517C9.02038 30.2735 8.92665 30.2032 8.81729 30.1563L4.34919 27.922C3.33372 27.4142 3.46651 25.922 4.55229 25.6017Z' fill='white'/%3E%3Cpath transform-origin='25 50%25' d='M22.4324 30.2031L21.3153 34H21.5028C28.408 34 34.001 28.4062 34.001 21.5C34.001 14.5938 28.408 9 21.5028 9C14.5976 9 9.00464 14.5938 9.00464 21.5V21.6875L12.801 20.5703C13.2696 16.1719 16.9878 12.75 21.5028 12.75C26.338 12.75 30.2515 16.6641 30.2515 21.5C30.2515 26.0156 26.8302 29.7344 22.4324 30.2031Z' fill='white' fill-opacity='0.7'%3E%3Canimate attributeName='fill-opacity' begin='0' values='0;0.7;0.7;0' keyTimes='0; 0.2; 0.85; 1' dur='4s' repeatCount='indefinite'/%3E%3CanimateTransform attributeName='transform' type='scale' values='0 0; 1 1; 1 1; 0 0' keyTimes='0; 0.1; 0.9; 1' begin='0s' dur='4s' repeatCount='indefinite'/%3E%3C/path%3E%3Cpath transform-origin='25 50%25' d='M37.7505 21.5C37.7505 30.4766 30.4782 37.75 21.5029 37.75V37.7422C21.0733 37.7422 20.6515 37.7266 20.2297 37.6953L19.1517 41.3594C19.925 41.4531 20.7062 41.5 21.5029 41.5C32.5482 41.5 41.5 32.5469 41.5 21.5C41.5 10.4531 32.5482 1.5 21.5029 1.5C10.4577 1.5 1.50586 10.4531 1.50586 21.5C1.50586 22.2969 1.55273 23.0781 1.64646 23.8516L5.30218 22.7734C5.27093 22.3516 5.25531 21.9297 5.25531 21.5C5.25531 12.5234 12.5277 5.25 21.5029 5.25C30.4782 5.25 37.7505 12.5234 37.7505 21.5Z' fill='white' fill-opacity='0.4'%3E%3Canimate attributeName='fill-opacity' begin='0.1s' values='0;0.4;0.4;0' keyTimes='0; 0.2; 0.85; 1' dur='4s' repeatCount='indefinite'/%3E%3CanimateTransform attributeName='transform' type='scale' values='0 0; 1 1; 1 1; 0 0' keyTimes='0; 0.1; 0.9; 1' begin='0.1s' dur='4s' repeatCount='indefinite'/%3E%3C/path%3E%3Cdiv xmlns='' style='all: initial !important;'/%3E%3C/svg%3E\");\n  background-size: contain;\n  background-repeat: no-repeat;\n}\n\n.btn[aria-grabbed=\"true\"] {\n  transform: scale(1.025);\n  box-shadow: inset 0px 0px 1px rgba(0,0,0,0.5), -1px 0 15px 0 rgba(34, 33, 81, 0.01), 0px 15px 15px 0 rgba(34, 33, 81, 0.25)\n}\n`.trim()\n\nexport const droppableStyles = `\n#app {\n  display: grid;\n  grid-template-columns: 2fr 1fr;\n  grid-gap: 20px;\n  align-items: center;\n  max-width: 700px;\n  margin: 0 auto;\n}\n\n.droppable {\n  display: flex;\n  grid-column: 2;\n  flex-direction: column;\n  gap: 20px;\n  align-items: center;\n  justify-content: flex-start;\n  position: relative;\n  padding-top: 80px;\n  text-align: center;\n  border-radius: 10px;\n  max-width: 340px;\n  max-height: 340px;\n  flex-grow: 1;\n  min-width: 300px;\n  aspect-ratio: 1 / 1;\n  box-sizing: border-box;\n  background-color: #fff;\n  box-shadow: inset rgba(0, 0, 0, 0.1) 0 0 0 2px,\n    rgba(0, 0, 0, 0.06) 20px 14px 24px;\n  transition: box-shadow 250ms ease;\n}\n\n.droppable::after {\n  content: url(\"data:image/svg+xml,%3Csvg width='200' viewBox='0 0 279 67' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M12 0H55C61.6274 0 67 5.37258 67 12V55C67 61.6274 61.6274 67 55 67H12C5.37258 67 0 61.6274 0 55V12C0 5.37258 5.37258 0 12 0Z' fill='%237F8C96'/%3E%3Cpath transform-origin='35 35' d='M19.8652 44.5547L12.494 52.1379V44.6787H8.33374V59.2396H22.8946V55.0794H15.4354L22.9863 47.5285L19.8652 44.5547Z' fill='white'%3E%3Canimate attributeName='fill-opacity' begin='0' values='0;1;1;0' keyTimes='0; 0.2; 0.85; 1' dur='3s' repeatCount='indefinite'/%3E%3CanimateTransform attributeName='transform' type='scale' values='0 0; 1 1; 1 1; 1 1' keyTimes='0; 0.15; 0.9; 1' begin='0s' dur='3s' repeatCount='indefinite' /%3E%3C/path%3E%3Cpath transform-origin='35 35' d='M47.7082 44.5547L44.5872 47.5285L52.1381 55.0794H44.6789V59.2396H59.2397V44.6787H55.0795V52.1379L47.7082 44.5547Z' fill='white'%3E%3Canimate attributeName='fill-opacity' begin='0' values='0;1;1;0' keyTimes='0; 0.2; 0.85; 1' dur='3s' repeatCount='indefinite'/%3E%3CanimateTransform attributeName='transform' type='scale' values='0 0; 1 1; 1 1; 1 1' keyTimes='0; 0.15; 0.9; 1' begin='0s' dur='3s' repeatCount='indefinite' /%3E%3C/path%3E%3Cpath transform-origin='35 35' d='M19.8652 22.9862L22.9863 20.0124L15.4354 12.4615H22.8946V8.30127H8.33374V22.8621H12.494V15.403L19.8652 22.9862Z' fill='white'%3E%3Canimate attributeName='fill-opacity' begin='0' values='0;1;1;0' keyTimes='0; 0.2; 0.85; 1' dur='3s' repeatCount='indefinite'/%3E%3CanimateTransform attributeName='transform' type='scale' values='0 0; 1 1; 1 1; 1 1' keyTimes='0; 0.15; 0.9; 1' begin='0s' dur='3s' repeatCount='indefinite' /%3E%3C/path%3E%3Cpath transform-origin='35 35' d='M47.7082 22.9862L55.0795 15.403V22.8621H59.2397V8.30127H44.6789V12.4615H52.1381L44.5872 20.0124L47.7082 22.9862Z' fill='white'%3E%3Canimate attributeName='fill-opacity' begin='0' values='0;1;1;0' keyTimes='0; 0.2; 0.85; 1' dur='3s' repeatCount='indefinite'/%3E%3CanimateTransform attributeName='transform' type='scale' values='0 0; 1 1; 1 1; 1 1' keyTimes='0; 0.15; 0.9; 1' begin='0s' dur='3s' repeatCount='indefinite' /%3E%3C/path%3E%3Cpath d='M277.629 33.6321C277.629 34.2081 277.593 34.8081 277.521 35.4321H263.589C263.685 36.6801 264.081 37.6401 264.777 38.3121C265.497 38.9601 266.373 39.2841 267.405 39.2841C268.941 39.2841 270.009 38.6361 270.609 37.3401H277.161C276.825 38.6601 276.213 39.8481 275.325 40.9041C274.461 41.9601 273.369 42.7881 272.049 43.3881C270.729 43.9881 269.253 44.2881 267.621 44.2881C265.653 44.2881 263.901 43.8681 262.365 43.0281C260.829 42.1881 259.629 40.9881 258.765 39.4281C257.901 37.8681 257.469 36.0441 257.469 33.9561C257.469 31.8681 257.889 30.0441 258.729 28.4841C259.593 26.9241 260.793 25.7241 262.329 24.8841C263.865 24.0441 265.629 23.6241 267.621 23.6241C269.565 23.6241 271.293 24.0321 272.805 24.8481C274.317 25.6641 275.493 26.8281 276.333 28.3401C277.197 29.8521 277.629 31.6161 277.629 33.6321ZM271.329 32.0121C271.329 30.9561 270.969 30.1161 270.249 29.4921C269.529 28.8681 268.629 28.5561 267.549 28.5561C266.517 28.5561 265.641 28.8561 264.921 29.4561C264.225 30.0561 263.793 30.9081 263.625 32.0121H271.329Z' fill='%237F8C96'/%3E%3Cpath d='M254.232 16.3601V44.0001H248.076V16.3601H254.232Z' fill='%237F8C96'/%3E%3Cpath d='M229.798 26.7561C230.374 25.8201 231.202 25.0641 232.282 24.4881C233.362 23.9121 234.598 23.6241 235.99 23.6241C237.646 23.6241 239.146 24.0441 240.49 24.8841C241.834 25.7241 242.89 26.9241 243.658 28.4841C244.45 30.0441 244.846 31.8561 244.846 33.9201C244.846 35.9841 244.45 37.8081 243.658 39.3921C242.89 40.9521 241.834 42.1641 240.49 43.0281C239.146 43.8681 237.646 44.2881 235.99 44.2881C234.574 44.2881 233.338 44.0121 232.282 43.4601C231.226 42.8841 230.398 42.1281 229.798 41.1921V44.0001H223.642V16.3601H229.798V26.7561ZM238.582 33.9201C238.582 32.3841 238.15 31.1841 237.286 30.3201C236.446 29.4321 235.402 28.9881 234.154 28.9881C232.93 28.9881 231.886 29.4321 231.022 30.3201C230.182 31.2081 229.762 32.4201 229.762 33.9561C229.762 35.4921 230.182 36.7041 231.022 37.5921C231.886 38.4801 232.93 38.9241 234.154 38.9241C235.378 38.9241 236.422 38.4801 237.286 37.5921C238.15 36.6801 238.582 35.4561 238.582 33.9201Z' fill='%237F8C96'/%3E%3Cpath d='M197.985 33.9201C197.985 31.8561 198.369 30.0441 199.137 28.4841C199.929 26.9241 200.997 25.7241 202.341 24.8841C203.685 24.0441 205.185 23.6241 206.841 23.6241C208.257 23.6241 209.493 23.9121 210.549 24.4881C211.629 25.0641 212.457 25.8201 213.033 26.7561V23.9121H219.189V44.0001H213.033V41.1561C212.433 42.0921 211.593 42.8481 210.513 43.4241C209.457 44.0001 208.221 44.2881 206.805 44.2881C205.173 44.2881 203.685 43.8681 202.341 43.0281C200.997 42.1641 199.929 40.9521 199.137 39.3921C198.369 37.8081 197.985 35.9841 197.985 33.9201ZM213.033 33.9561C213.033 32.4201 212.601 31.2081 211.737 30.3201C210.897 29.4321 209.865 28.9881 208.641 28.9881C207.417 28.9881 206.373 29.4321 205.509 30.3201C204.669 31.1841 204.249 32.3841 204.249 33.9201C204.249 35.4561 204.669 36.6801 205.509 37.5921C206.373 38.4801 207.417 38.9241 208.641 38.9241C209.865 38.9241 210.897 38.4801 211.737 37.5921C212.601 36.7041 213.033 35.4921 213.033 33.9561Z' fill='%237F8C96'/%3E%3Cpath d='M180.931 26.7561C181.531 25.8201 182.359 25.0641 183.415 24.4881C184.471 23.9121 185.707 23.6241 187.123 23.6241C188.779 23.6241 190.279 24.0441 191.623 24.8841C192.967 25.7241 194.023 26.9241 194.791 28.4841C195.583 30.0441 195.979 31.8561 195.979 33.9201C195.979 35.9841 195.583 37.8081 194.791 39.3921C194.023 40.9521 192.967 42.1641 191.623 43.0281C190.279 43.8681 188.779 44.2881 187.123 44.2881C185.731 44.2881 184.495 44.0001 183.415 43.4241C182.359 42.8481 181.531 42.1041 180.931 41.1921V53.5761H174.775V23.9121H180.931V26.7561ZM189.715 33.9201C189.715 32.3841 189.283 31.1841 188.419 30.3201C187.579 29.4321 186.535 28.9881 185.287 28.9881C184.063 28.9881 183.019 29.4321 182.155 30.3201C181.315 31.2081 180.895 32.4201 180.895 33.9561C180.895 35.4921 181.315 36.7041 182.155 37.5921C183.019 38.4801 184.063 38.9241 185.287 38.9241C186.511 38.9241 187.555 38.4801 188.419 37.5921C189.283 36.6801 189.715 35.4561 189.715 33.9201Z' fill='%237F8C96'/%3E%3Cpath d='M156.497 26.7561C157.097 25.8201 157.925 25.0641 158.981 24.4881C160.037 23.9121 161.273 23.6241 162.689 23.6241C164.345 23.6241 165.845 24.0441 167.189 24.8841C168.533 25.7241 169.589 26.9241 170.357 28.4841C171.149 30.0441 171.545 31.8561 171.545 33.9201C171.545 35.9841 171.149 37.8081 170.357 39.3921C169.589 40.9521 168.533 42.1641 167.189 43.0281C165.845 43.8681 164.345 44.2881 162.689 44.2881C161.297 44.2881 160.061 44.0001 158.981 43.4241C157.925 42.8481 157.097 42.1041 156.497 41.1921V53.5761H150.341V23.9121H156.497V26.7561ZM165.281 33.9201C165.281 32.3841 164.849 31.1841 163.985 30.3201C163.145 29.4321 162.101 28.9881 160.853 28.9881C159.629 28.9881 158.585 29.4321 157.721 30.3201C156.881 31.2081 156.461 32.4201 156.461 33.9561C156.461 35.4921 156.881 36.7041 157.721 37.5921C158.585 38.4801 159.629 38.9241 160.853 38.9241C162.077 38.9241 163.121 38.4801 163.985 37.5921C164.849 36.6801 165.281 35.4561 165.281 33.9201Z' fill='%237F8C96'/%3E%3Cpath d='M136.564 44.2881C134.596 44.2881 132.82 43.8681 131.236 43.0281C129.676 42.1881 128.44 40.9881 127.528 39.4281C126.64 37.8681 126.196 36.0441 126.196 33.9561C126.196 31.8921 126.652 30.0801 127.564 28.5201C128.476 26.9361 129.724 25.7241 131.308 24.8841C132.892 24.0441 134.668 23.6241 136.636 23.6241C138.604 23.6241 140.38 24.0441 141.964 24.8841C143.548 25.7241 144.796 26.9361 145.708 28.5201C146.62 30.0801 147.076 31.8921 147.076 33.9561C147.076 36.0201 146.608 37.8441 145.672 39.4281C144.76 40.9881 143.5 42.1881 141.892 43.0281C140.308 43.8681 138.532 44.2881 136.564 44.2881ZM136.564 38.9601C137.74 38.9601 138.736 38.5281 139.552 37.6641C140.392 36.8001 140.812 35.5641 140.812 33.9561C140.812 32.3481 140.404 31.1121 139.588 30.2481C138.796 29.3841 137.812 28.9521 136.636 28.9521C135.436 28.9521 134.44 29.3841 133.648 30.2481C132.856 31.0881 132.46 32.3241 132.46 33.9561C132.46 35.5641 132.844 36.8001 133.612 37.6641C134.404 38.5281 135.388 38.9601 136.564 38.9601Z' fill='%237F8C96'/%3E%3Cpath d='M118.177 27.2601C118.897 26.1561 119.797 25.2921 120.877 24.6681C121.957 24.0201 123.157 23.6961 124.477 23.6961V30.2121H122.785C121.249 30.2121 120.097 30.5481 119.329 31.2201C118.561 31.8681 118.177 33.0201 118.177 34.6761V44.0001H112.021V23.9121H118.177V27.2601Z' fill='%237F8C96'/%3E%3Cpath d='M86.3635 33.9201C86.3635 31.8561 86.7475 30.0441 87.5155 28.4841C88.3075 26.9241 89.3755 25.7241 90.7195 24.8841C92.0635 24.0441 93.5635 23.6241 95.2195 23.6241C96.5395 23.6241 97.7395 23.9001 98.8195 24.4521C99.9235 25.0041 100.788 25.7481 101.412 26.6841V16.3601H107.568V44.0001H101.412V41.1201C100.836 42.0801 100.008 42.8481 98.9275 43.4241C97.8715 44.0001 96.6355 44.2881 95.2195 44.2881C93.5635 44.2881 92.0635 43.8681 90.7195 43.0281C89.3755 42.1641 88.3075 40.9521 87.5155 39.3921C86.7475 37.8081 86.3635 35.9841 86.3635 33.9201ZM101.412 33.9561C101.412 32.4201 100.98 31.2081 100.116 30.3201C99.2755 29.4321 98.2435 28.9881 97.0195 28.9881C95.7955 28.9881 94.7515 29.4321 93.8875 30.3201C93.0475 31.1841 92.6275 32.3841 92.6275 33.9201C92.6275 35.4561 93.0475 36.6801 93.8875 37.5921C94.7515 38.4801 95.7955 38.9241 97.0195 38.9241C98.2435 38.9241 99.2755 38.4801 100.116 37.5921C100.98 36.7041 101.412 35.4921 101.412 33.9561Z' fill='%237F8C96'/%3E%3C/svg%3E%0A\");\n  position: absolute;\n  left: 50%;\n  top: 50%;\n  transform: translate3d(-50%, -50%, 0);\n  opacity: 0.3;\n  transition: opacity 300ms ease, transform 200ms ease;\n  user-select: none;\n  pointer-events: none;\n}\n\n.droppable.active {\n  background-color: #f7f9fb;\n  box-shadow: inset #1eb99d 0 0 0 2px, rgba(0, 0, 0, 0.12) 20px 14px 24px;\n}\n\n.droppable.active:not(:empty) {\n  box-shadow: inset #1eb99d 0 0 0 2px, rgba(0, 0, 0, 0.1) 20px 14px 24px;\n}\n\n.droppable.active::after {\n  opacity: 0.5;\n}\n\n.droppable:not(:empty)::after {\n  opacity: 0.2;\n  transform: translate3d(-50%, 100%, 0) scale(0.8);\n}\n`.trim();\n\nexport const sortableStyles = `\nbody {\n  padding: 1em;\n  font-size: 20px;\n  font-family: system-ui, sans-serif;\n  -webkit-font-smoothing: antialiased;\n  line-height: 1.5;\n}\n\n.list {\n  display: flex;\n  flex-wrap: wrap;\n  gap: 10px;\n  padding: 0;\n  margin: 0;\n  list-style: none;\n}\n\n.item {\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  box-sizing: border-box;\n  padding: 10px 20px;\n  border: none;\n  gap: 10px;\n  background-color: rgb(255, 255, 255);\n  border-radius: 6px;\n  font-size: 14px !important;\n  color: #555;\n  outline: none;\n  min-height: 50px;\n  box-shadow: inset 0 0 1px rgba(0,0,0,0.4), 0 0 0 1px rgba(63, 63, 68, 0.05), 0 1px 2px 0 rgba(34, 33, 81, 0.05);\n  font-family: var(--font-family);\n  width: calc(25% - 10px);\n  min-width: 150px;\n  max-width: 300px;\n  white-space: nowrap;\n  transition: transform 0.3s ease, box-shadow 0.3s ease;\n  cursor: grab;\n}\n\n.item[aria-grabbed=\"true\"] {\n  transform: scale(1.025);\n  box-shadow: inset 0px 0px 1px rgba(0,0,0,0.5), -1px 0 15px 0 rgba(34, 33, 81, 0.01), 0px 15px 15px 0 rgba(34, 33, 81, 0.25)\n}\n`.trim()\n"
  },
  {
    "path": "apps/docs/snippets/quickstart/intro.mdx",
    "content": "<Card title=\"You will learn\">\n  <div class=\"info\">\n    1. How to make elements draggable\n    2. How to set up droppable targets\n    3. How to listen to drag and drop events to move elements\n  </div>\n</Card>\n"
  },
  {
    "path": "apps/docs/snippets/sandbox.mdx",
    "content": "export const CodeSandbox = ({ files, height, hero, previewHeight, showTabs, template }) => {\n  const Element = 'code-sandbox';\n\n  return (\n    <Element\n      class={`not-prose${hero ? ' hero' : ''}`}\n      files={JSON.stringify(files)}\n      height={height}\n      style={previewHeight ? {'--preview-height': `${previewHeight}px`} : undefined}\n      showTabs={showTabs}\n      template={template}\n    />\n  );\n};\n"
  },
  {
    "path": "apps/docs/snippets/story.mdx",
    "content": "export const Story = ({ id, framework = \"react\", width = \"100%\", height = \"250\", hero = false }) => {\n  const BRANCH = 'experimental';\n  const STORYBOOKS = {\n    react: {\n      localPort: 6006,\n      productionHost: '5fc05e08a4a65d0021ae0bf2',\n    },\n    vue: {\n      localPort: 6008,\n      productionHost: '6989440ed560d70abcd6bcc7',\n    },\n    vanilla: {\n      localPort: 6007,\n      productionHost: '69892d294eb9040f0d29aa81',\n    },\n    solid: {\n      localPort: 6009,\n      productionHost: '698944444eb9040f0d2a0217',\n    },\n    svelte: {\n      localPort: 6010,\n      productionHost: '69910d2a631cb57638616dcd',\n    },\n  };\n  const config = STORYBOOKS[framework] ?? STORYBOOKS.react;\n  const host = typeof window !== 'undefined' && window.location?.hostname === 'localhost' ? `//localhost:${config.localPort}` : `https://${BRANCH}--${config.productionHost}.chromatic.com`;\n  const dark = typeof document !== 'undefined' && document.documentElement.classList.contains('dark');\n\n  return (\n    <Frame>\n      <iframe src={`${host}/iframe.html?args=&id=${id}&viewMode=story&dark=${dark}&hero=${hero}`} width={width} height={height} />\n    </Frame>\n  );\n};\n"
  },
  {
    "path": "apps/docs/solid/components/drag-drop-provider.mdx",
    "content": "---\ntitle: 'DragDropProvider'\ndescription: 'The DragDropProvider component creates and manages a DragDropManager instance for your SolidJS application.'\nicon: 'sitemap'\n---\n\n## Overview\n\nThe `DragDropProvider` component is the root component for drag and drop interactions. It creates a [DragDropManager](/concepts/drag-drop-manager) instance and makes it available to all descendant components via Solid's context API.\n\n## Usage\n\n```tsx\nimport {DragDropProvider} from '@dnd-kit/solid';\n\nfunction App() {\n  return (\n    <DragDropProvider\n      onDragEnd={(event) => {\n        // Handle drop\n      }}\n    >\n      {/* Your draggable and droppable elements */}\n    </DragDropProvider>\n  );\n}\n```\n\n## Props\n\n<ParamField path=\"manager\" type=\"DragDropManager\" optional>\n  An optional externally created `DragDropManager` instance. If not provided, one will be created automatically.\n</ParamField>\n\n<ParamField path=\"plugins\" type=\"Plugin[] | (defaults: Plugin[]) => Plugin[]\" optional>\n  Plugins to use. Defaults to the default preset. Pass an array to replace defaults, or a function to extend them.\n\n  ```tsx\n  // Add a plugin alongside defaults\n  plugins={(defaults) => [...defaults, MyPlugin]}\n\n  // Replace defaults entirely\n  plugins={[MyPlugin]}\n  ```\n</ParamField>\n\n<ParamField path=\"sensors\" type=\"Sensor[] | (defaults: Sensor[]) => Sensor[]\" optional>\n  Sensors to use. Defaults to `PointerSensor` and `KeyboardSensor`. Pass an array to replace defaults, or a function to extend them.\n</ParamField>\n\n<ParamField path=\"modifiers\" type=\"Modifier[] | (defaults: Modifier[]) => Modifier[]\" optional>\n  Modifiers to apply to drag operations. Pass an array to replace defaults, or a function to extend them.\n</ParamField>\n\n## Event Props\n\n| Prop | Description |\n|------|-------------|\n| `onBeforeDragStart` | Called before a drag operation begins. |\n| `onDragStart` | Called when a drag operation starts. |\n| `onDragMove` | Called when the dragged element moves. |\n| `onDragOver` | Called when the dragged element moves over a droppable target. Call `event.preventDefault()` to prevent the default behavior of plugins that respond to this event. |\n| `onDragEnd` | Called when a drag operation ends (dropped or canceled). |\n| `onCollision` | Called when collisions are detected. |\n"
  },
  {
    "path": "apps/docs/solid/components/drag-overlay.mdx",
    "content": "---\ntitle: 'DragOverlay'\ndescription: 'Render a custom element as visual feedback during drag operations.'\nicon: 'clone'\n---\n\n## Overview\n\nThe `DragOverlay` component renders a custom overlay element while a drag operation is in progress. This allows you to display a completely different element than the one being dragged, which is useful for rendering a styled clone, a preview, or a simplified representation of the dragged element.\n\n<img src=\"/images/draggable/drag-overlay.png\" />\n\n## Usage\n\nImport and place the `DragOverlay` component inside a [`DragDropProvider`](/solid/components/drag-drop-provider). Its children will only be rendered when a drag operation is active.\n\n```tsx\nimport {DragDropProvider, DragOverlay, useDraggable} from '@dnd-kit/solid';\n\nfunction Draggable() {\n  const {ref} = useDraggable({id: 'draggable'});\n\n  return (\n    <>\n      <button ref={ref}>Draggable</button>\n      <DragOverlay>\n        <div>I will be rendered while dragging...</div>\n      </DragOverlay>\n    </>\n  );\n}\n```\n\n<Warning>\n  You should only render the `DragOverlay` component once per [DragDropProvider](/solid/components/drag-drop-provider) component.\n</Warning>\n\n### Rendering based on the drag source\n\nYou can pass a function as a child to the `DragOverlay` component, which will receive the `source` as an argument. This is useful for rendering different content depending on which element is being dragged.\n\n```tsx\nimport {DragDropProvider, DragOverlay} from '@dnd-kit/solid';\n\nfunction App() {\n  return (\n    <DragDropProvider>\n      <Draggable id=\"foo\" />\n      <Draggable id=\"bar\" />\n      <DragOverlay>\n        {source => (\n          <div>Dragging {source.id}</div>\n        )}\n      </DragOverlay>\n    </DragDropProvider>\n  );\n}\n```\n\n### Customizing the drop animation\n\nBy default, when a drag operation ends, the overlay animates back to the position of the source element. You can customize or disable this animation using the `dropAnimation` prop.\n\n```tsx\n{/* Disable the drop animation */}\n<DragOverlay dropAnimation={null}>\n  <div>No animation on drop</div>\n</DragOverlay>\n\n{/* Customize the animation timing */}\n<DragOverlay dropAnimation={{ duration: 150, easing: 'ease-out' }}>\n  <div>Fast drop animation</div>\n</DragOverlay>\n```\n\n## Props\n\n<ParamField path=\"children\" type=\"JSX.Element | ((source: Draggable) => JSX.Element)\">\n  The content to render as the drag overlay. Only rendered when a drag operation is in progress. Can be a JSX element or a function that receives the drag `source` as an argument.\n</ParamField>\n\n<ParamField path=\"tag\" type=\"ValidComponent\" default=\"'div'\">\n  The component or HTML tag to render as the overlay wrapper element.\n</ParamField>\n\n<ParamField path=\"disabled\" type=\"boolean | ((source: Draggable | null) => boolean)\">\n  Whether the drag overlay is disabled. Can be a boolean or a function that receives the current drag source.\n</ParamField>\n\n<ParamField path=\"dropAnimation\" type=\"DropAnimation | null\" optional>\n  Customize or disable the drop animation that plays when a drag operation ends.\n\n  - `undefined` – use the default animation (`250ms` ease)\n  - `null` – disable the drop animation entirely\n  - `{duration, easing}` – customize the animation timing\n  - `(context) => Promise<void> | void` – provide a fully custom animation function\n</ParamField>\n\n<ParamField path=\"class\" type=\"string\" optional>\n  CSS class name for the overlay wrapper element.\n</ParamField>\n\n<ParamField path=\"style\" type=\"JSX.CSSProperties\" optional>\n  Inline styles for the overlay wrapper element.\n</ParamField>\n"
  },
  {
    "path": "apps/docs/solid/hooks/use-draggable.mdx",
    "content": "---\ntitle: 'useDraggable'\ndescription: 'Make elements draggable with the useDraggable hook.'\nicon: 'bullseye-pointer'\n---\n\nimport {CodeSandbox} from '/snippets/sandbox.mdx';\nimport {draggableStyles} from '/snippets/code.mdx';\n\n<CodeSandbox template=\"solid\" files={{\n  'App.tsx': {code: app, active: true},\n  'styles.css': {code: draggableStyles, hidden: true},\n}} height={220} previewHeight={200} hero />\n\n## Usage\n\nThe `useDraggable` hook requires a unique `id` and returns a `ref` callback and reactive getters for drag state.\n\n```tsx\nimport {useDraggable} from '@dnd-kit/solid';\n\nfunction Draggable() {\n  const {ref, isDragging} = useDraggable({id: 'my-draggable'});\n\n  return (\n    <button ref={ref} data-dragging={isDragging()}>\n      Drag me\n    </button>\n  );\n}\n```\n\n## Input\n\n<ParamField path=\"id\" type=\"UniqueIdentifier\" required>\n  A unique identifier for this draggable instance. Use getter syntax (`get id() { return props.id }`) for reactive values.\n</ParamField>\n\n<ParamField path=\"handle\" type=\"Element\" optional>\n  A handle element. When set, only this element activates dragging. Use the `handleRef` callback to set it.\n</ParamField>\n\n<ParamField path=\"disabled\" type=\"boolean\" optional>\n  Whether the draggable is disabled.\n</ParamField>\n\n<ParamField path=\"plugins\" type=\"PluginDescriptor[]\" optional>\n  An array of plugin descriptors for per-entity plugin configuration. Use `Plugin.configure()` to create descriptors. For example, `Feedback.configure({ feedback: 'clone' })`.\n</ParamField>\n\n<ParamField path=\"modifiers\" type=\"Modifier[]\" optional>\n  Modifiers to apply to this draggable instance.\n</ParamField>\n\n<ParamField path=\"sensors\" type=\"Sensor[]\" optional>\n  Sensors to use for this draggable instance.\n</ParamField>\n\n<ParamField path=\"data\" type=\"Data\" optional>\n  Custom data to attach to this draggable instance.\n</ParamField>\n\n## Output\n\n<ResponseField name=\"ref\" type=\"(element: Element) => void\">\n  A callback ref to attach to the draggable element.\n</ResponseField>\n\n<ResponseField name=\"handleRef\" type=\"(element: Element) => void\">\n  A callback ref to attach to a drag handle element.\n</ResponseField>\n\n<ResponseField name=\"isDragging\" type=\"() => boolean\" note=\"accessor\">\n  Whether this element is currently being dragged. Call as `isDragging()` in JSX.\n</ResponseField>\n\n<ResponseField name=\"isDropping\" type=\"() => boolean\" note=\"accessor\">\n  Whether this element is in the process of being dropped. Call as `isDropping()` in JSX.\n</ResponseField>\n\n<ResponseField name=\"isDragSource\" type=\"() => boolean\" note=\"accessor\">\n  Whether this element is the source of the current drag operation. Call as `isDragSource()` in JSX.\n</ResponseField>\n\n<ResponseField name=\"draggable\" type=\"Draggable\">\n  The underlying `Draggable` instance.\n</ResponseField>\n\n## Guides\n\n### Rendering a drag overlay\n\nYou can render a completely different element while the draggable element is being dragged by using the [`<DragOverlay>`](/solid/components/drag-overlay) component.\n\n<img src=\"/images/draggable/drag-overlay.png\" />\n\n```tsx\nimport {DragDropProvider, DragOverlay, useDraggable} from '@dnd-kit/solid';\n\nfunction Draggable() {\n  const {ref} = useDraggable({id: 'draggable'});\n\n  return (\n    <>\n      <button ref={ref}>Draggable</button>\n      <DragOverlay>\n        <div>I will be rendered while dragging...</div>\n      </DragOverlay>\n    </>\n  );\n}\n```\n\nThe `<DragOverlay>` component will only render its children when a drag operation is in progress. This can be useful for rendering a completely different element while the draggable element is being dragged.\n\n<Warning>\n  You should only render the `<DragOverlay>` component once per [DragDropProvider](/solid/components/drag-drop-provider) component.\n</Warning>\n\nTo render different content depending on which element is being dragged, pass a function as a child that receives the drag `source`:\n\n```tsx\nimport {DragDropProvider, DragOverlay} from '@dnd-kit/solid';\n\nfunction App() {\n  return (\n    <DragDropProvider>\n      <Draggable id=\"foo\" />\n      <Draggable id=\"bar\" />\n      <DragOverlay>\n        {source => (\n          <div>Dragging {source.id}</div>\n        )}\n      </DragOverlay>\n    </DragDropProvider>\n  );\n}\n```\n\nexport const app = `\nimport {DragDropProvider, useDraggable} from '@dnd-kit/solid';\nimport './styles.css';\n\nfunction Draggable() {\n  const {ref} = useDraggable({id: 'draggable'});\n\n  return <button ref={ref} class=\"btn\">draggable</button>;\n}\n\nexport default function App() {\n  return (\n    <DragDropProvider>\n      <Draggable />\n    </DragDropProvider>\n  );\n}\n`.trim();\n"
  },
  {
    "path": "apps/docs/solid/hooks/use-droppable.mdx",
    "content": "---\ntitle: 'useDroppable'\ndescription: 'Create droppable targets with the useDroppable hook.'\nicon: 'expand'\n---\n\nimport {CodeSandbox} from '/snippets/sandbox.mdx';\nimport {draggableStyles, droppableStyles} from '/snippets/code.mdx';\n\n<CodeSandbox template=\"solid\" files={{\n  'App.tsx': {code: app, hidden: true},\n  'Droppable.tsx': {code, active: true},\n  'styles.css': {code: draggableStyles + '\\n\\n' + droppableStyles + '\\n\\n' + containerStyles, hidden: true},\n}} height={350} previewHeight={400} hero />\n\n## Usage\n\nThe `useDroppable` hook requires a unique `id` and returns a `ref` callback.\n\n```tsx\nimport {useDroppable} from '@dnd-kit/solid';\n\nfunction Droppable(props) {\n  const {ref, isDropTarget} = useDroppable({id: props.id});\n\n  return (\n    <div ref={ref} data-highlight={isDropTarget()}>\n      {props.children}\n    </div>\n  );\n}\n```\n\n## Input\n\n<ParamField path=\"id\" type=\"UniqueIdentifier\" required>\n  A unique identifier for this droppable instance.\n</ParamField>\n\n<ParamField path=\"accept\" type=\"string | string[]\" optional>\n  The types of draggable elements this droppable accepts.\n</ParamField>\n\n<ParamField path=\"type\" type=\"string\" optional>\n  The type of this droppable element.\n</ParamField>\n\n<ParamField path=\"collisionDetector\" type=\"CollisionDetector\" optional>\n  A custom collision detection algorithm.\n</ParamField>\n\n<ParamField path=\"disabled\" type=\"boolean\" optional>\n  Whether the droppable is disabled.\n</ParamField>\n\n<ParamField path=\"data\" type=\"Data\" optional>\n  Custom data to attach to this droppable instance.\n</ParamField>\n\n## Output\n\n<ResponseField name=\"ref\" type=\"(element: Element) => void\">\n  A callback ref to attach to the droppable element.\n</ResponseField>\n\n<ResponseField name=\"isDropTarget\" type=\"() => boolean\" note=\"accessor\">\n  Whether this element is currently a drop target. Call as `isDropTarget()` in JSX.\n</ResponseField>\n\n<ResponseField name=\"droppable\" type=\"Droppable\">\n  The underlying `Droppable` instance.\n</ResponseField>\n\nexport const app = `\nimport {createSignal} from 'solid-js';\nimport {DragDropProvider, useDraggable} from '@dnd-kit/solid';\nimport {Droppable} from './Droppable';\nimport './styles.css';\n\nfunction Draggable() {\n  const {ref} = useDraggable({id: 'draggable'});\n  return <button ref={ref} class=\"btn\">draggable</button>;\n}\n\nexport default function App() {\n  const [parent, setParent] = createSignal(undefined);\n  return (\n    <DragDropProvider\n      onDragEnd={(event) => {\n        if (event.canceled) return;\n        setParent(event.operation.target?.id);\n      }}\n    >\n      <div class=\"container\">\n        {parent() == null ? <Draggable /> : null}\n        <Droppable>\n          {parent() === 'droppable' ? <Draggable /> : null}\n        </Droppable>\n      </div>\n    </DragDropProvider>\n  );\n}\n`.trim();\n\nexport const code = `\nimport {useDroppable} from '@dnd-kit/solid';\n\nexport function Droppable(props) {\n  const {ref, isDropTarget} = useDroppable({id: 'droppable'});\n\n  return (\n    <div ref={ref} class={isDropTarget() ? \"droppable active\" : \"droppable\"}>\n      {props.children}\n    </div>\n  );\n}\n`.trim();\n\nexport const containerStyles = `\n.container {\n  display: grid;\n  grid-template-columns: 2fr 1fr;\n  grid-gap: 20px;\n  align-items: center;\n  max-width: 700px;\n  margin: 0 auto;\n}\n`.trim();\n"
  },
  {
    "path": "apps/docs/solid/hooks/use-sortable.mdx",
    "content": "---\ntitle: 'useSortable'\ndescription: 'Create sortable elements with the useSortable hook.'\nicon: 'layer-group'\n---\n\nimport {Story} from '/snippets/story.mdx';\nimport {CodeSandbox} from '/snippets/sandbox.mdx';\nimport {sortableStyles} from '/snippets/code.mdx';\n\n<Story id=\"sortable-vertical-list--basic-setup\" framework=\"solid\" height=\"320\" hero />\n\n## Usage\n\nThe `useSortable` hook combines draggable and droppable behavior with sorting logic. Import it from `@dnd-kit/solid/sortable`.\n\n<CodeSandbox template=\"solid\" files={{\n  'App.tsx': {code: appCode, active: true},\n  'styles.css': {code: sortableStyles, hidden: true},\n}} height={560} previewHeight={180} />\n\n<Note>\n  Use **getter syntax** for reactive props to maintain Solid's fine-grained reactivity. Without getters, the hook reads prop values once during setup and never re-runs its effects when they change.\n</Note>\n\n## Without the move helper\n\nThe example above uses the `move` helper from `@dnd-kit/helpers`, a convenience function that takes your items and a drag event and returns a new array with the item moved to its new position. It supports flat arrays and grouped records, handles canceled drags, and works with optimistic sorting out of the box.\n\nIf you need more control over state updates, you can manage state manually using the `isSortable` type guard and the sortable properties (`initialIndex`, `index`).\n\nWith [optimistic sorting](/concepts/sortable#optimistic-sorting) enabled (the default), you only need to handle the `onDragEnd` event:\n\n```tsx\nimport {createSignal, For} from 'solid-js';\nimport {DragDropProvider} from '@dnd-kit/solid';\nimport {useSortable, isSortable} from '@dnd-kit/solid/sortable';\n\nfunction SortableItem(props) {\n  const {ref} = useSortable({\n    get id() { return props.id; },\n    get index() { return props.index; },\n  });\n\n  return <li ref={ref} class=\"item\">Item {props.id}</li>;\n}\n\nexport default function App() {\n  const [items, setItems] = createSignal([1, 2, 3, 4]);\n\n  return (\n    <DragDropProvider\n      onDragEnd={(event) => {\n        if (event.canceled) return;\n\n        const {source} = event.operation;\n\n        if (isSortable(source)) {\n          const {initialIndex, index} = source;\n\n          if (initialIndex !== index) {\n            setItems((items) => {\n              const newItems = [...items];\n              const [removed] = newItems.splice(initialIndex, 1);\n              newItems.splice(index, 0, removed);\n              return newItems;\n            });\n          }\n        }\n      }}\n    >\n      <ul class=\"list\">\n        <For each={items()}>\n          {(id, index) => <SortableItem id={id} index={index()} />}\n        </For>\n      </ul>\n    </DragDropProvider>\n  );\n}\n```\n\n<Tip>\n  You can call `event.preventDefault()` in an `onDragOver` handler to prevent the `OptimisticSortingPlugin` from optimistically updating for that specific event. This is useful when you want to conditionally block certain moves.\n</Tip>\n\n<Info>\n  Learn more about [optimistic sorting, type guards, and manual state management](/concepts/sortable#optimistic-sorting) in the Sortable concepts page.\n</Info>\n\n## Input\n\n<ParamField path=\"id\" type=\"UniqueIdentifier\" required>\n  A unique identifier. Use `get id() { return props.id }` for reactive values.\n</ParamField>\n\n<ParamField path=\"index\" type=\"number\" required>\n  The current index in the sorted list. Use `get index() { return props.index }` for reactive values.\n</ParamField>\n\n<ParamField path=\"group\" type=\"string\" optional>\n  The group this sortable belongs to. Used for sorting across multiple lists.\n</ParamField>\n\n<ParamField path=\"handle\" type=\"Element\" optional>\n  A handle element. Use the `handleRef` callback to set it.\n</ParamField>\n\n<ParamField path=\"accept\" type=\"string | string[]\" optional>\n  The types of draggable elements this sortable accepts.\n</ParamField>\n\n<ParamField path=\"type\" type=\"string\" optional>\n  The type of this sortable element.\n</ParamField>\n\n<ParamField path=\"plugins\" type=\"PluginDescriptor[]\" optional>\n  An array of plugin descriptors for per-entity plugin configuration. Use `Plugin.configure()` to create descriptors. For example, `Feedback.configure({ feedback: 'clone' })`.\n</ParamField>\n\n<ParamField path=\"transition\" type=\"SortableTransition\" optional>\n  Animation transition configuration.\n</ParamField>\n\n<ParamField path=\"modifiers\" type=\"Modifier[]\" optional>\n  Modifiers to apply to this sortable instance.\n</ParamField>\n\n<ParamField path=\"sensors\" type=\"Sensor[]\" optional>\n  Sensors to use for this sortable instance.\n</ParamField>\n\n<ParamField path=\"collisionDetector\" type=\"CollisionDetector\" optional>\n  A custom collision detection algorithm.\n</ParamField>\n\n<ParamField path=\"collisionPriority\" type=\"number\" optional>\n  The collision priority of this sortable element. Higher values take precedence when multiple droppable elements overlap.\n</ParamField>\n\n<ParamField path=\"disabled\" type=\"boolean\" optional>\n  Whether the sortable is disabled.\n</ParamField>\n\n<ParamField path=\"data\" type=\"Data\" optional>\n  Custom data to attach to this sortable instance.\n</ParamField>\n\n## Output\n\n<ResponseField name=\"ref\" type=\"(element: Element) => void\">\n  A callback ref to attach to the sortable element.\n</ResponseField>\n\n<ResponseField name=\"handleRef\" type=\"(element: Element) => void\">\n  A callback ref for a drag handle.\n</ResponseField>\n\n<ResponseField name=\"sourceRef\" type=\"(element: Element) => void\">\n  A callback ref for the drag source element.\n</ResponseField>\n\n<ResponseField name=\"targetRef\" type=\"(element: Element) => void\">\n  A callback ref for the drop target element.\n</ResponseField>\n\n<ResponseField name=\"isDragging\" type=\"() => boolean\" note=\"accessor\">\n  Whether this element is currently being dragged. Call as `isDragging()` in JSX.\n</ResponseField>\n\n<ResponseField name=\"isDropping\" type=\"() => boolean\" note=\"accessor\">\n  Whether this element is in the process of being dropped. Call as `isDropping()` in JSX.\n</ResponseField>\n\n<ResponseField name=\"isDragSource\" type=\"() => boolean\" note=\"accessor\">\n  Whether this element is the source of the current drag operation. Call as `isDragSource()` in JSX.\n</ResponseField>\n\n<ResponseField name=\"isDropTarget\" type=\"() => boolean\" note=\"accessor\">\n  Whether this element is currently a drop target. Call as `isDropTarget()` in JSX.\n</ResponseField>\n\n<ResponseField name=\"sortable\" type=\"Sortable\">\n  The underlying `Sortable` instance.\n</ResponseField>\n\nexport const appCode = `\nimport {createSignal, For} from 'solid-js';\nimport {DragDropProvider} from '@dnd-kit/solid';\nimport {useSortable} from '@dnd-kit/solid/sortable';\nimport {move} from '@dnd-kit/helpers';\nimport './styles.css';\n\nfunction SortableItem(props) {\n  const {ref} = useSortable({\n    get id() { return props.id; },\n    get index() { return props.index; },\n  });\n\n  return <li ref={ref} class=\"item\">Item {props.id}</li>;\n}\n\nexport default function App() {\n  const [items, setItems] = createSignal([1, 2, 3, 4]);\n\n  return (\n    <DragDropProvider\n      onDragEnd={(event) => {\n        setItems((items) => move(items, event));\n      }}\n    >\n      <ul class=\"list\">\n        <For each={items()}>\n          {(id, index) => <SortableItem id={id} index={index()} />}\n        </For>\n      </ul>\n    </DragDropProvider>\n  );\n}\n`.trim();\n"
  },
  {
    "path": "apps/docs/solid/quickstart.mdx",
    "content": "---\ntitle: 'Quickstart'\ndescription: 'Start building drag and drop interfaces with SolidJS in minutes.'\nicon: 'rocket'\n---\n\nimport {Story} from '/snippets/story.mdx';\nimport Intro from '/snippets/quickstart/intro.mdx';\n\n<Intro />\n\n## Overview\n\nThe `@dnd-kit/solid` package provides a set of SolidJS hooks and components that you can use to build drag and drop interfaces. It is a thin SolidJS integration layer built on top of the [vanilla](/overview) library, so all of the same concepts are shared and can be used. You can refer to the vanilla documentation of these concepts, such as [plugins](/extend/plugins), [modifiers](/extend/modifiers), and [sensors](/extend/sensors).\n\n<Note>\n  `@dnd-kit/solid` requires SolidJS 1.8 or later.\n</Note>\n\n## Installation\nBefore getting started, make sure you install `@dnd-kit/solid` in your project:\n\n<CodeGroup>\n  ```bash npm\n  npm install @dnd-kit/solid\n  ```\n\n  ```bash yarn\n  yarn add @dnd-kit/solid\n  ```\n\n  ```bash pnpm\n  pnpm add @dnd-kit/solid\n  ```\n\n  ```bash bun\n  bun add @dnd-kit/solid\n  ```\n</CodeGroup>\n\n## Making elements draggable\n\nLet's get started by creating draggable elements. The `useDraggable` hook requires a unique `id`, and returns a `ref` callback that you can attach to any element.\n\n```tsx\nimport {useDraggable} from '@dnd-kit/solid';\n\nfunction Draggable() {\n  const {ref} = useDraggable({id: 'draggable'});\n\n  return (\n    <button ref={ref}>\n      Draggable\n    </button>\n  );\n}\n```\n\n## Creating droppable elements\n\nTo create drop targets, use the `useDroppable` hook.\n\n```tsx\nimport {useDroppable} from '@dnd-kit/solid';\n\nfunction Droppable(props) {\n  const {ref, isDropTarget} = useDroppable({id: props.id});\n\n  return (\n    <div ref={ref} style={{width: '300px', height: '300px'}}>\n      {props.children}\n    </div>\n  );\n}\n```\n\n## Putting all the pieces together\n\nWrap your draggable and droppable elements in a `DragDropProvider` to enable drag and drop interactions.\n\n```tsx\nimport {createSignal} from 'solid-js';\nimport {DragDropProvider, useDraggable, useDroppable} from '@dnd-kit/solid';\n\nfunction Draggable() {\n  const {ref} = useDraggable({id: 'draggable'});\n  return <button ref={ref}>Draggable</button>;\n}\n\nfunction Droppable(props) {\n  const {ref, isDropTarget} = useDroppable({id: 'droppable'});\n  return <div ref={ref}>{props.children}</div>;\n}\n\nfunction App() {\n  const [parent, setParent] = createSignal(undefined);\n\n  return (\n    <DragDropProvider\n      onDragEnd={(event) => {\n        if (event.canceled) return;\n        setParent(event.operation.target?.id);\n      }}\n    >\n      {parent() == null ? <Draggable /> : null}\n\n      <Droppable id=\"droppable\">\n        {parent() === 'droppable' ? <Draggable /> : null}\n      </Droppable>\n    </DragDropProvider>\n  );\n}\n```\n\n<Note>\n  When passing reactive props to hooks like `useSortable`, use getter syntax to maintain Solid's fine-grained reactivity:\n  ```tsx\n  useSortable({\n    get id() { return props.id; },\n    get index() { return props.index; },\n  });\n  ```\n</Note>\n\n## Next steps\n\n<CardGroup>\n  <Card title=\"DragDropProvider\" icon=\"sitemap\" href=\"/solid/components/drag-drop-provider\">\n    Create drag and drop contexts for your draggable and droppable elements.\n  </Card>\n\n  <Card title=\"useDraggable\" icon=\"bullseye-pointer\" href=\"/solid/hooks/use-draggable\">\n    Learn how to make elements draggable with the `useDraggable` hook.\n  </Card>\n\n  <Card title=\"useDroppable\" icon=\"expand\" href=\"/solid/hooks/use-droppable\">\n    Learn how to create droppable targets with the `useDroppable` hook.\n  </Card>\n\n  <Card title=\"useSortable\" icon=\"layer-group\" href=\"/solid/hooks/use-sortable\">\n    Learn how to create sortable elements with the `useSortable` hook.\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "apps/docs/style.css",
    "content": "#navbar img[src*=\"logo\"] {\n  height: 45px;\n}\n\n#sidebar svg:is([style*=\"sitemap.svg\"], [style*=\"layer-group.svg\"], [style*=\"arrows-from-line.svg\"], [style*=\"signal-stream.svg\"]) {\n  width: 1.1rem;\n}\n\n.hero-image {\n  margin-top: -3vw;\n\n  @media (min-width: 1280px) and (max-width: 1420px) {\n    margin-top: -2vw;\n  }\n\n  @media (max-width: 540px) {\n    margin-top: -40px;\n  }\n}\n\n#navbar a:is([href=\"/react/quickstart\"], [href=\"/javascript/quickstart\"]) {\n  display: inline-flex;\n  gap: 0.5rem;\n  align-items: center;\n\n  &::before {\n    content: '';\n    display: block;\n    mask-repeat: no-repeat;\n    mask-position: center center;\n    width: 18px;\n    height: 18px;\n  }\n}\n\n#navbar a[href=\"/react/quickstart\"]::before {\n  mask-image: url(\"https://mintlify.b-cdn.net/v6.4.0/brands/react.svg\");\n  background-color: #61DAFB;\n}\n\n#navbar a[href=\"/javascript/quickstart\"]::before {\n  mask-image: url(\"https://mintlify.b-cdn.net/v6.4.0/brands/js.svg\");\n  background-color: #F7DF1E;\n}\n\n/* Framework brand colors for sidebar icons */\n[data-component-part=\"card-content-container\"] svg[style*=\"react.svg\"] {\n  background-color: #61DAFB !important;\n}\n\n[data-component-part=\"card-content-container\"] svg[style*=\"vuejs.svg\"] {\n  background-color: #4FC08D !important;\n}\n\nsvg[style*=\"svelte.svg\"] {\n  mask-image: url(\"/images/logo/svelte.svg\") !important;\n}\n\n[data-component-part=\"card-content-container\"] svg[style*=\"svelte.svg\"] {\n  background-color: #FF3E00 !important;\n}\n\nsvg[style*=\"solidjs.svg\"] {\n  mask-image: url(\"/images/logo/solid.svg\") !important;\n}\n\n[data-component-part=\"card-content-container\"] svg[style*=\"solidjs.svg\"] {\n  background-color: #4B7BBE !important;\n}\n\n[data-component-part=\"card-content-container\"] svg[style*=\"/js.svg\"] {\n  background-color: #F7DF1E !important;\n}\n\n.font-extrabold,\n.prose :where(h2):not(:where([class~=not-prose] *)) {\n  font-weight: 600;\n}\n\n.info ol {\n  list-style-type: decimal;\n  padding: 1.25rem;\n  text-indent: 0.25rem;\n}\n\nkbd {\n  display: inline-flex;\n  align-items: center;\n  justify-content: center;\n  flex-shrink: 0;\n  font-weight: 400;\n  vertical-align: text-top;\n  white-space: nowrap;\n  font-size: .75em;\n  min-width: 1.75em;\n  line-height: 1.7em;\n  box-sizing: border-box;\n  padding-left: .5em;\n  padding-right: .5em;\n  padding-bottom: .05em;\n  word-spacing: -.1em;\n  border-radius: 0.25em;\n  height: fit-content;\n  background-color: rgba(255, 255, 255);\n  box-shadow: color(display-p3 0.024 0.024 0.349 / 0.024) 0px -0.6px 6px 0px inset, color(display-p3 1 1 1 / 0.95) 0px 0.6px 0px 0px inset, color(display-p3 0.024 0.024 0.349 / 0.024) 0px 3px 6px 0px inset, color(display-p3 0.008 0.008 0.165 / 0.15) 0px -0.6px 0px 0px inset, color(display-p3 0.004 0.039 0.2 / 0.122) 0px 0px 0px 0.6px, color(display-p3 0.008 0.027 0.184 / 0.197) 0px 0.96px 2.04px 0px;\n}\n\n.dark kbd {\n  background-color: rgba(0, 0, 0);\n  box-shadow: color(display-p3 0.882 0.933 0.992 / 0.077) 0px -0.6px 6px 0px inset, color(display-p3 0.949 0.969 0.996 / 0.708) 0px 0.6px 0px 0px inset, color(display-p3 0.875 0.992 1 / 0.034) 0px 3px 6px 0px inset, color(display-p3 0 0 0 / 0.9) 0px -1.2px 0px 0px inset, color(display-p3 0.882 0.929 1 / 0.246) 0px 0px 0px 0.9px, color(display-p3 0 0 0 / 0.95) 0px 0.96px 2.04px 0px;\n}\n\n.sponsors {\n  display: grid;\n  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));\n  gap: 20px;\n}\n\n.sponsors .rounded-2xl:hover {\n  outline: 1px solid rgb(var(--primary-light));\n}\n\n.inline-logo {\n  display: inline-block;\n}\n\n.inline-logo::before {\n  content: '';\n  position: relative;\n  top: 0.15em;\n  margin-right: 0.3em;\n  margin-left: 0.2em;\n  display: inline-block;\n  width: 17px;\n  height: 17px;\n  mask-image: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNzIiIGhlaWdodD0iNzIiIHZpZXdCb3g9IjAgMCA3MiA3MiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTcxLjc2MDggMC43NzgzMlYyMC45ODc1SDY1LjkwOTZWMTAuNjM0OEw2MS43NzI3IDYuNTUyMzFINTEuMjgxN1YwLjc3ODMySDcxLjc2MDhaTTIwLjU5NzUgMC43NzgzMlY2LjU1MjMxSDEwLjEwNjVMMjguNTE3MiAyNC43MjA0TDI0LjM4MDIgMjguODAyOEw1Ljk2OTU2IDEwLjYzNDhWMjAuOTg3NUgwLjExODM3VjAuNzc4MzJIMjAuNTk3NVpNNDcuNDk5IDQzLjQ1Mkw2NS45MDk2IDYxLjYyVjUxLjI2NzNINzEuNzYwOFY3MS40NzY2SDUxLjI4MTdWNjUuNzAyNUg2MS43NzI3TDQzLjM2MiA0Ny41MzQ1TDQ3LjQ5OSA0My40NTJaTTYxLjc3MjcgNi41NTIzMUw2NS45MDk2IDEwLjYzNDhMMTAuMTg3NSA2NS42MzkySDIwLjc2MzZWNzEuNDc2NkgwLjExODM3VjUxLjA0NTdINi4wMTcwMVY2MS41MTE5TDYxLjc3MjcgNi41NTIzMVoiIGZpbGw9ImJsYWNrIi8+Cjwvc3ZnPgo=);\n  mask-repeat: no-repeat;\n  mask-position: center center;\n  mask-size: contain;\n  background-color: currentColor;\n}\n\n#content-container.max-w-6xl {\n  max-width: 80rem;\n}\n\n.sp-layout {\n  border-radius: var(--rounded-xl, .75rem);\n  --tw-ring-color: rgba(0, 0, 0, .05);\n  --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);\n  --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);\n  box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);\n}\n\nhtml:not(.dark) .hero .sp-layout {\n  box-shadow: none;\n}\n\n\n.sp-tabs-scrollable-container {\n  padding-left: 0;\n  padding-right: 0;\n}\n\n.sp-tab-button {\n  padding: 0.5rem 1rem;\n  border-bottom: 1px solid transparent;\n}\n\n.sp-tab-button[data-active=\"true\"] {\n  border-color: rgb(var(--primary-light));\n}\n\n.sp-layout {\n  gap: 0px;\n}\n\n.dark .sp-layout {\n  --tw-ring-color: rgb(var(--gray-800) / 0.5);\n}\n\n.sp-editor {\n  flex-basis: 100% !important;\n  order: 1;\n}\n\n.sp-preview {\n  flex-basis: 100% !important;\n}\n\n.sp-preview,\n.sp-preview-container {\n  background-color: transparent;\n}\n\n.sp-preview-iframe {\n  min-height: 100px;\n}\n\n[data-as=\"iframe\"] {\n  width: 100%;\n}\n\ncode-sandbox[style*=\"--preview-height\"] .sp-preview {\n  height: var(--preview-height) !important;\n}\n\n.sp-preview-container,\n.sp-overlay {\n  background-color: #fafafd;\n}\n\n.dark .sp-preview-container,\n.dark .sp-overlay {\n  background-color: #11131b;\n}\n\n.sp-preview-container iframe {\n  background: transparent;\n  color-scheme: normal;\n}\n\n.hero .sp-preview-container,\n.hero .sp-overlay {\n  --gradient: linear-gradient(65deg, #56fff420, #001AFF20, #5F6AF220, #F25FD020, #56FFF520, #F25FD020, #001AFF20, #56fff420);\n  background-image: var(--gradient);\n  animation: background 16s linear infinite;\n  animation-direction: alternate;\n  background-size: 600% 100%;\n}\n\n.dark .hero .sp-preview-container,\n.dark .hero .sp-overlay {\n  --gradient: linear-gradient(65deg, #56fff480, #001AFF80, #5F6AF280, #F25FD080, #56FFF580, #F25FD080, #001AFF80, #56fff480);\n  animation: gradient 16s linear infinite;\n}\n\n\n@keyframes gradient {\n  0% {\n    background-color: #ff0000;\n  }\n\n  25% {\n    background-color: #7f00ff;\n  }\n\n  50% {\n    background-color: #00affa;\n  }\n\n  75% {\n    background-color: #00f594;\n  }\n\n  100% {\n    background-color: #ff0000\n  }\n}\n\n@keyframes background-position {\n  0% {\n    background-position: 0% 50%;\n  }\n\n  100% {\n    background-position: 100% 50%;\n  }\n}\n\nheader:has(+ [data-page-title=\"Overview\"]) #page-context-menu {\n  display: none;\n}\n\n#page-context-menu {\n  align-items: stretch;\n}\n\n#page-context-menu-button svg+span {\n  display: none;\n}\n"
  },
  {
    "path": "apps/docs/svelte/components/drag-drop-provider.mdx",
    "content": "---\ntitle: 'DragDropProvider'\ndescription: 'The DragDropProvider component creates and manages a DragDropManager instance for your Svelte application.'\nicon: 'sitemap'\n---\n\n## Overview\n\nThe `DragDropProvider` component is the root component for drag and drop interactions. It creates a [DragDropManager](/concepts/drag-drop-manager) instance and makes it available to all descendant components via Svelte's context API.\n\n## Usage\n\n```svelte\n<script>\n  import {DragDropProvider} from '@dnd-kit/svelte';\n\n  function onDragEnd(event) {\n    // Handle drag end\n  }\n</script>\n\n<DragDropProvider {onDragEnd}>\n  <!-- Your draggable and droppable elements -->\n</DragDropProvider>\n```\n\n## Events\n\nThe `DragDropProvider` accepts callback props for all drag and drop lifecycle stages:\n\n| Prop | Description |\n|------|-------------|\n| `onBeforeDragStart` | Fired before a drag operation begins. Can be used to prepare state. |\n| `onDragStart` | Fired when a drag operation starts. |\n| `onDragMove` | Fired when the dragged element moves. |\n| `onDragOver` | Fired when the dragged element moves over a droppable target. Call `event.preventDefault()` to prevent the default behavior of plugins that respond to this event. |\n| `onDragEnd` | Fired when a drag operation ends (dropped or canceled). |\n| `onCollision` | Fired when collisions are detected between draggable and droppable elements. |\n\n## Props\n\n<ParamField path=\"manager\" type=\"DragDropManager\" optional>\n  An optional externally created `DragDropManager` instance. If not provided, one will be created automatically.\n</ParamField>\n\n<ParamField path=\"plugins\" type=\"Plugin[] | (defaults: Plugin[]) => Plugin[]\" optional>\n  Plugins to use. Defaults to the default preset. Pass an array to replace defaults, or a function to extend them.\n\n  ```ts\n  // Add a plugin alongside defaults\n  plugins={(defaults) => [...defaults, MyPlugin]}\n\n  // Replace defaults entirely\n  plugins={[MyPlugin]}\n  ```\n</ParamField>\n\n<ParamField path=\"sensors\" type=\"Sensor[] | (defaults: Sensor[]) => Sensor[]\" optional>\n  Sensors to use. Defaults to `PointerSensor` and `KeyboardSensor`. Pass an array to replace defaults, or a function to extend them.\n</ParamField>\n\n<ParamField path=\"modifiers\" type=\"Modifier[] | (defaults: Modifier[]) => Modifier[]\" optional>\n  Modifiers to apply to drag operations. Pass an array to replace defaults, or a function to extend them.\n</ParamField>\n"
  },
  {
    "path": "apps/docs/svelte/components/drag-overlay.mdx",
    "content": "---\ntitle: 'DragOverlay'\ndescription: 'Render a custom element as visual feedback during drag operations.'\nicon: 'clone'\n---\n\n## Overview\n\nThe `DragOverlay` component renders a custom overlay element while a drag operation is in progress. This allows you to display a completely different element than the one being dragged, which is useful for rendering a styled clone, a preview, or a simplified representation of the dragged element.\n\n<img src=\"/images/draggable/drag-overlay.png\" />\n\n## Usage\n\nImport and place the `DragOverlay` component inside a [`DragDropProvider`](/svelte/components/drag-drop-provider). Its children will only be rendered when a drag operation is active.\n\n```svelte\n<script>\n  import {DragDropProvider, DragOverlay, createDraggable} from '@dnd-kit/svelte';\n\n  const draggable = createDraggable({id: 'my-item'});\n</script>\n\n<DragDropProvider>\n  <button {@attach draggable.attach}>Drag me</button>\n  <DragOverlay>\n    {#snippet children(source)}\n      <div>I will be rendered while dragging...</div>\n    {/snippet}\n  </DragOverlay>\n</DragDropProvider>\n```\n\n<Warning>\n  You should only render the `DragOverlay` component once per [DragDropProvider](/svelte/components/drag-drop-provider).\n</Warning>\n\n### Rendering based on the drag source\n\nYou can use the `children` snippet parameter to access the current drag `source` and render different content depending on which element is being dragged:\n\n```svelte\n<script>\n  import {DragDropProvider, DragOverlay} from '@dnd-kit/svelte';\n</script>\n\n<DragDropProvider>\n  <!-- draggable elements -->\n  <DragOverlay>\n    {#snippet children(source)}\n      <div>Dragging {source.id}</div>\n    {/snippet}\n  </DragOverlay>\n</DragDropProvider>\n```\n\n### Customizing the drop animation\n\nBy default, when a drag operation ends, the overlay animates back to the position of the source element. You can customize or disable this animation using the `dropAnimation` prop.\n\n```svelte\n<!-- Disable the drop animation -->\n<DragOverlay dropAnimation={null}>\n  {#snippet children(source)}\n    <div>No animation on drop</div>\n  {/snippet}\n</DragOverlay>\n\n<!-- Customize the animation timing -->\n<DragOverlay dropAnimation={{ duration: 150, easing: 'ease-out' }}>\n  {#snippet children(source)}\n    <div>Fast drop animation</div>\n  {/snippet}\n</DragOverlay>\n```\n\n## Props\n\n<ParamField path=\"disabled\" type=\"boolean\" default=\"false\">\n  Whether the drag overlay is disabled. When `true`, the overlay will not render its children during drag operations.\n</ParamField>\n\n<ParamField path=\"dropAnimation\" type=\"DropAnimation | null\" optional>\n  Customize or disable the drop animation that plays when a drag operation ends.\n\n  - `undefined` – use the default animation (`250ms` ease)\n  - `null` – disable the drop animation entirely\n  - `{duration, easing}` – customize the animation timing\n  - `(context) => Promise<void> | void` – provide a fully custom animation function\n</ParamField>\n\n## Snippets\n\n<ParamField path=\"children\" type=\"Snippet<[Draggable]>\">\n  The content to render as the drag overlay. Only rendered when a drag operation is in progress.\n\n  **Snippet parameters:**\n  - `source` – the [Draggable](/concepts/draggable) instance that is the source of the current drag operation.\n</ParamField>\n"
  },
  {
    "path": "apps/docs/svelte/primitives/create-draggable.mdx",
    "content": "---\ntitle: 'createDraggable'\ndescription: 'Make elements draggable with the createDraggable primitive.'\nicon: 'bullseye-pointer'\n---\n\nimport {Story} from '/snippets/story.mdx';\n\n<Story id=\"draggable-basic-setup--example\" framework=\"svelte\" height=\"200\" hero />\n\n## Usage\n\nThe `createDraggable` primitive requires a unique `id`. It returns an object with `attach` and `attachHandle` functions for connecting elements, and reactive state properties.\n\n```svelte\n<script>\n  import {createDraggable} from '@dnd-kit/svelte';\n\n  const draggable = createDraggable({id: 'my-draggable'});\n</script>\n\n<button {@attach draggable.attach}>\n  Drag me\n</button>\n```\n\n## Input\n\nAll input properties accept plain values or getter functions for reactivity.\n\n<ParamField path=\"id\" type=\"UniqueIdentifier | (() => UniqueIdentifier)\" required>\n  A unique identifier for this draggable instance.\n</ParamField>\n\n<ParamField path=\"disabled\" type=\"boolean | (() => boolean)\" optional>\n  Whether the draggable is disabled.\n</ParamField>\n\n<ParamField path=\"plugins\" type=\"PluginDescriptor[] | (() => PluginDescriptor[])\" optional>\n  An array of plugin descriptors for per-entity plugin configuration. Use `Plugin.configure()` to create descriptors. For example, `Feedback.configure({ feedback: 'clone' })`.\n</ParamField>\n\n<ParamField path=\"modifiers\" type=\"Modifier[] | (() => Modifier[])\" optional>\n  Modifiers to apply to this draggable instance.\n</ParamField>\n\n<ParamField path=\"sensors\" type=\"Sensor[] | (() => Sensor[])\" optional>\n  Sensors to use for this draggable instance.\n</ParamField>\n\n<ParamField path=\"data\" type=\"Data | (() => Data)\" optional>\n  Custom data to attach to this draggable instance.\n</ParamField>\n\n## Output\n\nThe returned object provides reactive properties and attachment functions:\n\n<ResponseField name=\"isDragging\" type=\"boolean\">\n  Whether this element is currently being dragged (visually).\n</ResponseField>\n\n<ResponseField name=\"isDropping\" type=\"boolean\">\n  Whether this element is in the process of being dropped (animating to final position).\n</ResponseField>\n\n<ResponseField name=\"isDragSource\" type=\"boolean\">\n  Whether this element is the source of the current drag operation.\n</ResponseField>\n\n<ResponseField name=\"draggable\" type=\"Draggable\">\n  The underlying `Draggable` instance.\n</ResponseField>\n\n<ResponseField name=\"attach\" type=\"(element: HTMLElement) => () => void\">\n  Attachment function for the draggable element. Use with `{@attach}`.\n</ResponseField>\n\n<ResponseField name=\"attachHandle\" type=\"(element: HTMLElement) => () => void\">\n  Attachment function for a drag handle. Use with `{@attach}`.\n</ResponseField>\n\n## Guides\n\n### Using drag handles\n\nYou can use `attachHandle` to designate a specific element as the drag handle:\n\n```svelte\n<script>\n  import {createDraggable} from '@dnd-kit/svelte';\n\n  const draggable = createDraggable({id: 'draggable'});\n</script>\n\n<div {@attach draggable.attach}>\n  Drag me by the handle\n  <button {@attach draggable.attachHandle} class=\"handle\" />\n</div>\n```\n\n### Rendering a drag overlay\n\nYou can render a completely different element while the draggable element is being dragged by using the [`<DragOverlay>`](/svelte/components/drag-overlay) component.\n\n<img src=\"/images/draggable/drag-overlay.png\" />\n\n```svelte\n<script>\n  import {DragDropProvider, DragOverlay, createDraggable} from '@dnd-kit/svelte';\n\n  const draggable = createDraggable({id: 'draggable'});\n</script>\n\n<DragDropProvider>\n  <button {@attach draggable.attach}>Draggable</button>\n  <DragOverlay>\n    {#snippet children(source)}\n      <div>I will be rendered while dragging...</div>\n    {/snippet}\n  </DragOverlay>\n</DragDropProvider>\n```\n\nThe `<DragOverlay>` component will only render its children when a drag operation is in progress. This can be useful for rendering a completely different element while the draggable element is being dragged.\n\n<Warning>\n  You should only render the `<DragOverlay>` component once per [DragDropProvider](/svelte/components/drag-drop-provider).\n</Warning>\n"
  },
  {
    "path": "apps/docs/svelte/primitives/create-droppable.mdx",
    "content": "---\ntitle: 'createDroppable'\ndescription: 'Create droppable targets with the createDroppable primitive.'\nicon: 'expand'\n---\n\nimport {Story} from '/snippets/story.mdx';\n\n<Story id=\"droppable-basic-setup--example\" framework=\"svelte\" height=\"400\" hero />\n\n## Usage\n\nThe `createDroppable` primitive requires a unique `id`. It returns an object with an `attach` function and reactive state.\n\n```svelte\n<script>\n  import {createDroppable} from '@dnd-kit/svelte';\n\n  const droppable = createDroppable({id: 'my-droppable'});\n</script>\n\n<div {@attach droppable.attach}>\n  Drop here\n</div>\n```\n\n## Input\n\n<ParamField path=\"id\" type=\"UniqueIdentifier | (() => UniqueIdentifier)\" required>\n  A unique identifier for this droppable instance.\n</ParamField>\n\n<ParamField path=\"accept\" type=\"string | string[] | (() => string | string[])\" optional>\n  The types of draggable elements this droppable accepts.\n</ParamField>\n\n<ParamField path=\"type\" type=\"string | (() => string)\" optional>\n  The type of this droppable element.\n</ParamField>\n\n<ParamField path=\"collisionDetector\" type=\"CollisionDetector | (() => CollisionDetector)\" optional>\n  A custom collision detection algorithm.\n</ParamField>\n\n<ParamField path=\"disabled\" type=\"boolean | (() => boolean)\" optional>\n  Whether the droppable is disabled.\n</ParamField>\n\n<ParamField path=\"data\" type=\"Data | (() => Data)\" optional>\n  Custom data to attach to this droppable instance.\n</ParamField>\n\n## Output\n\n<ResponseField name=\"isDropTarget\" type=\"boolean\">\n  Whether this element is currently a drop target (a draggable is hovering over it).\n</ResponseField>\n\n<ResponseField name=\"droppable\" type=\"Droppable\">\n  The underlying `Droppable` instance.\n</ResponseField>\n\n<ResponseField name=\"attach\" type=\"(element: HTMLElement) => () => void\">\n  Attachment function for the droppable element. Use with `{@attach}`.\n</ResponseField>\n"
  },
  {
    "path": "apps/docs/svelte/primitives/create-sortable.mdx",
    "content": "---\ntitle: 'createSortable'\ndescription: 'Create sortable elements with the createSortable primitive.'\nicon: 'layer-group'\n---\n\nimport {Story} from '/snippets/story.mdx';\n\n<Story id=\"sortable-vertical-list--basic-setup\" framework=\"svelte\" height=\"320\" hero />\n\n## Usage\n\nThe `createSortable` primitive combines draggable and droppable behavior with sorting logic. Import it from `@dnd-kit/svelte/sortable`.\n\n```svelte\n<script>\n  import {DragDropProvider} from '@dnd-kit/svelte';\n  import {createSortable} from '@dnd-kit/svelte/sortable';\n  import {move} from '@dnd-kit/helpers';\n\n  let items = $state([1, 2, 3, 4]);\n\n  function onDragEnd(event) {\n    items = move(items, event);\n  }\n</script>\n\n<DragDropProvider {onDragEnd}>\n  <ul>\n    {#each items as id, index (id)}\n      {@const sortable = createSortable({id, index: () => index})}\n      <li {@attach sortable.attach}>\n        Item {id}\n      </li>\n    {/each}\n  </ul>\n</DragDropProvider>\n```\n\n<Note>\n  When using `createSortable` inside an `{#each}` block, pass reactive values like `index` as getter functions (e.g. `index: () => index`) to maintain reactivity as items are reordered.\n</Note>\n\n## Without the move helper\n\nThe example above uses the `move` helper from `@dnd-kit/helpers`, a convenience function that takes your items and a drag event and returns a new array with the item moved to its new position. It supports flat arrays and grouped records, handles canceled drags, and works with optimistic sorting out of the box.\n\nIf you need more control over state updates, you can manage state manually using the `isSortable` type guard and the sortable properties (`initialIndex`, `index`).\n\nWith [optimistic sorting](/concepts/sortable#optimistic-sorting) enabled (the default), you only need to handle the `dragend` event:\n\n```svelte\n<script>\n  import {DragDropProvider} from '@dnd-kit/svelte';\n  import {createSortable, isSortable} from '@dnd-kit/svelte/sortable';\n\n  let items = $state([1, 2, 3, 4]);\n\n  function onDragEnd(event) {\n    if (event.canceled) return;\n\n    const {source} = event.operation;\n\n    if (isSortable(source)) {\n      const {initialIndex, index} = source;\n\n      if (initialIndex !== index) {\n        const newItems = [...items];\n        const [removed] = newItems.splice(initialIndex, 1);\n        newItems.splice(index, 0, removed);\n        items = newItems;\n      }\n    }\n  }\n</script>\n\n<DragDropProvider {onDragEnd}>\n  <ul>\n    {#each items as id, index (id)}\n      {@const sortable = createSortable({id, index: () => index})}\n      <li {@attach sortable.attach}>\n        Item {id}\n      </li>\n    {/each}\n  </ul>\n</DragDropProvider>\n```\n\n<Tip>\n  You can call `event.preventDefault()` in an `onDragOver` handler to prevent the `OptimisticSortingPlugin` from optimistically updating for that specific event. This is useful when you want to conditionally block certain moves.\n</Tip>\n\n<Info>\n  Learn more about [optimistic sorting, type guards, and manual state management](/concepts/sortable#optimistic-sorting) in the Sortable concepts page.\n</Info>\n\n## Input\n\nAll input properties accept plain values or getter functions for reactivity.\n\n<ParamField path=\"id\" type=\"UniqueIdentifier | (() => UniqueIdentifier)\" required>\n  A unique identifier for this sortable instance.\n</ParamField>\n\n<ParamField path=\"index\" type=\"number | (() => number)\" required>\n  The current index of this item in the sorted list.\n</ParamField>\n\n<ParamField path=\"group\" type=\"string | (() => string)\" optional>\n  The group this sortable belongs to. Used for sorting across multiple lists.\n</ParamField>\n\n<ParamField path=\"accept\" type=\"string | string[] | (() => string | string[])\" optional>\n  The types of draggable elements this sortable accepts.\n</ParamField>\n\n<ParamField path=\"type\" type=\"string | (() => string)\" optional>\n  The type of this sortable element.\n</ParamField>\n\n<ParamField path=\"plugins\" type=\"PluginDescriptor[] | (() => PluginDescriptor[])\" optional>\n  An array of plugin descriptors for per-entity plugin configuration. Use `Plugin.configure()` to create descriptors. For example, `Feedback.configure({ feedback: 'clone' })`.\n</ParamField>\n\n<ParamField path=\"transition\" type=\"SortableTransition | (() => SortableTransition)\" optional>\n  Animation transition configuration for sort operations.\n</ParamField>\n\n<ParamField path=\"modifiers\" type=\"Modifier[] | (() => Modifier[])\" optional>\n  Modifiers to apply to this sortable instance.\n</ParamField>\n\n<ParamField path=\"sensors\" type=\"Sensor[] | (() => Sensor[])\" optional>\n  Sensors to use for this sortable instance.\n</ParamField>\n\n<ParamField path=\"collisionDetector\" type=\"CollisionDetector | (() => CollisionDetector)\" optional>\n  A custom collision detection algorithm.\n</ParamField>\n\n<ParamField path=\"collisionPriority\" type=\"number | (() => number)\" optional>\n  The collision priority of this sortable element. Higher values take precedence when multiple droppable elements overlap.\n</ParamField>\n\n<ParamField path=\"disabled\" type=\"boolean | (() => boolean)\" optional>\n  Whether the sortable is disabled.\n</ParamField>\n\n<ParamField path=\"data\" type=\"Data | (() => Data)\" optional>\n  Custom data to attach to this sortable instance.\n</ParamField>\n\n## Output\n\n<ResponseField name=\"isDragging\" type=\"boolean\">\n  Whether this element is currently being dragged.\n</ResponseField>\n\n<ResponseField name=\"isDropping\" type=\"boolean\">\n  Whether this element is in the process of being dropped.\n</ResponseField>\n\n<ResponseField name=\"isDragSource\" type=\"boolean\">\n  Whether this element is the source of the current drag operation.\n</ResponseField>\n\n<ResponseField name=\"isDropTarget\" type=\"boolean\">\n  Whether this element is currently a drop target.\n</ResponseField>\n\n<ResponseField name=\"sortable\" type=\"Sortable\">\n  The underlying `Sortable` instance.\n</ResponseField>\n\n<ResponseField name=\"attach\" type=\"(element: HTMLElement) => () => void\">\n  Attachment function for the sortable element. Use with `{@attach}`.\n</ResponseField>\n\n<ResponseField name=\"attachHandle\" type=\"(element: HTMLElement) => () => void\">\n  Attachment function for a drag handle. Use with `{@attach}`.\n</ResponseField>\n\n<ResponseField name=\"attachSource\" type=\"(element: HTMLElement) => () => void\">\n  Attachment function for the drag source element (when different from the sortable element).\n</ResponseField>\n\n<ResponseField name=\"attachTarget\" type=\"(element: HTMLElement) => () => void\">\n  Attachment function for the drop target element (when different from the sortable element).\n</ResponseField>\n"
  },
  {
    "path": "apps/docs/svelte/quickstart.mdx",
    "content": "---\ntitle: 'Quickstart'\ndescription: 'Start building drag and drop interfaces with Svelte in minutes.'\nicon: 'rocket'\n---\n\nimport {Story} from '/snippets/story.mdx';\nimport Intro from '/snippets/quickstart/intro.mdx';\n\n<Intro />\n\n## Overview\n\nThe `@dnd-kit/svelte` package provides a set of Svelte primitives and components that you can use to build drag and drop interfaces. It is a thin Svelte integration layer built on top of the [vanilla](/overview) library, so all of the same concepts are shared and can be used. You can refer to the vanilla documentation of these concepts, such as [plugins](/extend/plugins), [modifiers](/extend/modifiers), and [sensors](/extend/sensors).\n\n<Note>\n  `@dnd-kit/svelte` requires Svelte 5.29 or later.\n</Note>\n\n## Installation\nBefore getting started, make sure you install `@dnd-kit/svelte` in your project:\n\n<CodeGroup>\n  ```bash npm\n  npm install @dnd-kit/svelte\n  ```\n\n  ```bash yarn\n  yarn add @dnd-kit/svelte\n  ```\n\n  ```bash pnpm\n  pnpm add @dnd-kit/svelte\n  ```\n\n  ```bash bun\n  bun add @dnd-kit/svelte\n  ```\n</CodeGroup>\n\n## Making elements draggable\n\nLet's get started by creating draggable elements that can be dropped over droppable targets. To do so, we'll be using the `createDraggable` primitive.\n\nThe `createDraggable` primitive requires a unique `id`. It returns an object with an `attach` function that you can use with the `{@attach}` directive to connect an element to the drag system.\n\n```svelte\n<script>\n  import {createDraggable} from '@dnd-kit/svelte';\n\n  const draggable = createDraggable({id: 'draggable'});\n</script>\n\n<button {@attach draggable.attach}>\n  Draggable\n</button>\n```\n\n## Creating droppable elements\n\nIn order for our draggable elements to have targets where they can be dropped, we need to create droppable elements. To do so, we'll be using the `createDroppable` primitive.\n\nLike `createDraggable`, the `createDroppable` primitive requires a unique `id`.\n\n```svelte\n<script>\n  import {createDroppable} from '@dnd-kit/svelte';\n\n  const droppable = createDroppable({id: 'droppable'});\n</script>\n\n<div {@attach droppable.attach} style=\"width: 300px; height: 300px;\">\n  Droppable\n</div>\n```\n\n## Putting all the pieces together\n\nNow that we have both draggable and droppable elements, we can put them together to create a simple drag and drop interaction.\n\nWe'll be using the `DragDropProvider` component to wrap our draggable and droppable elements. This component handles the drag and drop interactions and allows us to listen to drag and drop events.\n\n```svelte App.svelte\n<script>\n  import {DragDropProvider, createDraggable, createDroppable} from '@dnd-kit/svelte';\n\n  let parent = $state(undefined);\n\n  const draggable = createDraggable({id: 'draggable'});\n  const droppable = createDroppable({id: 'droppable'});\n\n  function onDragEnd(event) {\n    if (event.canceled) return;\n    parent = event.operation.target?.id;\n  }\n</script>\n\n<DragDropProvider {onDragEnd}>\n  {#if parent == null}\n    <button {@attach draggable.attach}>Draggable</button>\n  {/if}\n\n  <div {@attach droppable.attach} style=\"width: 300px; height: 300px;\">\n    {#if parent === 'droppable'}\n      <button {@attach draggable.attach}>Draggable</button>\n    {/if}\n  </div>\n</DragDropProvider>\n```\n\n## Next steps\n\nNow that you have a basic understanding of how to make elements draggable and droppable, you can explore the concepts covered in this quickstart guide in more detail:\n\n<CardGroup>\n  <Card title=\"DragDropProvider\" icon=\"sitemap\" href=\"/svelte/components/drag-drop-provider\">\n    Create drag and drop contexts for your draggable and droppable elements.\n  </Card>\n\n  <Card title=\"createDraggable\" icon=\"bullseye-pointer\" href=\"/svelte/primitives/create-draggable\">\n    Learn how to make elements draggable with the `createDraggable` primitive.\n  </Card>\n\n  <Card title=\"createDroppable\" icon=\"expand\" href=\"/svelte/primitives/create-droppable\">\n    Learn how to create droppable targets with the `createDroppable` primitive.\n  </Card>\n\n  <Card title=\"createSortable\" icon=\"layer-group\" href=\"/svelte/primitives/create-sortable\">\n    Learn how to create sortable elements with the `createSortable` primitive.\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "apps/docs/vue/components/drag-drop-provider.mdx",
    "content": "---\ntitle: 'DragDropProvider'\ndescription: 'The DragDropProvider component creates and manages a DragDropManager instance for your Vue application.'\nicon: 'sitemap'\n---\n\n## Overview\n\nThe `DragDropProvider` component is the root component for drag and drop interactions. It creates a [DragDropManager](/concepts/drag-drop-manager) instance and makes it available to all descendant components via Vue's `provide`/`inject` system.\n\n## Usage\n\n```vue\n<script setup>\nimport {DragDropProvider} from '@dnd-kit/vue';\n</script>\n\n<template>\n  <DragDropProvider @dragEnd=\"handleDragEnd\">\n    <!-- Your draggable and droppable elements -->\n  </DragDropProvider>\n</template>\n```\n\n## Events\n\nThe `DragDropProvider` emits Vue events for all drag and drop lifecycle stages:\n\n| Event | Description |\n|-------|-------------|\n| `@beforeDragStart` | Fired before a drag operation begins. Can be used to prepare state. |\n| `@dragStart` | Fired when a drag operation starts. |\n| `@dragMove` | Fired when the dragged element moves. |\n| `@dragOver` | Fired when the dragged element moves over a droppable target. Call `event.preventDefault()` to prevent the default behavior of plugins that respond to this event. |\n| `@dragEnd` | Fired when a drag operation ends (dropped or canceled). |\n| `@collision` | Fired when collisions are detected between draggable and droppable elements. |\n\n## Props\n\n<ParamField path=\"manager\" type=\"DragDropManager\" optional>\n  An optional externally created `DragDropManager` instance. If not provided, one will be created automatically.\n</ParamField>\n\n<ParamField path=\"plugins\" type=\"Plugin[] | (defaults: Plugin[]) => Plugin[]\" optional>\n  Plugins to use. Defaults to the default preset. Pass an array to replace defaults, or a function to extend them.\n\n  ```ts\n  // Add a plugin alongside defaults\n  :plugins=\"(defaults) => [...defaults, MyPlugin]\"\n\n  // Replace defaults entirely\n  :plugins=\"[MyPlugin]\"\n  ```\n</ParamField>\n\n<ParamField path=\"sensors\" type=\"Sensor[] | (defaults: Sensor[]) => Sensor[]\" optional>\n  Sensors to use. Defaults to `PointerSensor` and `KeyboardSensor`. Pass an array to replace defaults, or a function to extend them.\n</ParamField>\n\n<ParamField path=\"modifiers\" type=\"Modifier[] | (defaults: Modifier[]) => Modifier[]\" optional>\n  Modifiers to apply to drag operations. Pass an array to replace defaults, or a function to extend them.\n</ParamField>\n"
  },
  {
    "path": "apps/docs/vue/components/drag-overlay.mdx",
    "content": "---\ntitle: 'DragOverlay'\ndescription: 'Render a custom element as visual feedback during drag operations.'\nicon: 'clone'\n---\n\n## Overview\n\nThe `DragOverlay` component renders a custom overlay element while a drag operation is in progress. This allows you to display a completely different element than the one being dragged, which is useful for rendering a styled clone, a preview, or a simplified representation of the dragged element.\n\n<img src=\"/images/draggable/drag-overlay.png\" />\n\n## Usage\n\nImport and place the `DragOverlay` component inside a [`DragDropProvider`](/vue/components/drag-drop-provider). Its children will only be rendered when a drag operation is active.\n\n```vue\n<script setup>\nimport {ref} from 'vue';\nimport {DragDropProvider, DragOverlay, useDraggable} from '@dnd-kit/vue';\n\nconst element = ref(null);\nuseDraggable({id: 'my-item', element});\n</script>\n\n<template>\n  <DragDropProvider>\n    <button ref=\"element\">Drag me</button>\n    <DragOverlay>\n      <div>I will be rendered while dragging...</div>\n    </DragOverlay>\n  </DragDropProvider>\n</template>\n```\n\n<Warning>\n  You should only render the `DragOverlay` component once per [DragDropProvider](/vue/components/drag-drop-provider).\n</Warning>\n\n### Rendering based on the drag source\n\nYou can use the scoped slot to access the current drag `source` and render different content depending on which element is being dragged:\n\n```vue\n<script setup>\nimport {DragDropProvider, DragOverlay} from '@dnd-kit/vue';\n</script>\n\n<template>\n  <DragDropProvider>\n    <Draggable id=\"foo\" />\n    <Draggable id=\"bar\" />\n    <DragOverlay>\n      <template #default=\"{ source }\">\n        <div>Dragging {{ source.id }}</div>\n      </template>\n    </DragOverlay>\n  </DragDropProvider>\n</template>\n```\n\n### Customizing the drop animation\n\nBy default, when a drag operation ends, the overlay animates back to the position of the source element. You can customize or disable this animation using the `drop-animation` prop.\n\n```vue\n<!-- Disable the drop animation -->\n<DragOverlay :drop-animation=\"null\">\n  <div>No animation on drop</div>\n</DragOverlay>\n\n<!-- Customize the animation timing -->\n<DragOverlay :drop-animation=\"{ duration: 150, easing: 'ease-out' }\">\n  <div>Fast drop animation</div>\n</DragOverlay>\n```\n\n## Props\n\n<ParamField path=\"tag\" type=\"string\" default=\"'div'\">\n  The HTML tag to render as the overlay wrapper element.\n</ParamField>\n\n<ParamField path=\"disabled\" type=\"boolean\" default=\"false\">\n  Whether the drag overlay is disabled. When `true`, the overlay will not render its children during drag operations.\n</ParamField>\n\n<ParamField path=\"drop-animation\" type=\"DropAnimation | null\" optional>\n  Customize or disable the drop animation that plays when a drag operation ends.\n\n  - `undefined` – use the default animation (`250ms` ease)\n  - `null` – disable the drop animation entirely\n  - `{duration, easing}` – customize the animation timing\n  - `(context) => Promise<void> | void` – provide a fully custom animation function\n</ParamField>\n\n## Slots\n\n<ParamField path=\"default\" type=\"Slot\">\n  The content to render as the drag overlay. Only rendered when a drag operation is in progress.\n\n  **Slot props:**\n  - `source` – the [Draggable](/concepts/draggable) instance that is the source of the current drag operation.\n</ParamField>\n"
  },
  {
    "path": "apps/docs/vue/composables/use-draggable.mdx",
    "content": "---\ntitle: 'useDraggable'\ndescription: 'Make elements draggable with the useDraggable composable.'\nicon: 'bullseye-pointer'\n---\n\nimport {CodeSandbox} from '/snippets/sandbox.mdx';\nimport {draggableStyles} from '/snippets/code.mdx';\n\n<CodeSandbox template=\"vue\" files={{\n  'src/App.vue': {code: app, hidden: true},\n  'src/Draggable.vue': {code: code, active: true},\n  'src/styles.css': {code: draggableStyles, hidden: true},\n}} height={260} previewHeight={200} hero />\n\n## Usage\n\nThe `useDraggable` composable requires a unique `id` and an `element` template ref. It returns reactive computed properties for the drag state.\n\n```vue\n<script setup>\nimport {ref} from 'vue';\nimport {useDraggable} from '@dnd-kit/vue';\n\nconst element = ref(null);\nconst {isDragging} = useDraggable({id: 'my-draggable', element});\n</script>\n\n<template>\n  <button ref=\"element\" :data-dragging=\"isDragging\">\n    Drag me\n  </button>\n</template>\n```\n\n## Input\n\nAll input properties accept plain values or Vue refs/getters (`MaybeRefOrGetter`), so they can be reactive.\n\n<ParamField path=\"id\" type=\"MaybeRefOrGetter<UniqueIdentifier>\" required>\n  A unique identifier for this draggable instance.\n</ParamField>\n\n<ParamField path=\"element\" type=\"MaybeRefOrGetter<HTMLElement | null>\" required>\n  A template ref pointing to the draggable element.\n</ParamField>\n\n<ParamField path=\"handle\" type=\"MaybeRefOrGetter<HTMLElement | null>\" optional>\n  A template ref for a drag handle. When set, only this element activates dragging.\n</ParamField>\n\n<ParamField path=\"disabled\" type=\"MaybeRefOrGetter<boolean>\" optional>\n  Whether the draggable is disabled.\n</ParamField>\n\n<ParamField path=\"plugins\" type=\"MaybeRefOrGetter<PluginDescriptor[]>\" optional>\n  An array of plugin descriptors for per-entity plugin configuration. Use `Plugin.configure()` to create descriptors. For example, `Feedback.configure({ feedback: 'clone' })`.\n</ParamField>\n\n<ParamField path=\"modifiers\" type=\"MaybeRefOrGetter<Modifier[]>\" optional>\n  Modifiers to apply to this draggable instance.\n</ParamField>\n\n<ParamField path=\"sensors\" type=\"MaybeRefOrGetter<Sensor[]>\" optional>\n  Sensors to use for this draggable instance.\n</ParamField>\n\n<ParamField path=\"data\" type=\"MaybeRefOrGetter<Data>\" optional>\n  Custom data to attach to this draggable instance.\n</ParamField>\n\n## Output\n\n<ResponseField name=\"isDragging\" type=\"ComputedRef<boolean>\">\n  Whether this element is currently being dragged (visually).\n</ResponseField>\n\n<ResponseField name=\"isDropping\" type=\"ComputedRef<boolean>\">\n  Whether this element is in the process of being dropped (animating to final position).\n</ResponseField>\n\n<ResponseField name=\"isDragSource\" type=\"ComputedRef<boolean>\">\n  Whether this element is the source of the current drag operation.\n</ResponseField>\n\n<ResponseField name=\"draggable\" type=\"ShallowReadonly<Ref<Draggable>>\">\n  The underlying `Draggable` instance.\n</ResponseField>\n\n## Guides\n\n### Rendering a drag overlay\n\nYou can render a completely different element while the draggable element is being dragged by using the [`<DragOverlay>`](/vue/components/drag-overlay) component.\n\n<img src=\"/images/draggable/drag-overlay.png\" />\n\n```vue\n<script setup>\nimport {ref} from 'vue';\nimport {DragDropProvider, DragOverlay, useDraggable} from '@dnd-kit/vue';\n\nconst element = ref(null);\nuseDraggable({id: 'draggable', element});\n</script>\n\n<template>\n  <DragDropProvider>\n    <button ref=\"element\">Draggable</button>\n    <DragOverlay>\n      <div>I will be rendered while dragging...</div>\n    </DragOverlay>\n  </DragDropProvider>\n</template>\n```\n\nThe `<DragOverlay>` component will only render its children when a drag operation is in progress. This can be useful for rendering a completely different element while the draggable element is being dragged.\n\n<Warning>\n  You should only render the `<DragOverlay>` component once per [DragDropProvider](/vue/components/drag-drop-provider).\n</Warning>\n\nTo render different content depending on which element is being dragged, use the scoped slot to access the drag `source`:\n\n```vue\n<script setup>\nimport {DragDropProvider, DragOverlay} from '@dnd-kit/vue';\n</script>\n\n<template>\n  <DragDropProvider>\n    <Draggable id=\"foo\" />\n    <Draggable id=\"bar\" />\n    <DragOverlay>\n      <template #default=\"{ source }\">\n        <div>Dragging {{ source.id }}</div>\n      </template>\n    </DragOverlay>\n  </DragDropProvider>\n</template>\n```\n\nexport const app = `\n<script setup>\nimport { DragDropProvider } from '@dnd-kit/vue';\nimport Draggable from './Draggable.vue';\nimport './styles.css';\n</script>\n\n<template>\n  <DragDropProvider>\n    <Draggable id=\"draggable\" />\n  </DragDropProvider>\n</template>\n`.trim();\n\nexport const code = `\n<script setup>\nimport { ref } from 'vue';\nimport { useDraggable } from '@dnd-kit/vue';\n\nconst element = ref(null);\nuseDraggable({ id: 'draggable', element });\n</script>\n\n<template>\n  <button ref=\"element\" class=\"btn\">draggable</button>\n</template>\n`.trim();\n"
  },
  {
    "path": "apps/docs/vue/composables/use-droppable.mdx",
    "content": "---\ntitle: 'useDroppable'\ndescription: 'Create droppable targets with the useDroppable composable.'\nicon: 'expand'\n---\n\nimport {CodeSandbox} from '/snippets/sandbox.mdx';\nimport {draggableStyles, droppableStyles} from '/snippets/code.mdx';\n\n<CodeSandbox template=\"vue\" files={{\n  'src/App.vue': {code: app, hidden: true},\n  'src/Draggable.vue': {code: draggableCode, hidden: true},\n  'src/Droppable.vue': {code, active: true},\n  'src/styles.css': {code: draggableStyles + '\\n\\n' + droppableStyles + '\\n\\n' + containerStyles, hidden: true},\n}} height={300} previewHeight={400} hero />\n\n## Usage\n\nThe `useDroppable` composable requires a unique `id` and an `element` template ref.\n\n```vue\n<script setup>\nimport {ref} from 'vue';\nimport {useDroppable} from '@dnd-kit/vue';\n\nconst element = ref(null);\nconst {isDropTarget} = useDroppable({id: 'my-droppable', element});\n</script>\n\n<template>\n  <div ref=\"element\" :data-highlight=\"isDropTarget\">\n    Drop here\n  </div>\n</template>\n```\n\n## Input\n\n<ParamField path=\"id\" type=\"MaybeRefOrGetter<UniqueIdentifier>\" required>\n  A unique identifier for this droppable instance.\n</ParamField>\n\n<ParamField path=\"element\" type=\"MaybeRefOrGetter<HTMLElement | null>\" required>\n  A template ref pointing to the droppable element.\n</ParamField>\n\n<ParamField path=\"accept\" type=\"MaybeRefOrGetter<string | string[]>\" optional>\n  The types of draggable elements this droppable accepts.\n</ParamField>\n\n<ParamField path=\"type\" type=\"MaybeRefOrGetter<string>\" optional>\n  The type of this droppable element.\n</ParamField>\n\n<ParamField path=\"collisionDetector\" type=\"MaybeRefOrGetter<CollisionDetector>\" optional>\n  A custom collision detection algorithm.\n</ParamField>\n\n<ParamField path=\"disabled\" type=\"MaybeRefOrGetter<boolean>\" optional>\n  Whether the droppable is disabled.\n</ParamField>\n\n<ParamField path=\"data\" type=\"MaybeRefOrGetter<Data>\" optional>\n  Custom data to attach to this droppable instance.\n</ParamField>\n\n## Output\n\n<ResponseField name=\"isDropTarget\" type=\"ComputedRef<boolean>\">\n  Whether this element is currently a drop target (a draggable is hovering over it).\n</ResponseField>\n\n<ResponseField name=\"droppable\" type=\"ShallowReadonly<Ref<Droppable>>\">\n  The underlying `Droppable` instance.\n</ResponseField>\n\nexport const app = `\n<script setup>\nimport { ref } from 'vue';\nimport { DragDropProvider } from '@dnd-kit/vue';\nimport Draggable from './Draggable.vue';\nimport Droppable from './Droppable.vue';\nimport './styles.css';\n\nconst parent = ref(undefined);\n\nfunction onDragEnd(event) {\n  if (event.canceled) return;\n  parent.value = event.operation.target?.id;\n}\n</script>\n\n<template>\n  <DragDropProvider @dragEnd=\"onDragEnd\">\n    <div class=\"container\">\n      <Draggable v-if=\"parent == null\" />\n      <Droppable>\n        <Draggable v-if=\"parent === 'droppable'\" />\n      </Droppable>\n    </div>\n  </DragDropProvider>\n</template>\n`.trim();\n\nexport const draggableCode = `\n<script setup>\nimport { ref } from 'vue';\nimport { useDraggable } from '@dnd-kit/vue';\n\nconst element = ref(null);\nuseDraggable({ id: 'draggable', element });\n</script>\n\n<template>\n  <button ref=\"element\" class=\"btn\">draggable</button>\n</template>\n`.trim();\n\nexport const code = `\n<script setup>\nimport { ref } from 'vue';\nimport { useDroppable } from '@dnd-kit/vue';\n\nconst element = ref(null);\nconst { isDropTarget } = useDroppable({ id: 'droppable', element });\n</script>\n\n<template>\n  <div ref=\"element\" :class=\"['droppable', { active: isDropTarget }]\">\n    <slot />\n  </div>\n</template>\n`.trim();\n\nexport const containerStyles = `\n.container {\n  display: grid;\n  grid-template-columns: 2fr 1fr;\n  grid-gap: 20px;\n  align-items: center;\n  max-width: 700px;\n  margin: 0 auto;\n}\n`.trim();\n"
  },
  {
    "path": "apps/docs/vue/composables/use-sortable.mdx",
    "content": "---\ntitle: 'useSortable'\ndescription: 'Create sortable elements with the useSortable composable.'\nicon: 'layer-group'\n---\n\nimport {Story} from '/snippets/story.mdx';\nimport {CodeSandbox} from '/snippets/sandbox.mdx';\nimport {sortableStyles} from '/snippets/code.mdx';\n\n<Story id=\"sortable-vertical-list--basic-setup\" framework=\"vue\" height=\"320\" hero />\n\n## Usage\n\nThe `useSortable` composable combines draggable and droppable behavior with sorting logic. Import it from `@dnd-kit/vue/sortable`.\n\n<CodeSandbox template=\"vue\" files={{\n  'src/App.vue': {code: appCode, active: true},\n  'src/SortableItem.vue': {code: itemCode},\n  'src/styles.css': {code: sortableStyles, hidden: true},\n}} height={560} previewHeight={180} />\n\n\n<Note>\n  When passing props to `useSortable`, wrap reactive values in `computed()` to maintain reactivity. Plain values like `props.id` are read once during setup and won't update.\n</Note>\n\n## Without the move helper\n\nThe example above uses the `move` helper from `@dnd-kit/helpers`, a convenience function that takes your items and a drag event and returns a new array with the item moved to its new position. It supports flat arrays and grouped records, handles canceled drags, and works with optimistic sorting out of the box.\n\nIf you need more control over state updates, you can manage state manually using the `isSortable` type guard and the sortable properties (`initialIndex`, `index`).\n\nWith [optimistic sorting](/concepts/sortable#optimistic-sorting) enabled (the default), you only need to handle the `dragEnd` event:\n\n```vue\n<script setup>\nimport { ref } from 'vue';\nimport { DragDropProvider } from '@dnd-kit/vue';\nimport { isSortable } from '@dnd-kit/vue/sortable';\nimport SortableItem from './SortableItem.vue';\n\nconst items = ref([1, 2, 3, 4]);\n\nfunction onDragEnd(event) {\n  if (event.canceled) return;\n\n  const { source } = event.operation;\n\n  if (isSortable(source)) {\n    const { initialIndex, index } = source;\n\n    if (initialIndex !== index) {\n      const newItems = [...items.value];\n      const [removed] = newItems.splice(initialIndex, 1);\n      newItems.splice(index, 0, removed);\n      items.value = newItems;\n    }\n  }\n}\n</script>\n\n<template>\n  <DragDropProvider @dragEnd=\"onDragEnd\">\n    <ul class=\"list\">\n      <SortableItem\n        v-for=\"(id, index) in items\"\n        :key=\"id\"\n        :id=\"id\"\n        :index=\"index\"\n      />\n    </ul>\n  </DragDropProvider>\n</template>\n```\n\n<Tip>\n  You can call `event.preventDefault()` in a `@dragOver` handler to prevent the `OptimisticSortingPlugin` from optimistically updating for that specific event. This is useful when you want to conditionally block certain moves.\n</Tip>\n\n<Info>\n  Learn more about [optimistic sorting, type guards, and manual state management](/concepts/sortable#optimistic-sorting) in the Sortable concepts page.\n</Info>\n\n## Input\n\nAll input properties accept plain values or Vue refs/getters (`MaybeRefOrGetter`).\n\n<ParamField path=\"id\" type=\"MaybeRefOrGetter<UniqueIdentifier>\" required>\n  A unique identifier for this sortable instance.\n</ParamField>\n\n<ParamField path=\"index\" type=\"MaybeRefOrGetter<number>\" required>\n  The current index of this item in the sorted list.\n</ParamField>\n\n<ParamField path=\"element\" type=\"MaybeRefOrGetter<HTMLElement | null>\" required>\n  A template ref pointing to the sortable element.\n</ParamField>\n\n<ParamField path=\"group\" type=\"MaybeRefOrGetter<string>\" optional>\n  The group this sortable belongs to. Used for sorting across multiple lists.\n</ParamField>\n\n<ParamField path=\"handle\" type=\"MaybeRefOrGetter<HTMLElement | null>\" optional>\n  A template ref for a drag handle.\n</ParamField>\n\n<ParamField path=\"accept\" type=\"MaybeRefOrGetter<string | string[]>\" optional>\n  The types of draggable elements this sortable accepts.\n</ParamField>\n\n<ParamField path=\"type\" type=\"MaybeRefOrGetter<string>\" optional>\n  The type of this sortable element.\n</ParamField>\n\n<ParamField path=\"plugins\" type=\"MaybeRefOrGetter<PluginDescriptor[]>\" optional>\n  An array of plugin descriptors for per-entity plugin configuration. Use `Plugin.configure()` to create descriptors. For example, `Feedback.configure({ feedback: 'clone' })`.\n</ParamField>\n\n<ParamField path=\"transition\" type=\"MaybeRefOrGetter<SortableTransition>\" optional>\n  Animation transition configuration for sort operations.\n</ParamField>\n\n<ParamField path=\"modifiers\" type=\"MaybeRefOrGetter<Modifier[]>\" optional>\n  Modifiers to apply to this sortable instance.\n</ParamField>\n\n<ParamField path=\"sensors\" type=\"MaybeRefOrGetter<Sensor[]>\" optional>\n  Sensors to use for this sortable instance.\n</ParamField>\n\n<ParamField path=\"collisionDetector\" type=\"MaybeRefOrGetter<CollisionDetector>\" optional>\n  A custom collision detection algorithm.\n</ParamField>\n\n<ParamField path=\"collisionPriority\" type=\"MaybeRefOrGetter<number>\" optional>\n  The collision priority of this sortable element. Higher values take precedence when multiple droppable elements overlap.\n</ParamField>\n\n<ParamField path=\"disabled\" type=\"MaybeRefOrGetter<boolean>\" optional>\n  Whether the sortable is disabled.\n</ParamField>\n\n<ParamField path=\"data\" type=\"MaybeRefOrGetter<Data>\" optional>\n  Custom data to attach to this sortable instance.\n</ParamField>\n\n## Output\n\n<ResponseField name=\"isDragging\" type=\"ComputedRef<boolean>\">\n  Whether this element is currently being dragged.\n</ResponseField>\n\n<ResponseField name=\"isDropping\" type=\"ComputedRef<boolean>\">\n  Whether this element is in the process of being dropped.\n</ResponseField>\n\n<ResponseField name=\"isDragSource\" type=\"ComputedRef<boolean>\">\n  Whether this element is the source of the current drag operation.\n</ResponseField>\n\n<ResponseField name=\"isDropTarget\" type=\"ComputedRef<boolean>\">\n  Whether this element is currently a drop target.\n</ResponseField>\n\n<ResponseField name=\"sortable\" type=\"ShallowReadonly<Ref<Sortable>>\">\n  The underlying `Sortable` instance.\n</ResponseField>\n\nexport const itemCode = `\n<script setup>\nimport { ref, computed } from 'vue';\nimport { useSortable } from '@dnd-kit/vue/sortable';\n\nconst props = defineProps(['id', 'index']);\nconst element = ref(null);\nconst { isDragging } = useSortable({\n  id: computed(() => props.id),\n  index: computed(() => props.index),\n  element,\n});\n</script>\n\n<template>\n  <li ref=\"element\" class=\"item\">\n    Item {{ id }}\n  </li>\n</template>\n`.trim();\n\nexport const appCode = `\n<script setup>\nimport { ref } from 'vue';\nimport { DragDropProvider } from '@dnd-kit/vue';\nimport { move } from '@dnd-kit/helpers';\nimport SortableItem from './SortableItem.vue';\nimport './styles.css';\n\nconst items = ref([1, 2, 3, 4]);\n\nfunction onDragEnd(event) {\n  items.value = move(items.value, event);\n}\n</script>\n\n<template>\n  <DragDropProvider @dragEnd=\"onDragEnd\">\n    <ul class=\"list\">\n      <SortableItem\n        v-for=\"(id, index) in items\"\n        :key=\"id\"\n        :id=\"id\"\n        :index=\"index\"\n      />\n    </ul>\n  </DragDropProvider>\n</template>\n`.trim();\n"
  },
  {
    "path": "apps/docs/vue/quickstart.mdx",
    "content": "---\ntitle: 'Quickstart'\ndescription: 'Start building drag and drop interfaces with Vue in minutes.'\nicon: 'rocket'\n---\n\nimport {Story} from '/snippets/story.mdx';\nimport Intro from '/snippets/quickstart/intro.mdx';\n\n<Intro />\n\n## Overview\n\nThe `@dnd-kit/vue` package provides a set of Vue composables and components that you can use to build drag and drop interfaces. It is a thin Vue integration layer built on top of the [vanilla](/overview) library, so all of the same concepts are shared and can be used. You can refer to the vanilla documentation of these concepts, such as [plugins](/extend/plugins), [modifiers](/extend/modifiers), and [sensors](/extend/sensors).\n\n<Note>\n  `@dnd-kit/vue` requires Vue 3.5 or later.\n</Note>\n\n## Installation\nBefore getting started, make sure you install `@dnd-kit/vue` in your project:\n\n<CodeGroup>\n  ```bash npm\n  npm install @dnd-kit/vue\n  ```\n\n  ```bash yarn\n  yarn add @dnd-kit/vue\n  ```\n\n  ```bash pnpm\n  pnpm add @dnd-kit/vue\n  ```\n\n  ```bash bun\n  bun add @dnd-kit/vue\n  ```\n</CodeGroup>\n\n## Making elements draggable\n\nLet's get started by creating draggable elements that can be dropped over droppable targets. To do so, we'll be using the `useDraggable` composable.\n\nThe `useDraggable` composable requires a unique `id` and a template ref for the `element`. It returns reactive properties like `isDragging` that you can use in your template.\n\n```vue\n<script setup>\nimport {ref} from 'vue';\nimport {useDraggable} from '@dnd-kit/vue';\n\nconst element = ref(null);\nconst {isDragging} = useDraggable({id: 'draggable', element});\n</script>\n\n<template>\n  <button ref=\"element\">\n    Draggable\n  </button>\n</template>\n```\n\n## Creating droppable elements\n\nIn order for our draggable elements to have targets where they can be dropped, we need to create droppable elements. To do so, we'll be using the `useDroppable` composable.\n\nLike `useDraggable`, the `useDroppable` composable requires a unique `id` and an `element` ref.\n\n```vue Droppable.vue\n<script setup>\nimport {ref} from 'vue';\nimport {useDroppable} from '@dnd-kit/vue';\n\nconst element = ref(null);\nconst {isDropTarget} = useDroppable({id: 'droppable', element});\n</script>\n\n<template>\n  <div ref=\"element\" :style=\"{width: '300px', height: '300px'}\">\n    <slot />\n  </div>\n</template>\n```\n\n## Putting all the pieces together\n\nNow that we have both draggable and droppable elements, we can put them together to create a simple drag and drop interaction.\n\nWe'll be using the `DragDropProvider` component to wrap our draggable and droppable elements. This component handles the drag and drop interactions and allows us to listen to drag and drop events.\n\n<Note>\n  In Vue, composables like `useDraggable` and `useDroppable` must be called in a **child component** of `DragDropProvider`, not in the same component that renders the provider. This is because Vue's `provide`/`inject` requires the injection to be from an ancestor component.\n</Note>\n\n<CodeGroup>\n```vue App.vue\n<script setup>\nimport {ref} from 'vue';\nimport {DragDropProvider} from '@dnd-kit/vue';\nimport Draggable from './Draggable.vue';\nimport Droppable from './Droppable.vue';\n\nconst parent = ref(undefined);\n\nfunction onDragEnd(event) {\n  if (event.canceled) return;\n  parent.value = event.operation.target?.id;\n}\n</script>\n\n<template>\n  <DragDropProvider @dragEnd=\"onDragEnd\">\n    <Draggable v-if=\"parent == null\" />\n\n    <Droppable id=\"droppable\">\n      <Draggable v-if=\"parent === 'droppable'\" />\n    </Droppable>\n  </DragDropProvider>\n</template>\n```\n```vue Draggable.vue\n<script setup>\nimport {ref} from 'vue';\nimport {useDraggable} from '@dnd-kit/vue';\n\nconst element = ref(null);\nconst {isDragging} = useDraggable({id: 'draggable', element});\n</script>\n\n<template>\n  <button ref=\"element\">\n    Draggable\n  </button>\n</template>\n```\n```vue Droppable.vue\n<script setup>\nimport {ref} from 'vue';\nimport {useDroppable} from '@dnd-kit/vue';\n\nconst props = defineProps(['id']);\nconst element = ref(null);\nconst {isDropTarget} = useDroppable({\n  id: props.id,\n  element,\n});\n</script>\n\n<template>\n  <div ref=\"element\" :style=\"{width: '300px', height: '300px'}\">\n    <slot />\n  </div>\n</template>\n```\n</CodeGroup>\n\n## Next steps\n\nNow that you have a basic understanding of how to make elements draggable and droppable, you can explore the concepts covered in this quickstart guide in more detail:\n\n<CardGroup>\n  <Card title=\"DragDropProvider\" icon=\"sitemap\" href=\"/vue/components/drag-drop-provider\">\n    Create drag and drop contexts for your draggable and droppable elements.\n  </Card>\n\n  <Card title=\"useDraggable\" icon=\"bullseye-pointer\" href=\"/vue/composables/use-draggable\">\n    Learn how to make elements draggable with the `useDraggable` composable.\n  </Card>\n\n  <Card title=\"useDroppable\" icon=\"expand\" href=\"/vue/composables/use-droppable\">\n    Learn how to create droppable targets with the `useDroppable` composable.\n  </Card>\n\n  <Card title=\"useSortable\" icon=\"layer-group\" href=\"/vue/composables/use-sortable\">\n    Learn how to create sortable elements with the `useSortable` composable.\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "apps/stories/.eslintrc.js",
    "content": "module.exports = {\n  extends: ['@dnd-kit/eslint-config', 'plugin:storybook/recommended'],\n};\n"
  },
  {
    "path": "apps/stories/.storybook/main.ts",
    "content": "import {readFileSync} from 'fs';\nimport {dirname, join} from 'path';\nimport {mergeConfig} from 'vite';\n\nconst sharedPreviewHead = readFileSync(\n  join(__dirname, '..', '..', 'stories-shared', 'preview-head.html'),\n  'utf-8'\n);\n\nexport default {\n  previewHead: (head: string) => `${sharedPreviewHead}\\n${head}`,\n  stories: ['../stories/**/*.stories.mdx', '../stories/**/*.stories.tsx'],\n\n  addons: [\n    getAbsolutePath('@storybook/addon-links'),\n    getAbsolutePath('@vueless/storybook-dark-mode'),\n    getAbsolutePath(\"@storybook/addon-docs\"),\n    getAbsolutePath(\"@dnd-kit/storybook-addon-codesandbox\")\n  ],\n\n  framework: {\n    name: getAbsolutePath('@storybook/react-vite'),\n    options: {\n      strictMode: true,\n    },\n  },\n\n  refs: () => {\n    const refs: Record<string, {title: string; url: string}> = {};\n\n    if (process.env.VANILLA_STORYBOOK_URL) {\n      refs.vanilla = {title: 'Vanilla', url: process.env.VANILLA_STORYBOOK_URL};\n    }\n\n    if (process.env.VUE_STORYBOOK_URL) {\n      refs.vue = {title: 'Vue', url: process.env.VUE_STORYBOOK_URL};\n    }\n\n    if (process.env.SOLID_STORYBOOK_URL) {\n      refs.solid = {title: 'Solid', url: process.env.SOLID_STORYBOOK_URL};\n    }\n\n    if (process.env.SVELTE_STORYBOOK_URL) {\n      refs.svelte = {title: 'Svelte', url: process.env.SVELTE_STORYBOOK_URL};\n    }\n\n    return refs;\n  },\n\n  async viteFinal(config) {\n    // customize the Vite config here\n    return mergeConfig(config, {\n      define: {\n        'process.env': {},\n      },\n      optimizeDeps: {\n        exclude: ['@dnd-kit/*'],\n      },\n    });\n  }\n};\n\n/**\n * This function is used to resolve the absolute path of a package.\n * It is needed in projects that use Yarn PnP or are set up within a monorepo.\n */\nfunction getAbsolutePath(value) {\n  return dirname(require.resolve(join(value, 'package.json')));\n}\n"
  },
  {
    "path": "apps/stories/.storybook/manager-head.html",
    "content": "<link\n  rel=\"apple-touch-icon\"\n  sizes=\"180x180\"\n  href=\"/apple-touch-icon.png\"\n/>\n<link\n  rel=\"icon\"\n  type=\"image/png\"\n  sizes=\"32x32\"\n  href=\"/favicon-32x32.png\"\n/>\n<link\n  rel=\"icon\"\n  type=\"image/png\"\n  sizes=\"16x16\"\n  href=\"/favicon-16x16.png\"\n/>\n<link rel=\"shortcut icon\" href=\"/favicon.ico\">\n<style>\n  img[src*=\"dnd-kit-banner\"] {\n    width: 100%;\n    max-width: 200px;\n    margin-bottom: 10px;\n  }\n</style>\n"
  },
  {
    "path": "apps/stories/.storybook/manager.ts",
    "content": "import {addons} from 'storybook/manager-api';\nimport type {API_PreparedIndexEntry} from 'storybook/internal/types';\n\nimport {theme} from './theme';\n\naddons.setConfig({\n  theme,\n  showPanel: false,\n});\n\naddons.setConfig({\n  sidebar: {\n    filters: {\n      patterns: (\n        item: API_PreparedIndexEntry\n      ): boolean => {\n        return !(item.tags ?? []).includes('hidden');\n      },\n    },\n  },\n});\n"
  },
  {
    "path": "apps/stories/.storybook/preview-head.html",
    "content": "<style>\n  .css-qa4clq :where(h1:not(.sb-anchor, .sb-unstyled, .sb-unstyled h1)),\n  .css-qa4clq :where(h2:not(.sb-anchor, .sb-unstyled, .sb-unstyled h2)),\n  .css-qa4clq :where(h3:not(.sb-anchor, .sb-unstyled, .sb-unstyled h3)) {\n    font-family: var(--font-family) !important;\n  }\n\n  body.dark .sb-preparing-story {\n    background-color: #2a2c2e;\n  }\n\n  body.dark .sb-preparing-docs {\n    background-color: #222425;\n  }\n\n  body.dark .sb-previewBlock, body.dark .sb-argstableBlock[aria-hidden=\"true\"] {\n    filter: invert(0.9);\n  }\n\n  .dark .sbdocs {\n    background-color: #222425\n  }\n\n  .dark .sbdocs :is(h1, h2, h3, h4, h5, h6) {\n    color: rgba(255,255,255,0.98);\n  }\n\n  .dark .sbdocs :is(p, li) {\n    color: rgba(255,255,255,0.9);\n  }\n\n  .sbdocs h1 {\n    font-size: 40px !important;\n  }\n\n  .sbdocs h2 {\n    margin-top: 40px !important;\n    font-size: 30px !important;\n    border-bottom: none !important;\n  }\n\n  .sbdocs h3 {\n    font-size: 25px !important;\n    margin-top: 30px !important;\n    margin-bottom: 16px !important;\n  }\n\n  .sbdocs h4 {\n    font-size: 20px !important;\n  }\n\n  .sbdocs p, .sbdocs li {\n    font-size: 17px !important;\n    line-height: 30px !important;\n  }\n\n\n  .sbdocs h1 + p {\n    font-size: 20px !important;\n  }\n\n  button:not([class]) {\n    appearance: none;\n    cursor: grab;\n    background-color: #FFF;\n    color: #666;\n    padding: 12px 20px;\n    border: none;\n    border-radius: 5px;\n    font-size: 15px;\n    outline: none;\n    box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.10), inset 0 0 1px hsla(203, 50%, 30%, 0.5);\n    white-space: nowrap;\n  }\n\n  button:not([class]):hover {\n    background-color: #F9F9F9;\n  }\n\n  button:not([class]):focus-visible {\n    box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.10), inset 0 0 1px hsla(203, 50%, 30%, 0.5), inset 0 0 0 2px #4c9ffe;\n  }\n\n  a {\n    color: #3a58ed !important;\n  }\n\n  .dark a {\n    color: #8ea1ff !important;\n  }\n\n</style>\n"
  },
  {
    "path": "apps/stories/.storybook/preview.tsx",
    "content": "import React from 'react';\nimport {Unstyled} from '@storybook/addon-docs/blocks';\n\nimport '@dnd-kit/stories-shared/register';\nimport {Code} from '../stories/components';\nimport {\n  draggableStyles,\n  droppableStyles,\n  sortableStyles,\n  multipleListsStyles,\n} from '@dnd-kit/stories-shared/styles/sandbox';\nimport {withCodeSandbox} from '@dnd-kit/storybook-addon-codesandbox/decorator';\n\n// Inject sandbox-compatible CSS classes into Storybook so the Example\n// stories render identically to their CodeSandbox counterparts.\nif (typeof document !== 'undefined') {\n  const style = document.createElement('style');\n  style.setAttribute('data-sandbox-styles', '');\n  style.textContent = [draggableStyles, droppableStyles, sortableStyles, multipleListsStyles].join('\\n\\n');\n  document.head.appendChild(style);\n}\n\nconst preview = {\n  decorators: [withCodeSandbox],\n  parameters: {\n    docs: {\n      components: {\n        pre: (props) => (\n          <Unstyled>\n            <pre {...props} />\n          </Unstyled>\n        ),\n        code: Code,\n      },\n    },\n    codesandbox: {\n      dependencies: {\n        '@dnd-kit/abstract': 'beta',\n        '@dnd-kit/dom': 'beta',\n        '@dnd-kit/react': 'beta',\n        '@dnd-kit/helpers': 'beta',\n        '@dnd-kit/collision': 'beta',\n        'react': '^19.0.0',\n        'react-dom': '^19.0.0',\n      },\n      entry: [\n        \"import './styles.css';\",\n        \"import React from 'react';\",\n        \"import {createRoot} from 'react-dom/client';\",\n        \"import App from './App';\",\n        \"\",\n        \"createRoot(document.getElementById('root')).render(<App />);\",\n      ].join('\\n'),\n      mainFile: 'src/App.tsx',\n    },\n    darkMode: {\n      stylePreview: true,\n    },\n    options: {\n      storySort: {\n        order: [\n          'Docs',\n          'React',\n          [\n            'Draggable',\n            'Droppable',\n            'Sortable',\n            [\n              'Vertical list',\n              'Horizontal list',\n              'Grid',\n              'Multiple lists',\n              'Iframe',\n              'Virtualized',\n            ],\n          ],\n        ],\n      },\n    },\n  },\n};\n\nexport default preview;\n"
  },
  {
    "path": "apps/stories/.storybook/theme.ts",
    "content": "import {create} from 'storybook/theming/create';\nimport {default as brandImage} from './assets/dnd-kit-banner.svg';\n\nexport const theme = create({\n  base: 'light',\n  brandImage,\n  appBg: '#F9F9F9',\n});\n"
  },
  {
    "path": "apps/stories/package.json",
    "content": "{\n  \"name\": \"@dnd-kit/stories\",\n  \"version\": \"0.0.0\",\n  \"type\": \"module\",\n  \"private\": true,\n  \"scripts\": {\n    \"dev\": \"storybook dev -p 6006\",\n    \"build\": \"storybook build\",\n    \"preview-storybook\": \"serve storybook-static\",\n    \"clean\": \"rm -rf .turbo && rm -rf node_modules\",\n    \"lint\": \"eslint ./stories/*.stories.tsx --max-warnings 0\",\n    \"test:e2e\": \"playwright test\",\n    \"test:e2e:ui\": \"playwright test --ui\"\n  },\n  \"dependencies\": {\n    \"@dnd-kit/abstract\": \"*\",\n    \"@dnd-kit/dom\": \"*\",\n    \"@dnd-kit/react\": \"*\",\n    \"@dnd-kit/helpers\": \"*\",\n    \"@dnd-kit/stories-shared\": \"*\",\n    \"@dnd-kit/storybook-addon-codesandbox\": \"*\",\n    \"@tanstack/react-virtual\": \"^3.0.0-beta.54\",\n    \"clipboard\": \"^2.0.11\",\n    \"prismjs\": \"^1.29.0\",\n    \"react\": \"^19.0.0\",\n    \"react-dom\": \"^19.0.0\",\n    \"react-tiny-virtual-list\": \"^2.2.0\",\n    \"react-window\": \"1.8.9\"\n  },\n  \"devDependencies\": {\n    \"@dnd-kit/eslint-config\": \"*\",\n    \"@measured/auto-frame-component\": \"^0.1.7\",\n    \"@playwright/test\": \"^1.58.2\",\n    \"@storybook/addon-docs\": \"^9.0.15\",\n    \"@storybook/addon-links\": \"^9.0.15\",\n    \"@storybook/react-vite\": \"^9.0.15\",\n    \"@vitejs/plugin-react\": \"^4.2.1\",\n    \"@vueless/storybook-dark-mode\": \"^9.0.6\",\n    \"eslint\": \"^8.56.0\",\n    \"eslint-plugin-storybook\": \"9.0.15\",\n    \"http-server\": \"^14.1.1\",\n    \"serve\": \"^14.2.4\",\n    \"storybook\": \"^9.0.15\",\n    \"typescript\": \"^5.7.3\",\n    \"vite\": \"^6.0.0\"\n  }\n}\n"
  },
  {
    "path": "apps/stories/playwright.config.ts",
    "content": "import {defineConfig} from '@playwright/test';\n\nconst CI = !!process.env.CI;\n\nexport default defineConfig({\n  testDir: './tests',\n  timeout: 15_000,\n  expect: {\n    timeout: 5_000,\n  },\n  fullyParallel: true,\n  retries: CI ? 2 : 1,\n  reporter: CI ? 'html' : 'list',\n  use: {\n    baseURL: 'http://localhost:6006',\n    actionTimeout: 5_000,\n  },\n  projects: [\n    {\n      name: 'chromium',\n      use: {browserName: 'chromium'},\n    },\n  ],\n  webServer: {\n    command: 'npx http-server storybook-static --port 6006 --silent',\n    port: 6006,\n    reuseExistingServer: true,\n    timeout: 120_000,\n  },\n});\n"
  },
  {
    "path": "apps/stories/raw.d.ts",
    "content": "declare module '*.tsx?raw' {\n  const content: string;\n  export default content;\n}\n\ndeclare module '*.ts?raw' {\n  const content: string;\n  export default content;\n}\n"
  },
  {
    "path": "apps/stories/stories/components/docs/Code/Code.module.css",
    "content": ".Code {\n  --background-color: #263038;\n  --border-radius: 8px;\n  --border-color: transparent;\n  --box-shadow:  0 1px 3px 0 rgba(0, 0, 0, 0.10), inset 0 0 1px hsla(203, 50%, 30%, 0.5);\n\n  max-width: 100%;\n  margin: 30px 0;\n  border: 1px solid var(--border-color);\n  background-color: var(--background-color);\n  border-radius: var(--border-radius);\n  color: #fff;\n  box-shadow: var(--box-shadow);\n}\n\n.InlineCode {\n  padding: 0.4em 0.6em !important;\n  border-radius: 4px !important;\n  color: rgb(0,37,158) !important;\n  background-color: rgba(1,68,255,0.059) !important;\n}\n\n\n:global(.dark) .Code {\n  --background-color: #2a2c2e;\n  --border-color: rgba(255,255,255,0.1);\n  --box-shadow: none;\n}\n\n:global(.dark) .InlineCode {\n  color: rgb(135 163 255) !important;\n  background-color: #2a2c2e !important;\n  border-color: rgba(255,255,255,0.1);\n}\n\n.TabContent {\n  padding: 20px 0;\n  padding-right: 20px;\n  overflow: auto;\n}\n\n.Tabs {\n  display: flex;\n  overflow-x: auto;\n  background-color: #1e272d;\n}\n\n:global(.dark) .Tabs {\n  background-color: #222425;\n}\n\n.Tab {\n  background-color: transparent;\n  appearance: none;\n  outline: none;\n  border: 0;\n  color: #97999e;\n  padding: 20px;\n  font-family: \"Roboto Mono\",Consolas,\"Andale Mono WT\",\"Andale Mono\",\"Lucida Console\",\"Lucida Sans Typewriter\",\"DejaVu Sans Mono\",\"Bitstream Vera Sans Mono\",\"Liberation Mono\",\"Nimbus Mono L\",Monaco,\"Courier New\",Courier,monospace;\n\n  cursor: pointer;\n  font-size: 14px;\n  font-weight: 400;\n}\n\n.Tab[aria-selected=\"true\"] {\n  color: #fff;\n  background-color: var(--background-color);\n}\n"
  },
  {
    "path": "apps/stories/stories/components/docs/Code/Code.tsx",
    "content": "import React, {useState} from 'react';\nimport {Unstyled} from '@storybook/addon-docs/blocks';\n\nimport {CodeHighlighter} from './components';\nimport styles from './Code.module.css';\n\ninterface Props {\n  children: string | string[];\n  tabs?: string[];\n  className?: string;\n}\n\nexport function Code(props: Props) {\n  const {children, className} = props;\n  const [selectedTab, setSelectedTab] = useState(0);\n  const contents = Array.isArray(children) ? children[selectedTab] : children;\n\n  return Array.isArray(children) || children.includes('\\n') ? (\n    <Unstyled>\n      <div className={styles.Code}>\n        {props.tabs ? (\n          <div className={styles.Tabs} role=\"tablist\">\n            {props.tabs.map((tab, index) => (\n              <button\n                key={tab}\n                className={styles.Tab}\n                role=\"tab\"\n                aria-selected={index === selectedTab}\n                onClick={() => setSelectedTab(index)}\n              >\n                {tab}\n              </button>\n            ))}\n          </div>\n        ) : null}\n        <div className={styles.TabContent} role=\"tabpanel\">\n          <CodeHighlighter language={className?.replace('language-', '')}>\n            {contents}\n          </CodeHighlighter>\n        </div>\n      </div>\n    </Unstyled>\n  ) : (\n    <code className={styles.InlineCode}>{children}</code>\n  );\n}\n"
  },
  {
    "path": "apps/stories/stories/components/docs/Code/components/CodeHighlighter/CodeHighlighter.module.css",
    "content": "@import url('https://fonts.googleapis.com/css2?family=Roboto+Mono:wght@400&display=swap');\n\n:root {\n  --mono-font-stack: 'Roboto Mono', Consolas, 'Andale Mono WT', 'Andale Mono',\n    'Lucida Console', 'Lucida Sans Typewriter', 'DejaVu Sans Mono',\n    'Bitstream Vera Sans Mono', 'Liberation Mono', 'Nimbus Mono L', Monaco,\n    'Courier New', Courier, monospace;\n}\n\n.CodeHighlighter {\n  position: relative;\n  font-size: 0.9rem;\n}\n\n.CodeHighlighter > pre {\n  position: relative;\n  overflow-y: hidden;\n  overflow-x: auto;\n  display: flex;\n  margin: 0;\n  padding-left: 50px;\n  padding-right: 20px;\n}\n\n.CodeHighlighter code {\n  flex-shrink: 0;\n  -webkit-text-size-adjust: none;\n  text-rendering: optimizeLegibility;\n}\n\n.CodeHighlighter code,\n.LineNumbers {\n  font-weight: 400;\n  font-family: var(--mono-font-stack);\n}\n\n.Copy {\n  position: absolute;\n  top: -18px;\n  right: -10px;\n  padding: 16px;\n  outline: none;\n  appearance: none;\n  border: none;\n  background: var(--background-color);\n  cursor: pointer;\n}\n\n.Copy img {\n  opacity: 0.5;\n}\n\n.Copy:active {\n  cursor: pointer;\n}\n\n.Copy:hover img {\n  opacity: 1;\n}\n\n.LineNumbers {\n  position: absolute;\n  left: 20px;\n  color: rgba(255, 255, 255, 0.2);\n  font-weight: 300;\n  user-select: none;\n}\n\n.CodeHighlighter :global .tag .token.spread .attr-value {\n  color: #fff;\n}\n\n.CodeHighlighter :global .token.parameter {\n  color: orange;\n}\n\n.CodeHighlighter :global .keyword,\n.CodeHighlighter :global .operator,\n.CodeHighlighter :global .tag .script.language-javascript .punctuation:not(.parentheses),\n.CodeHighlighter :global .tag .token.spread .punctuation {\n  color: #eb2b78;\n}\n\n.CodeHighlighter :global .comment {\n  color: #959595;\n}\n\n.CodeHighlighter :global .keyword.function,\n.CodeHighlighter :global .keyword.const,\n.CodeHighlighter :global .class-name,\n.CodeHighlighter :global .operator.arrow-function {\n  color: #70dcee;\n}\n\n.CodeHighlighter :global .operator + .keyword,\n.CodeHighlighter :global .boolean,\n.CodeHighlighter :global .token.keyword.null,\n.CodeHighlighter :global .number,\n.CodeHighlighter :global .token.token.punctuation.braces,\n.CodeHighlighter :global .token.token.punctuation.braces + .token.punctuation.parentheses,\n.CodeHighlighter :global .token.token.punctuation.parentheses.opening + .token.punctuation.parentheses.opening,\n.CodeHighlighter :global .token.token.punctuation.parentheses + .token.parameter + .token.punctuation.parentheses  {\n  color: #fc8bf5;\n}\n\n.CodeHighlighter :global .string,\n.CodeHighlighter :global .tag .attr-value {\n  color: #fdf0a2;\n}\n\n.CodeHighlighter :global .token.function + .punctuation,\n.CodeHighlighter :global .script.language-javascript .token.punctuation.braces,\n.CodeHighlighter :global .token.punctuation.parentheses,\n.CodeHighlighter :global .token.function ~ .token.punctuation.parentheses,\n.CodeHighlighter :global .token.token.punctuation.parentheses + .token.parameter + .token.punctuation.parentheses:has(+ .token.braces.opening) {\n  color: #ffd602;\n}\n\n.CodeHighlighter :global .function,\n.CodeHighlighter :global .attr-name {\n  color: #4bff83;\n}\n\n.CodeHighlighter :global .punctuation,\n.CodeHighlighter :global .script.language-javascript .token.punctuation.semicolon,\n.CodeHighlighter :global .tag .script.language-javascript {\n  color: #f9f9f4;\n}\n\n.CodeHighlighter :global .tag {\n  color: #fa2b7d;\n}\n\n.CodeHighlighter :global .token.punctuation.parentheses:where(+ .semicolon) {\n  color: #ffd602 !important;\n}\n"
  },
  {
    "path": "apps/stories/stories/components/docs/Code/components/CodeHighlighter/CodeHighlighter.tsx",
    "content": "import React, {useEffect, useMemo, useRef} from 'react';\nimport Prism from 'prismjs';\nimport Clipboard from 'clipboard';\nimport 'prismjs/components/prism-jsx.min';\n\nimport copy from './copy.svg';\nimport styles from './CodeHighlighter.module.css';\nimport {classNames, createRange} from '@dnd-kit/stories-shared/utilities';\n\ninterface Props {\n  children: string;\n  language?: string;\n}\n\nexport function CodeHighlighter({children = '', language = 'jsx'}: Props) {\n  const lineCount = children.split('\\n').length - 1;\n  const nodeRef = useRef<HTMLButtonElement>(null);\n  const highlightedCode = useMemo(\n    () =>\n      syntaxReplacements(\n        Prism.highlight(\n          children.trim(),\n          Prism.languages[language] ?? Prism.languages.txt,\n          language\n        )\n      ),\n    [children]\n  );\n\n  useEffect(() => {\n    const clipboard = new Clipboard(nodeRef.current as Element);\n    return () => clipboard.destroy();\n  }, []);\n\n  return (\n    <div\n      className={classNames(styles.CodeHighlighter, 'sb-unstyled', language)}\n    >\n      <pre>\n        <div aria-hidden=\"true\" className={styles.LineNumbers}>\n          {lineCount > 1\n            ? createRange(lineCount).map((line) => (\n                <React.Fragment key={line}>\n                  {line}\n                  <br />\n                </React.Fragment>\n              ))\n            : null}\n        </div>\n        <code dangerouslySetInnerHTML={{__html: highlightedCode}} />\n      </pre>\n      <button\n        className={styles.Copy}\n        ref={nodeRef}\n        data-clipboard-text={children}\n      >\n        <img src={copy} width=\"19\" height=\"20\" alt=\"Copy\" />\n      </button>\n    </div>\n  );\n}\n\nfunction syntaxReplacements(value: string) {\n  const markup = (string, newAttribute = '') =>\n    `<span class=\"token ${newAttribute}\">${string}</span>`;\n  const replacements = [\n    ['const', 'token', 'const'],\n    ['null', 'token', 'null'],\n    ['function', 'token', 'function'],\n    ['[(]', 'punctuation', 'parentheses opening', '('],\n    ['[)]', 'punctuation', 'parentheses closing', ')'],\n    ['{', 'punctuation', 'braces opening'],\n    ['}', 'punctuation', 'braces closing'],\n    [';', 'punctuation', 'semicolon'],\n    ['=>', 'operator', 'arrow-function'],\n  ];\n\n  return replacements.reduce(\n    (accumulator, [value, label, annotation, replacement]) =>\n      accumulator.replace(\n        new RegExp(markup(value, label), 'g'),\n        markup(replacement ?? value, `${label} ${annotation}`)\n      ),\n    value\n  );\n}\n"
  },
  {
    "path": "apps/stories/stories/components/docs/Code/components/CodeHighlighter/index.ts",
    "content": "export {CodeHighlighter} from './CodeHighlighter';\n"
  },
  {
    "path": "apps/stories/stories/components/docs/Code/components/index.ts",
    "content": "export {CodeHighlighter} from './CodeHighlighter';\n"
  },
  {
    "path": "apps/stories/stories/components/docs/Code/index.ts",
    "content": "export {Code} from './Code';\n"
  },
  {
    "path": "apps/stories/stories/components/docs/Info/Info.module.css",
    "content": ".Info {\n  display: flex;\n  gap: 10px;\n  align-items: center;\n  justify-content: stretch;\n  padding: 16px 24px;\n  color: #333;\n  background-color: #f9f9f9;\n  border: 1px solid #57595a42;\n  border-radius: 10px;\n}\n\n:global(.dark) .Info {\n  background-color: #ffffff05;\n}\n\n.Info > p {\n  color: inherit;\n  margin: 0;\n}\n\n.Info > svg {\n  color: #2196F3;\n  width: 20px;\n  height: 20px;\n}\n"
  },
  {
    "path": "apps/stories/stories/components/docs/Info/Info.tsx",
    "content": "import React, {type PropsWithChildren} from 'react';\n\nimport styles from './Info.module.css';\n\nconst icon = (\n  <svg\n    width=\"15\"\n    height=\"15\"\n    viewBox=\"0 0 15 15\"\n    fill=\"none\"\n    xmlns=\"http://www.w3.org/2000/svg\"\n  >\n    <path\n      d=\"M7.49991 0.876892C3.84222 0.876892 0.877075 3.84204 0.877075 7.49972C0.877075 11.1574 3.84222 14.1226 7.49991 14.1226C11.1576 14.1226 14.1227 11.1574 14.1227 7.49972C14.1227 3.84204 11.1576 0.876892 7.49991 0.876892ZM1.82707 7.49972C1.82707 4.36671 4.36689 1.82689 7.49991 1.82689C10.6329 1.82689 13.1727 4.36671 13.1727 7.49972C13.1727 10.6327 10.6329 13.1726 7.49991 13.1726C4.36689 13.1726 1.82707 10.6327 1.82707 7.49972ZM8.24992 4.49999C8.24992 4.9142 7.91413 5.24999 7.49992 5.24999C7.08571 5.24999 6.74992 4.9142 6.74992 4.49999C6.74992 4.08577 7.08571 3.74999 7.49992 3.74999C7.91413 3.74999 8.24992 4.08577 8.24992 4.49999ZM6.00003 5.99999H6.50003H7.50003C7.77618 5.99999 8.00003 6.22384 8.00003 6.49999V9.99999H8.50003H9.00003V11H8.50003H7.50003H6.50003H6.00003V9.99999H6.50003H7.00003V6.99999H6.50003H6.00003V5.99999Z\"\n      fill=\"currentColor\"\n      fillRule=\"evenodd\"\n      clipRule=\"evenodd\"\n    ></path>\n  </svg>\n);\n\nexport function Info({children}: PropsWithChildren) {\n  return (\n    <div className={styles.Info}>\n      {icon}\n      <p>{children}</p>\n    </div>\n  );\n}\n"
  },
  {
    "path": "apps/stories/stories/components/docs/Info/index.ts",
    "content": "export {Info} from './Info';\n"
  },
  {
    "path": "apps/stories/stories/components/docs/Preview/Preview.module.css",
    "content": ".Preview {\n  --background-color: #FCFCFC;\n\n  overflow-y: auto;\n  padding: 30px 40px;\n  margin: 25px 0 40px;\n  border-radius: 8px;\n  box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.10), inset 0 0 1px hsla(203, 50%, 30%, 0.5);\n  background: var(--background-color);\n}\n\n.Preview:has( + .Code) {\n  border-bottom-left-radius: 0;\n  border-bottom-right-radius: 0;\n  margin-bottom: 0;\n}\n\n.Preview + .Code > div > div {\n  margin-top: 0px;\n  border-top-left-radius: 0;\n  border-top-right-radius: 0;\n}\n\n.hero {\n  position: relative;\n  --gradient: linear-gradient(65deg, #56fff420, #001AFF20, #5F6AF220, #F25FD020, #56FFF520, #F25FD020, #001AFF20, #56fff420);\n  display: grid;\n  align-items: center;\n  min-height: 200px;\n  max-height: 400px;\n  background-image: var(--gradient);\n  animation: gradient 16s linear infinite;\n  animation-direction: alternate;\n  background-size: 600% 100%;\n}\n\n.hero > * {\n  position: relative;\n  z-index: 1;\n}\n\n\n:global(.dark) .hero {\n  --gradient: linear-gradient(65deg, #56fff480, #001AFF80, #5F6AF280, #F25FD080, #56FFF580, #F25FD080, #001AFF80, #56fff480);\n\n  animation: background 16s linear infinite, gradient 60s linear infinite;\n}\n\n:global(.dark) .Preview {\n  --background-color: #38393c;\n}\n\n@keyframes background {\n  0% {\n    background-color: #ff0000;\n  }\n  25% {\n    background-color: #7f00ff;\n  }\n  50% {\n    background-color: #00affa;\n  }\n  75% {\n    background-color: #00f594;\n  }\n  100% {\n    background-color: #ff0000\n  }\n}\n\n\n@keyframes gradient {\n  0% {background-position: 0%}\n  100% {background-position: 100%}\n}\n\n"
  },
  {
    "path": "apps/stories/stories/components/docs/Preview/Preview.tsx",
    "content": "import React from 'react';\nimport {Story, Unstyled} from '@storybook/addon-docs/blocks';\nimport {type StoryFn} from '@storybook/react';\n\nimport {classNames} from '@dnd-kit/stories-shared/utilities';\nimport {Code} from '../Code';\nimport styles from './Preview.module.css';\n\ninterface Props {\n  of?: StoryFn;\n  code?: string;\n  id?: string;\n  hero?: boolean;\n  tabs?: string[];\n  children?: React.ReactNode;\n}\n\nexport function Preview({children, code, of, hero, id, tabs}: Props) {\n  return (\n    <Unstyled>\n      <div\n        className={classNames(\n          styles.Preview,\n          hero && styles.hero,\n          hero && 'hero'\n        )}\n        id={id}\n      >\n        {children ?? <Story of={of} />}\n      </div>\n      {code ? (\n        <div className={styles.Code}>\n          <Code tabs={tabs}>{code}</Code>\n        </div>\n      ) : null}\n    </Unstyled>\n  );\n}\n"
  },
  {
    "path": "apps/stories/stories/components/docs/Preview/index.ts",
    "content": "export {Preview} from './Preview';\n"
  },
  {
    "path": "apps/stories/stories/components/docs/index.ts",
    "content": "export {Code} from './Code';\nexport {Info} from './Info';\nexport {Preview} from './Preview';\n"
  },
  {
    "path": "apps/stories/stories/components/index.ts",
    "content": "export {Code, Info, Preview} from './docs';\n"
  },
  {
    "path": "apps/stories/stories/react/Draggable/DragHandles/DragHandles.stories.tsx",
    "content": "import type {Meta, StoryObj} from '@storybook/react-vite';\n\nimport docs from './docs/DragHandles.mdx';\nimport {DraggableExample} from '../DraggableExample.tsx';\nimport {PointerSensor, KeyboardSensor} from '@dnd-kit/dom';\n\nconst meta: Meta<typeof DraggableExample> = {\n  title: 'React/Draggable/Drag handles',\n  component: DraggableExample,\n  tags: ['autodocs'],\n  parameters: {\n    docs: {\n      page: docs,\n    },\n  },\n};\n\nexport default meta;\ntype Story = StoryObj<typeof DraggableExample>;\n\nexport const DragHandle: Story = {\n  name: 'Example',\n  args: {\n    handle: true,\n  },\n};\n\nexport const DualActivators: Story = {\n  name: 'Dual activators',\n  args: {\n    handle: true,\n    sensors: [\n      PointerSensor.configure({\n        activatorElements(source) {\n          return [source.handle, source.element];\n        },\n      }),\n      KeyboardSensor,\n    ],\n  },\n};\n"
  },
  {
    "path": "apps/stories/stories/react/Draggable/DragHandles/docs/DragHandles.mdx",
    "content": "import {RestrictToElement} from '@dnd-kit/dom/modifiers';\n\nimport {Info, Preview} from '../../../../components';\nimport {DragHandle} from '../DragHandles.stories.tsx';\n\n# Drag handles\n\nRestrict dragging to a specific element within a draggable element.\n\n<Preview id=\"modifier-hero\" hero of={DragHandle} />\n\n## Usage\n\nTo create a drag handle, provide a `handle` element to the `useDraggable` hook by consuming the `handleRef` from the output object of the `useDraggable` hook.\n\n```jsx\nimport {useDraggable} from '@dnd-kit/react';\n\nfunction Draggable(props) {\n  const {handleRef, ref} = useDraggable({\n    id: props.id,\n  });\n\n  return (\n    <div ref={ref}>\n      {props.children}\n      <button ref={handleRef}>Drag handle</button>\n    </div>\n  );\n}\n```\n\nAlternatively, you can also pass an `Element` or `ref` to an element as an argument to the `handle` option of `useDraggable`:\n\n```jsx\nimport {useDraggable} from '@dnd-kit/react';\n\nfunction Draggable(props) {\n  const handleRef = useRef(null);\n  const {ref} = useDraggable({\n    id: props.id,\n    handle: handleRef,\n  });\n\n  return (\n    <div ref={ref}>\n      {props.children}\n      <button ref={handle}>Drag handle</button>\n    </div>\n  );\n}\n```\n"
  },
  {
    "path": "apps/stories/stories/react/Draggable/DragOverlay/DragOverlay.stories.tsx",
    "content": "import type {Meta, StoryObj} from '@storybook/react-vite';\n\nimport {DraggableExample} from '../DraggableExample.tsx';\n\nconst meta: Meta<typeof DraggableExample> = {\n  title: 'React/Draggable/Drag overlay',\n  component: DraggableExample,\n};\n\nexport default meta;\ntype Story = StoryObj<typeof DraggableExample>;\n\nexport const DragOverlay: Story = {\n  name: 'Example',\n  args: {\n    overlay: true,\n  },\n};\n"
  },
  {
    "path": "apps/stories/stories/react/Draggable/Draggable.stories.tsx",
    "content": "import type {Meta, StoryObj} from '@storybook/react-vite';\n\nimport DraggableApp from './DraggableApp.tsx';\nimport draggableSource from './DraggableApp.tsx?raw';\nimport {baseStyles, draggableStyles} from '@dnd-kit/stories-shared/styles/sandbox';\nimport docs from './docs/DraggableDocs.mdx';\n\nconst meta: Meta<typeof DraggableApp> = {\n  title: 'React/Draggable',\n  component: DraggableApp,\n  tags: ['autodocs'],\n  parameters: {\n    docs: {\n      page: docs,\n    },\n    codesandbox: {\n      files: {\n        'src/App.tsx': draggableSource,\n        'src/styles.css': [baseStyles, draggableStyles].join('\\n\\n'),\n      },\n    },\n  },\n};\n\nexport default meta;\ntype Story = StoryObj<typeof DraggableApp>;\n\nexport const Example: Story = {\n  name: 'Example',\n};\n"
  },
  {
    "path": "apps/stories/stories/react/Draggable/DraggableApp.tsx",
    "content": "import React from 'react';\nimport {DragDropProvider, useDraggable} from '@dnd-kit/react';\n\nfunction Draggable() {\n  const {ref} = useDraggable({id: 'draggable'});\n\n  return <button ref={ref} className=\"btn\">draggable</button>;\n}\n\nexport default function App() {\n  return (\n    <DragDropProvider>\n      <Draggable />\n    </DragDropProvider>\n  );\n}\n"
  },
  {
    "path": "apps/stories/stories/react/Draggable/DraggableExample.tsx",
    "content": "import React, {\n  type PropsWithChildren,\n  type CSSProperties,\n  useRef,\n  useState,\n} from 'react';\nimport type {Modifiers, Plugins, Sensors} from '@dnd-kit/abstract';\nimport {DragDropProvider, DragOverlay, useDraggable} from '@dnd-kit/react';\n\nimport {Button, Handle} from '../components';\n\ninterface Props {\n  container?: React.FC<PropsWithChildren<{}>> | string;\n  handle?: boolean;\n  overlay?: boolean;\n  modifiers?: Modifiers;\n  sensors?: Sensors;\n}\n\nexport function DraggableExample(props: Props) {\n  const {container, overlay, sensors} = props;\n  const Wrapper = container ?? 'div';\n\n  return (\n    <DragDropProvider sensors={sensors}>\n      <Wrapper>\n        <Draggable id=\"draggable\" {...props} />\n        {overlay && (\n          <DragOverlay>\n            <Button shadow style={{width: '100%'}}>\n              overlay\n              <Handle variant=\"dark\" />\n            </Button>\n          </DragOverlay>\n        )}\n      </Wrapper>\n    </DragDropProvider>\n  );\n}\n\ninterface DraggableProps {\n  id: string;\n  handle?: boolean;\n  plugins?: Plugins;\n  modifiers?: Modifiers;\n  style?: CSSProperties;\n  overlay?: boolean;\n}\n\nexport function Draggable({\n  id,\n  modifiers,\n  handle,\n  plugins,\n  style,\n  overlay,\n}: DraggableProps) {\n  const [element, setElement] = useState<Element | null>(null);\n  const handleRef = useRef<HTMLButtonElement | null>(null);\n\n  const {isDragging} = useDraggable({\n    id,\n    modifiers,\n    element,\n    plugins,\n    handle: handleRef,\n  });\n\n  return (\n    <Button\n      ref={setElement}\n      actions={handle ? <Handle ref={handleRef} variant=\"dark\" /> : undefined}\n      disabled={isDragging && overlay}\n      shadow={isDragging && !overlay}\n      style={style}\n    >\n      draggable\n    </Button>\n  );\n}\n"
  },
  {
    "path": "apps/stories/stories/react/Draggable/Modifiers/Modifiers.stories.tsx",
    "content": "import type {Meta, StoryObj} from '@storybook/react-vite';\nimport {\n  RestrictToHorizontalAxis,\n  RestrictToVerticalAxis,\n} from '@dnd-kit/abstract/modifiers';\nimport {RestrictToElement, RestrictToWindow} from '@dnd-kit/dom/modifiers';\n\nimport docs from './docs/ModifierDocs.mdx';\nimport {DraggableExample} from '../DraggableExample';\nimport {SnapToGridExample} from './SnapToGridExample';\nimport styles from './styles.module.css';\n\nconst meta: Meta<typeof DraggableExample> = {\n  title: 'React/Draggable/Modifiers',\n  component: DraggableExample,\n  tags: ['autodocs'],\n  parameters: {\n    docs: {\n      page: docs,\n    },\n  },\n};\n\nexport default meta;\ntype Story = StoryObj<typeof DraggableExample>;\n\nexport const VerticalAxis: Story = {\n  name: 'Vertical axis',\n  args: {\n    modifiers: [RestrictToVerticalAxis],\n  },\n};\n\nexport const HorizontalAxis: Story = {\n  name: 'Horizontal axis',\n  args: {\n    modifiers: [RestrictToHorizontalAxis],\n  },\n};\n\nexport const WindowModifier: Story = {\n  name: 'Restrict to window',\n  args: {\n    modifiers: [RestrictToWindow],\n  },\n};\n\nexport const ContainerModifier: Story = {\n  name: 'Restrict to container',\n  args: {\n    container({children}) {\n      return (\n        <div className={styles.Container} data-container>\n          {children}\n        </div>\n      );\n    },\n    modifiers: [\n      RestrictToElement.configure({\n        element() {\n          return document.querySelector('[data-container]');\n        },\n      }),\n    ],\n  },\n};\n\nexport const SnapModifierExample: Story = {\n  name: 'Snap to grid',\n  render: SnapToGridExample,\n};\n"
  },
  {
    "path": "apps/stories/stories/react/Draggable/Modifiers/SnapToGridExample.tsx",
    "content": "import {useState} from 'react';\nimport {RestrictToWindow} from '@dnd-kit/dom/modifiers';\nimport {SnapModifier} from '@dnd-kit/abstract/modifiers';\nimport {DragDropProvider} from '@dnd-kit/react';\n\nimport {Grid} from '../../components/index.ts';\nimport {Draggable} from '../DraggableExample.tsx';\n\nexport function SnapToGridExample() {\n  const [gridSize, setGridSize] = useState(30);\n  const [position, setPosition] = useState({x: gridSize, y: gridSize});\n\n  return (\n    <DragDropProvider\n      onDragEnd={(event) => {\n        setPosition(({x, y}) => ({\n          x: x + event.operation.transform.x,\n          y: y + event.operation.transform.y,\n        }));\n      }}\n    >\n      <Grid size={gridSize}>\n        <Draggable\n          id=\"draggable\"\n          modifiers={[\n            SnapModifier.configure({size: gridSize}),\n            RestrictToWindow,\n          ]}\n          style={{translate: `${position.x}px ${position.y}px`}}\n        />\n      </Grid>\n      <label\n        style={{\n          position: 'absolute',\n          bottom: 0,\n          right: 0,\n          padding: 15,\n          background: 'rgba(255, 255, 255, 0.5)',\n        }}\n      >\n        Grid size\n        <br />\n        <input\n          type=\"range\"\n          min=\"10\"\n          max=\"60\"\n          onChange={(e) => {\n            const gridSize = parseInt(e.target.value, 10);\n\n            setGridSize(gridSize);\n            setPosition({\n              x: gridSize,\n              y: gridSize,\n            });\n          }}\n        />\n      </label>\n    </DragDropProvider>\n  );\n}\n"
  },
  {
    "path": "apps/stories/stories/react/Draggable/Modifiers/docs/ModifierDocs.mdx",
    "content": "import {RestrictToElement} from '@dnd-kit/dom/modifiers';\n\nimport {Info, Preview} from '../../../../components';\nimport {DraggableExample} from '../../DraggableExample';\n\n# Modifiers\n\nModify or restrict the behavior of draggable elements.\n\n<Preview id=\"modifier-hero\" hero>\n  <DraggableExample\n    modifiers={[\n      RestrictToElement.configure({\n        element() {\n          return document.getElementById('modifier-hero');\n        },\n      }),\n    ]}\n  />\n</Preview>\n\nModifiers let you dynamically modify the movement coordinates that are detected by sensors. They can be used for a wide range of use cases, for example:\n\n- Restricting motion to a single axis\n- Restricting motion to the draggable node container's bounding rectangle\n- Restricting motion to the draggable node's scroll container bounding rectangle\n- Applying resistance or clamping the motion\n\n## Usage\n\nModifiers can be applied globally or to individual draggable elements.\n\n### Global modifiers\n\nModifiers can be applied globally by passing them to the `<DragDropProvider>` component.\n\n```jsx\nimport {DragDropProvider} from '@dnd-kit/react';\nimport {RestrictToVerticalAxis} from '@dnd-kit/abstract/modifiers';\nimport {RestrictToWindow} from '@dnd-kit/dom/modifiers';\n\nfunction App() {\n  return (\n    <DragDropProvider modifiers={[RestrictToWindow, RestrictToVerticalAxis]}>\n      {...}\n    </DragDropProvider>\n  )\n}\n```\n\n### Local modifiers\n\n<Info>Local modifiers take precedence over global modifiers.</Info>\n\nModifiers can also be applied to individual draggable elements by passing them to the `modifiers` prop.\n\n```jsx\nimport {useDraggable} from '@dnd-kit/react';\nimport {RestrictToVerticalAxis} from '@dnd-kit/abstract/modifiers';\nimport {RestrictToWindow} from '@dnd-kit/dom/modifiers';\n\nfunction Draggable({id}) {\n  const {ref} = useDraggable({\n    id,\n    modifiers: [RestrictToVerticalAxis, RestrictToWindow],\n  });\n}\n```\n"
  },
  {
    "path": "apps/stories/stories/react/Draggable/Modifiers/styles.module.css",
    "content": ".Container {\n  display: flex;\n  width: 60%;\n  min-width: 300px;\n  margin: 40px 80px;\n  height: 350px;\n  outline: 3px solid rgba(0,0,0,0.2);\n  background: #FFF;\n  align-items: center;\n  justify-content: center;\n  padding: 30px;\n  border-radius: 8px;\n}\n\n:global(.dark) .Container {\n  outline: 1px solid rgba(255,255,255,0.3);\n  background: rgba(255,255,255,0.05);\n}\n"
  },
  {
    "path": "apps/stories/stories/react/Draggable/Sensors/Sensors.stories.tsx",
    "content": "import type {Meta, StoryObj} from '@storybook/react-vite';\n\nimport docs from './docs/SensorDocs.mdx';\nimport {DraggableExample} from '../DraggableExample';\n\nconst meta: Meta<typeof DraggableExample> = {\n  title: 'React/Draggable/Sensors',\n  component: DraggableExample,\n  tags: ['autodocs'],\n  parameters: {\n    docs: {\n      page: docs,\n    },\n  },\n};\n\nexport default meta;\ntype Story = StoryObj<typeof DraggableExample>;\n\nexport const Pointer: Story = {\n  name: 'Default sensors',\n};\n"
  },
  {
    "path": "apps/stories/stories/react/Draggable/Sensors/docs/SensorDocs.mdx",
    "content": "import {Info, Preview} from '../../../../components';\nimport {DraggableExample} from '../../DraggableExample';\n\n# Sensors\n\nDetect user input and translate them into drag operations.\n\n## Overview\n\nSensors are an abstraction to detect different input methods in order to initiate drag operations, respond to movement and end or cancel the operation.\n\n## Built-in sensors\n\nThe `@dnd-kit/dom` package provides built-in sensors that can be used to detect user input in the browser.\n\n### Pointer sensor\n\nThe Pointer sensor responds to [Pointer events](https://developer.mozilla.org/en-US/docs/Web/API/Pointer_events). This sensor is enabled by default.\n\n> Pointer events are DOM events that are fired for a pointing device. They are designed to create a single DOM event model to handle pointing input devices such as a mouse, pen/stylus or touch (such as one or more fingers).\n> The pointer is a hardware-agnostic device that can target a specific set of screen coordinates.\n>\n> – Source: [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Pointer_events)\n\n#### Activation constraints\n\nThe Pointer sensor has two types of activation constraints:\n\n- Distance constraint\n- Delay constraint\n\nThese activation constraints are not mutually exclusive, they can be used simultaneously. In case both constraints are used, the Pointer sensor will activate as soon as one of the constraints is met.\n\n```js\nimport {PointerSensor, PointerActivationConstraints} from '@dnd-kit/dom';\n\nconst sensors = [\n  PointerSensor.configure({\n    activationConstraints: [\n      new PointerActivationConstraints.Delay({value: 200, tolerance: 10}),\n      new PointerActivationConstraints.Distance({value: 5}),\n    ],\n  }),\n];\n```\n\nThe **distance** `value` property represents the distance, in _pixels_, that a pointer needs to be moved by before a drag operation is initiated.\n\nThe **delay** `value` property represents the duration, in _milliseconds_, that a draggable item needs to be held by the primary pointer for before a drag start event is emitted.\n\nThe `tolerance` property represents the distance, in pixels, of motion that is tolerated before the drag operation is aborted. If the pointer is moved during the delay duration and the tolerance is set to zero, the drag operation will be immediately aborted. If a higher tolerance is set, for example, a tolerance of 5 pixels, the operation will only be aborted if the pointer is moved by more than 5 pixels during the delay.\n\nThis property is particularly useful for touch input, where some tolerance should be accounted for when using a delay constraint, as touch input is less precise than mouse input.\n\n#### Default behavior\n\nBy default, the `PointerSensor` applies sensible activation constraints depending on the context:\n\n- Mouse on handle: activates immediately.\n- Touch: `Delay({value: 250, tolerance: 5})`.\n- Text inputs: `Delay({value: 200, tolerance: 0})`.\n- Other cases: `Delay({value: 200, tolerance: 10})` and `Distance({value: 5})`.\n\nYou can override this with `activationConstraints`, which may be an array of constraints or a function `(event, source) => ActivationConstraints | undefined` to compute them per interaction.\n\n```js\nimport {PointerSensor, PointerActivationConstraints} from '@dnd-kit/dom';\n\nPointerSensor.configure({\n  activationConstraints(event, source) {\n    if (event.pointerType === 'touch') {\n      return [\n        new PointerActivationConstraints.Delay({value: 300, tolerance: 8}),\n      ];\n    }\n    return [new PointerActivationConstraints.Distance({value: 6})];\n  },\n});\n```\n\n#### Activator elements\n\nYou may specify additional elements that can start a pointer interaction via `activatorElements`:\n\n```js\nimport {PointerSensor} from '@dnd-kit/dom';\n\nPointerSensor.configure({\n  activatorElements(source) {\n    return [\n      source.handle,\n      document.querySelector('[data-dnd-activator]'),\n    ];\n  },\n});\n```\n\n### Keyboard sensor\n\nThe Keyboard sensor responds to [Keyboard events](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent). This sensor is enabled by default.\n\nThe keyboard sensor activates when the `handle` or `element` of a draggable source is focused and the `Space` or `Enter` key is pressed.\n\n#### Configuration\n\nThe Keyboard sensor can be configured to respond to different keyboard codes:\n\n```js\nimport {KeyboardSensor} from '@dnd-kit/dom';\n\nconst sensors = [\n  KeyboardSensor.configure({\n    keyboardCodes: {\n      start: ['Space', 'Enter'],\n      cancel: ['Escape'],\n      end: ['Space', 'Enter'],\n      up: ['ArrowUp'],\n      down: ['ArrowDown'],\n      left: ['ArrowLeft'],\n      right: ['ArrowRight'],\n    },\n  }),\n];\n```\n\nYou may customize these values, but do keep in mind that the [third rule of ARIA](https://www.w3.org/TR/using-aria/#3rdrule) requires that a user must be able to activate the action associated with a draggable widget using both the enter (on Windows) or return (on macOS) and the space key. To learn more, read the in-depth accessibility guide.\n\n## Usage\n\nSensors can be applied globally or to individual draggable elements.\n\n### Global sensors\n\nSensors can be applied globally by passing them to the `<DragDropProvider>` component.\n\n```jsx\nimport {DragDropProvider} from '@dnd-kit/react';\nimport {PointerSensor, KeyboardSensor} from '@dnd-kit/dom';\n\nfunction App() {\n  return (\n    <DragDropProvider sensors={[PointerSensor, KeyboardSensor]}>\n      {...}\n    </DragDropProvider>\n  )\n}\n```\n\n### Local sensors\n\n<Info>Local sensors take precedence over global sensors.</Info>\n\nSensors can also be applied to individual draggable elements by passing them to the `sensors` prop.\n\n```jsx\nimport {useDraggable} from '@dnd-kit/react';\nimport {KeyboardSensor} from '@dnd-kit/dom';\n\nfunction Draggable({id}) {\n  const {ref} = useDraggable({\n    id,\n    sensors: [KeyboardSensor],\n  });\n}\n```\n"
  },
  {
    "path": "apps/stories/stories/react/Draggable/docs/DraggableDocs.mdx",
    "content": "import {Preview} from '../../../components';\nimport {Example as Hero} from '../Draggable.stories';\nimport {Example} from './examples/QuickStart';\nimport ExampleSource from './examples/QuickStart?raw';\nimport DraggableSource from './examples/Draggable?raw';\nimport {Example as MultipleDraggableExample} from './examples/MultipleDraggable';\nimport MultipleDraggableExampleSource from './examples/MultipleDraggable?raw';\n\n# Draggable\n\nMake elements draggable and drop them over targets.\n\n<Preview of={Hero} hero />\n\n## Usage\n\nUse the `useDraggable` hook to create draggable elements that `draggable` elements can be dropped over `droppable` targets.\n\n```jsx\nimport {useDraggable} from '@dnd-kit/react';\n\nfunction Draggable(props) {\n  const {ref} = useDraggable({\n    id: props.id,\n  });\n\n  return <button ref={ref}>{props.children}</button>;\n}\n```\n\n## Getting started\n\nTo get started, we will create two files, `App.js` and `Draggable.js`.\n\n<Preview\n  code={[ExampleSource, DraggableSource]}\n  tabs={['App.js', 'Draggable.js']}\n>\n  <Example />\n</Preview>\n\nTo render multiple draggable elements, we can simply render the `<Draggable>` component multiple times:\n\n<Preview code={[MultipleDraggableExampleSource]} tabs={['App.js']}>\n  <MultipleDraggableExample />\n</Preview>\n"
  },
  {
    "path": "apps/stories/stories/react/Draggable/docs/examples/Draggable.jsx",
    "content": "import React from 'react';\nimport {useDraggable} from '@dnd-kit/react';\n\nexport function Draggable({id}) {\n  const {ref} = useDraggable({\n    id,\n  });\n\n  return (\n    <button ref={ref}>\n      Draggable\n    </button>\n  );\n}\n"
  },
  {
    "path": "apps/stories/stories/react/Draggable/docs/examples/MultipleDraggable.jsx",
    "content": "import React from 'react';\nimport {DragDropProvider} from '@dnd-kit/react';\n\nimport {Draggable} from './Draggable';\n\nexport function Example() {\n  return (\n    <DragDropProvider>\n      <div style={{display: 'inline-flex', flexDirection: 'row', gap: 20}}>\n        <Draggable id=\"draggable-1\" />\n        <Draggable id=\"draggable-2\" />\n        <Draggable id=\"draggable-3\" />\n      </div>\n    </DragDropProvider>\n  );\n}\n"
  },
  {
    "path": "apps/stories/stories/react/Draggable/docs/examples/QuickStart.jsx",
    "content": "import React from 'react';\nimport {DragDropProvider} from '@dnd-kit/react';\n\nimport {Draggable} from './Draggable';\n\nexport function Example() {\n  return (\n    <DragDropProvider>\n      <Draggable id=\"draggable\" />\n    </DragDropProvider>\n  );\n}\n"
  },
  {
    "path": "apps/stories/stories/react/Droppable/Droppable.stories.tsx",
    "content": "import type {Meta, StoryObj} from '@storybook/react-vite';\n\nimport DroppableApp from './DroppableApp.tsx';\nimport droppableSource from './DroppableApp.tsx?raw';\nimport {baseStyles, draggableStyles, droppableStyles} from '@dnd-kit/stories-shared/styles/sandbox';\nimport docs from './docs/DroppableDocs.mdx';\n\nconst meta: Meta<typeof DroppableApp> = {\n  title: 'React/Droppable',\n  component: DroppableApp,\n  tags: ['autodocs'],\n  parameters: {\n    docs: {\n      page: docs,\n    },\n    codesandbox: {\n      files: {\n        'src/App.tsx': droppableSource,\n        'src/styles.css': [baseStyles, draggableStyles, droppableStyles].join('\\n\\n'),\n      },\n    },\n  },\n};\n\nexport default meta;\ntype Story = StoryObj<typeof DroppableApp>;\n\nexport const Example: Story = {\n  name: 'Example',\n};\n"
  },
  {
    "path": "apps/stories/stories/react/Droppable/DroppableApp.tsx",
    "content": "import React, {useState} from 'react';\nimport {DragDropProvider, useDraggable, useDroppable} from '@dnd-kit/react';\n\nfunction Draggable({id}: {id: string}) {\n  const {ref} = useDraggable({id});\n\n  return <button ref={ref} className=\"btn\">draggable</button>;\n}\n\nfunction Droppable({id, children}: {id: string; children?: React.ReactNode}) {\n  const {ref, isDropTarget} = useDroppable({id});\n\n  return (\n    <div ref={ref} className={isDropTarget ? \"droppable active\" : \"droppable\"}>\n      {children}\n    </div>\n  );\n}\n\nexport default function App() {\n  const [parent, setParent] = useState<string | undefined>(undefined);\n  const draggable = <Draggable id=\"draggable\" />;\n\n  return (\n    <DragDropProvider\n      onDragEnd={(event) => {\n        if (event.canceled) return;\n        setParent(event.operation.target?.id as string);\n      }}\n    >\n      <section className=\"drop-layout\">\n        {parent == null ? draggable : null}\n        <Droppable id=\"droppable\">\n          {parent === 'droppable' ? draggable : null}\n        </Droppable>\n      </section>\n    </DragDropProvider>\n  );\n}\n"
  },
  {
    "path": "apps/stories/stories/react/Droppable/DroppableExample.tsx",
    "content": "import React, {useState} from 'react';\nimport type {PropsWithChildren} from 'react';\nimport type {UniqueIdentifier} from '@dnd-kit/abstract';\nimport {DragDropProvider, useDraggable, useDroppable} from '@dnd-kit/react';\nimport {Debug} from '@dnd-kit/dom/plugins/debug';\n\nimport {createRange} from '@dnd-kit/stories-shared/utilities';\nimport {Button} from '../components/Button/Button.tsx';\nimport {Dropzone} from '../components/Dropzone/Dropzone.tsx';\n\ninterface Props {\n  droppableCount?: number;\n  debug?: boolean;\n}\n\nexport function DroppableExample({droppableCount = 1, debug}: Props) {\n  const [parent, setParent] = useState<UniqueIdentifier | undefined>();\n  const draggable = <Draggable id=\"draggable\" />;\n\n  return (\n    <DragDropProvider\n      plugins={debug ? (defaults) => [...defaults, Debug] : undefined}\n      onDragEnd={(event) => {\n        const {target} = event.operation;\n\n        if (event.canceled) {\n          return;\n        }\n\n        setParent(target?.id);\n      }}\n    >\n      <section>\n        <div style={{display: 'flex', justifyContent: 'center'}}>\n          {parent == null ? draggable : null}\n        </div>\n        {createRange(droppableCount).map((id) => (\n          <Droppable key={id} id={id}>\n            {parent === id ? draggable : null}\n          </Droppable>\n        ))}\n      </section>\n    </DragDropProvider>\n  );\n}\n\ninterface DraggableProps {\n  id: UniqueIdentifier;\n}\n\nfunction Draggable({id}: DraggableProps) {\n  const [element, setElement] = useState<Element | null>(null);\n\n  const {isDragging} = useDraggable({\n    id,\n    element,\n  });\n\n  return (\n    <Button ref={setElement} shadow={isDragging}>\n      draggable\n    </Button>\n  );\n}\n\ninterface DroppableProps {\n  id: UniqueIdentifier;\n}\n\nfunction Droppable({id, children}: PropsWithChildren<DroppableProps>) {\n  const {ref, isDropTarget} = useDroppable({id});\n\n  return (\n    <Dropzone ref={ref} highlight={isDropTarget}>\n      {children}\n    </Dropzone>\n  );\n}\n"
  },
  {
    "path": "apps/stories/stories/react/Droppable/MultipleDroppable/MultipleDroppable.stories.tsx",
    "content": "import type {Meta, StoryObj} from '@storybook/react-vite';\n\nimport MultipleDroppableApp from './MultipleDroppableApp';\nimport multipleDroppableSource from './MultipleDroppableApp.tsx?raw';\nimport {baseStyles, draggableStyles, droppableStyles} from '@dnd-kit/stories-shared/styles/sandbox';\n\nconst meta: Meta<typeof MultipleDroppableApp> = {\n  title: 'React/Droppable/Multiple drop targets',\n  component: MultipleDroppableApp,\n};\n\nexport default meta;\ntype Story = StoryObj<typeof MultipleDroppableApp>;\n\nexport const Example: Story = {\n  parameters: {\n    codesandbox: {\n      files: {\n        'src/App.tsx': multipleDroppableSource,\n        'src/styles.css': [baseStyles, draggableStyles, droppableStyles].join('\\n\\n'),\n      },\n    },\n  },\n};\n"
  },
  {
    "path": "apps/stories/stories/react/Droppable/MultipleDroppable/MultipleDroppableApp.tsx",
    "content": "import React, {useState} from 'react';\nimport {DragDropProvider, useDraggable, useDroppable} from '@dnd-kit/react';\n\nfunction Draggable({id}: {id: string}) {\n  const {ref} = useDraggable({id});\n\n  return <button ref={ref} className=\"btn\">draggable</button>;\n}\n\nfunction Droppable({id, children}: {id: string; children?: React.ReactNode}) {\n  const {ref, isDropTarget} = useDroppable({id});\n\n  return (\n    <div ref={ref} className={isDropTarget ? \"droppable active\" : \"droppable\"}>\n      {children}\n    </div>\n  );\n}\n\nexport default function App() {\n  const [parent, setParent] = useState<string | undefined>(undefined);\n  const draggable = <Draggable id=\"draggable\" />;\n  const droppables = ['A', 'B', 'C'];\n\n  return (\n    <DragDropProvider\n      onDragEnd={(event) => {\n        if (event.canceled) return;\n        setParent(event.operation.target?.id as string);\n      }}\n    >\n      <div style={{display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 20, maxWidth: 500, margin: '0 auto'}}>\n        <div style={{display: 'flex', alignItems: 'center', justifyContent: 'center'}}>\n          {parent == null ? draggable : null}\n        </div>\n        {droppables.map((id) => (\n          <Droppable key={id} id={id}>\n            {parent === id ? draggable : null}\n          </Droppable>\n        ))}\n      </div>\n    </DragDropProvider>\n  );\n}\n"
  },
  {
    "path": "apps/stories/stories/react/Droppable/docs/DroppableDocs.mdx",
    "content": "import {Preview} from '../../../components';\nimport {Example as Hero} from '../Droppable.stories';\nimport {Example} from './examples/QuickStart';\nimport ExampleSource from './examples/QuickStart?raw';\nimport DraggableSource from './examples/Draggable?raw';\nimport DroppableSource from './examples/Droppable?raw';\nimport {Example as MultipleDroppableExample} from './examples/MultipleDroppable';\nimport MultipleDroppableExampleSource from './examples/MultipleDroppable?raw';\n\n# Droppable\n\nCreate droppable targets for draggable elements.\n\n<Preview of={Hero} hero />\n\n## Usage\n\nUse the `useDroppable` hook to create droppable targets that `draggable` elements can be dropped over.\n\n```jsx\nimport {useDroppable} from '@dnd-kit/react';\n\nfunction Droppable(props) {\n  const {ref} = useDroppable({\n    id: props.id,\n  });\n\n  return <div ref={ref}>{props.children}</div>;\n}\n```\n\nOn its own, the `useDroppable` hook does not provide a lot of functionality. It is meant to be used in conjunction with the `useDraggable` hook, along with a parent `<DragDropProvider>` component to listen for and respond to drag and drop events.\n\nYou can set up as many droppable targets as needed, either by calling the `useDroppable` hook multiple times within the same component, or by setting up a generic component that calls `useDroppable` and rendering that component multiple times. Just remember to make sure they all have a unique `id` so that they can be differentiated.\n\n## Getting started\n\nTo get started, we will create three files, `App.js`, `Droppable.js`, and `Draggable.js`.\n\n<Preview\n  code={[ExampleSource, DroppableSource, DraggableSource]}\n  tabs={['App.js', 'Droppable.js', 'Draggable.js']}\n>\n  <Example />\n</Preview>\n\nTo render multiple droppable targets, we can simply render the `<Droppable>` component multiple times:\n\n<Preview code={[MultipleDroppableExampleSource]} tabs={['App.js']}>\n  <MultipleDroppableExample />\n</Preview>\n"
  },
  {
    "path": "apps/stories/stories/react/Droppable/docs/examples/Draggable.jsx",
    "content": "import React from 'react';\nimport {useDraggable} from '@dnd-kit/react';\n\nexport function Draggable({id}) {\n  const {ref} = useDraggable({\n    id,\n  });\n\n  return (\n    <button ref={ref}>\n      Draggable\n    </button>\n  );\n}\n"
  },
  {
    "path": "apps/stories/stories/react/Droppable/docs/examples/Droppable.jsx",
    "content": "import React from 'react';\nimport {useDroppable} from '@dnd-kit/react';\n\nexport function Droppable({id, children}) {\n  const {ref, isDropTarget} = useDroppable({id});\n\n  return (\n    <div ref={ref} style={{\n      display: 'flex',\n      alignItems: 'center',\n      justifyContent: 'center',\n      width: 300,\n      height: 300,\n      backgroundColor: isDropTarget ? '#1eb99d25' : '#ffffff',\n      border: '3px solid',\n      borderColor: isDropTarget ? '#1eb99d' : '#00000020',\n      borderRadius: 10,\n    }}>\n      {children}\n    </div>\n  );\n}\n"
  },
  {
    "path": "apps/stories/stories/react/Droppable/docs/examples/MultipleDroppable.jsx",
    "content": "import React, {useState} from 'react';\nimport {DragDropProvider} from '@dnd-kit/react';\n\nimport {Droppable} from './Droppable';\nimport {Draggable} from './Draggable';\n\nexport function Example() {\n  const [parent, setParent] = useState();\n  const parents = ['A', 'B', 'C'];\n  const draggable = <Draggable id=\"draggable\" />;\n\n  return (\n    <DragDropProvider\n      onDragEnd={(event) => {\n        const {target} = event.operation;\n\n        if (event.canceled) return;\n\n        setParent(target ? target.id : undefined);\n      }}\n    >\n      <section>\n        <div>{parent == null ? draggable : null}</div>\n        {parents.map((id) => (\n          <Droppable key={id} id={id}>\n            {parent === id ? draggable : null}\n          </Droppable>\n        ))}\n      </section>\n    </DragDropProvider>\n  );\n}\n\n\n"
  },
  {
    "path": "apps/stories/stories/react/Droppable/docs/examples/QuickStart.jsx",
    "content": "import React, {useState} from 'react';\nimport {DragDropProvider} from '@dnd-kit/react';\n\nimport {Droppable} from './Droppable';\nimport {Draggable} from './Draggable';\n\nexport function Example() {\n  const [parent, setParent] = useState();\n  const draggable = <Draggable id=\"draggable\" />;\n\n  return (\n    <DragDropProvider\n      onDragEnd={(event) => {\n        const {target} = event.operation;\n\n        if (event.canceled) return;\n\n        setParent(target ? target.id : undefined);\n      }}\n    >\n      <section>\n        <div>{parent == null ? draggable : null}</div>\n        <Droppable id=\"dropzone\">\n          {parent === 'dropzone' ? draggable : null}\n        </Droppable>\n      </section>\n    </DragDropProvider>\n  );\n}\n\n\n"
  },
  {
    "path": "apps/stories/stories/react/Resizeable/Resizeable.css",
    "content": "body, html, #root {\n\theight: 100%;\n}\n\n.Test {\n\t--max-width: 1600px;\n\t--gutter: 3vw;\n\n\t--grid-gutter: calc(var(--gutter, 4vw) - 11px);\n\t--cell-max-width: calc( ( var(--max-width, 1500px) - (11px * 23) ) / 24 );\n\t--inset-padding: 0vw;\n\t--container-width: min(var(--max-width, 1500px), calc(100vw - var(--gutter, 4vw) * 2 - var(--inset-padding) ));\n\n\tgrid-template-rows: repeat(20,minmax(calc(var(--container-width) * 0.0215), auto));\n\tgrid-template-columns: minmax(var(--grid-gutter), 1fr) repeat(24, minmax(0, var(--cell-max-width))) minmax(var(--grid-gutter), 1fr);\n}\n\n.Grid {\n\tdisplay: grid;\n\tposition: relative;\n\tgrid-area: 1/1/-1/-1;\n\n\t--max-width: 1600px;\n\t--gap: 11px;\n\t--gutter: 3vw;\n\t--grid-gutter: calc(var(--gutter, 4vw) - 11px);\n\n\t--cell-max-width: calc( ( var(--max-width, 1500px) - (11px * 23) ) / 24 );\n\t--inset-padding: 0vw;\n\t--container-width: min(var(--max-width, 1500px), calc(100vw - var(--gutter, 4vw) * 2 - var(--inset-padding) ));\n\n\t--column-width: var(--cell-max-width);\n\t--column-height: calc(var(--container-width) * 0.0215);\n\n\tgrid-template-rows: repeat(20,minmax(var(--column-height), auto));\n\tgrid-template-columns: repeat(24, minmax(0, var(--column-width)));\n\n\trow-gap: var(--gap);\n  column-gap: var(--gap);\n}\n\n.reveal::before {\n\t--bg-width: calc(var(--column-width) + var(--gap));\n\t--bg-height: calc(var(--column-height) + var(--gap));\n\n\t--border-color: #EEE;\n\t--gap-color: #EEE;\n\t--cell-color: transparent;\n\n\tcontent: '';\n\tposition: absolute;\n\tinset: 0;\n\tpointer-events: none;\n\tbackground-image:\n\t\trepeating-linear-gradient(\n\t\t\t-90deg,\n\t\t\tvar(--gap-color) 0px,\n\t\t\tvar(--gap-color) calc(var(--gap) - 1px),\n\t\t\tvar(--border-color) var(--gap),\n\t\t\tvar(--cell-color) calc(var(--gap)),\n\t\t\tvar(--cell-color) calc(var(--bg-width) - 1px),\n\t\t\tvar(--border-color) var(--bg-width)\n\t\t),\n\t\trepeating-linear-gradient(\n\t\t\t0deg,\n\t\t\tvar(--gap-color) 0px,\n\t\t\tvar(--gap-color) calc(var(--gap) - 1px),\n\t\t\tvar(--border-color) var(--gap),\n\t\t\tvar(--cell-color) var(--gap),\n\t\t\tvar(--cell-color) calc(var(--bg-height) - 1px),\n\t\t\tvar(--border-color) var(--bg-height)\n\t\t);\n\tbackground-size: var(--bg-width) var(--bg-height);\n}\n\n\n.GridItem {\n\tposition: relative;\n\tpadding: 20px;\n\t// grid-area: attr(data-position);\n}\n\n.GridItem:hover, .selected {\n\toutline: 2px solid blue;\n}\n\n\n.Handle {\n\tposition: absolute;\n\tpadding: 10px;\n\tdisplay: flex;\n}\n\n.Handle::after {\n\tcontent: '';\n\twidth: 10px;\n\theight: 10px;\n\tline-height: 0;\n\tmargin: 0;\n\tborder-radius: 3px;\n\tborder: 2px solid blue;\n\tbackground-color: white;\n\tbox-sizing: border-box;\n}\n\n.Handle[data-direction=\"N\"] {\n\ttop: -1px;\n\tleft: 50%;\n\ttransform: translate3d(-50%, -50%, 0);\n\tcursor: row-resize;\n}\n\n.Handle[data-direction=\"NW\"] {\n\ttop: -1px;\n\tleft: -1px;\n\ttransform: translate3d(-50%, -50%, 0);\n\tcursor: nw-resize;\n}\n\n.Handle[data-direction=\"NE\"] {\n\ttop: -1px;\n\tright: -1px;\n\ttransform: translate3d(50%, -50%, 0);\n\tcursor: ne-resize;\n}\n\n.Handle[data-direction=\"S\"] {\n\tbottom: -1px;\n\tleft: 50%;\n\ttransform: translate3d(-50%, 50%, 0);\n\tcursor: row-resize;\n}\n\n.Handle[data-direction=\"SW\"] {\n\tbottom: -1px;\n\tleft: -1px;\n\ttransform: translate3d(-50%, 50%, 0);\n\tcursor: sw-resize;\n}\n\n.Handle[data-direction=\"W\"] {\n\ttop: 50%;\n\tleft: -1px;\n\ttransform: translate3d(-50%, -50%, 0);\n\tcursor: col-resize;\n}\n\n.Handle[data-direction=\"SE\"] {\n\tbottom: -1px;\n\tright: -1px;\n\ttransform: translate3d(50%, 50%, 0);\n\tcursor: se-resize;\n}\n\n.Handle[data-direction=\"E\"] {\n\ttop: 50%;\n\tright: -1px;\n\ttransform: translate3d(50%, -50%, 0);\n\tcursor: col-resize;\n}\n"
  },
  {
    "path": "apps/stories/stories/react/Resizeable/Resizeable.tsx",
    "content": "import React, {\n  useCallback,\n  useEffect,\n  useLayoutEffect,\n  useState,\n  useReducer,\n  useRef,\n} from 'react';\nimport type {PropsWithChildren} from 'react';\nimport type {UniqueIdentifier} from '@dnd-kit/abstract';\nimport {DragDropProvider, useDraggable} from '@dnd-kit/react';\n\nimport './Resizeable.css';\nimport {Coordinates} from '@dnd-kit/geometry';\n\ninterface Layout {\n  /** @x integer that represents the number of grid cells from the left edge */\n  x: number;\n  /** @y integer that represents the number of grid cells from the top edge */\n  y: number;\n  /** @z integer that represents the stacking order of the item */\n  z: number;\n  /** @width Integer that represents the number of grid cells representing the width of the item */\n  width: number;\n  /** @height Integer that represents the number of grid cells representing the height of the item */\n  height: number;\n}\n\ninterface State {\n  layouts: Record<UniqueIdentifier, Layout>;\n}\n\ninterface GridArea {\n  columnStart: number;\n  columnEnd: number;\n  rowStart: number;\n  rowEnd: number;\n}\n\nfunction toGridArea({x, y, width, height}: Layout): GridArea {\n  return {\n    columnStart: x,\n    columnEnd: x + width,\n    rowStart: y,\n    rowEnd: y + height,\n  };\n}\n\nfunction toString({rowStart, columnStart, rowEnd, columnEnd}: GridArea) {\n  return `${rowStart}/${columnEnd}/${rowEnd}/${columnStart}`;\n}\n\nconst CELL_WIDTH = 56;\nconst ROW_HEIGHT = 35;\n\ntype Action =\n  | {\n      type: 'move';\n      id: UniqueIdentifier;\n      data: Coordinates;\n    }\n  | {\n      type: 'resize';\n      id: UniqueIdentifier;\n      data: ResizeEvent;\n    };\n\nfunction sanitize(layout: Layout): Layout {\n  const {x, y, z, width, height} = layout;\n\n  return {\n    ...layout,\n    x: Math.min(Math.max(x, 1), CELL_WIDTH - (x + width)),\n    y: Math.max(y, 1),\n    z: Math.max(z, 0),\n    width,\n    height,\n  };\n}\n\nfunction move(layout: Layout, coordinates: Coordinates): Layout {\n  const {x, y} = coordinates;\n\n  return sanitize({\n    ...layout,\n    x: layout.x + x,\n    y: layout.y + y,\n  });\n}\n\nfunction resize(layout: Layout, data: ResizeEvent): Layout {\n  const {x, y, width, height} = data;\n\n  return sanitize({\n    ...layout,\n    width: layout.width + width,\n    height: layout.height + height,\n    x: layout.x + x,\n    y: layout.y + y,\n  });\n}\n\nfunction reducer(state: State, action: Action): State {\n  switch (action.type) {\n    case 'move': {\n      const {id, data} = action;\n\n      return {\n        ...state,\n        layouts: {\n          ...state.layouts,\n          [id]: move(state.layouts[id], data),\n        },\n      };\n    }\n    case 'resize': {\n      const {id, data} = action;\n\n      return {\n        ...state,\n        layouts: {\n          ...state.layouts,\n          [id]: resize(state.layouts[id], data),\n        },\n      };\n    }\n  }\n\n  return state;\n}\n\nexport function App() {\n  const [selectedIds, setSelectedIds] = useState<UniqueIdentifier[] | null>(\n    null\n  );\n  const [draggingIds, setDraggingIds] = useState<UniqueIdentifier[] | null>(\n    null\n  );\n  const isDragging = draggingIds != null;\n\n  const [state, dispatch] = useReducer(reducer, {\n    layouts: {\n      A: {\n        x: 2,\n        y: 3,\n        z: 0,\n        width: 6,\n        height: 3,\n      },\n      B: {\n        x: 3,\n        y: 10,\n        z: 0,\n        width: 4,\n        height: 2,\n      },\n    },\n  });\n  const {layouts} = state;\n\n  const handleMove = useCallback(\n    (id: UniqueIdentifier, coordinates: Coordinates) => {\n      dispatch({type: 'move', id, data: coordinates});\n    },\n    []\n  );\n\n  const handleResize = useCallback(\n    (id: UniqueIdentifier, data: ResizeEvent) => {\n      dispatch({type: 'resize', id, data});\n    },\n    []\n  );\n\n  return (\n    <DragDropProvider\n      onDragStart={(manager) => {\n        if (selectedIds?.length) {\n          manager.actions.initalize(selectedIds);\n        }\n\n        setDraggingIds(manager.dragOperation.selectedIds);\n        setSelectedIds(manager.dragOperation.selectedIds);\n      }}\n      onDragEnd={() => setDraggingIds(null)}\n    >\n      <Grid reveal={isDragging} onClick={() => setSelectedIds(null)}>\n        {Object.entries(layouts).map(([id, layout]) => (\n          <GridItem\n            key={id}\n            id={id}\n            layout={layout}\n            onMove={handleMove}\n            onResize={handleResize}\n            onSelect={(id, shiftKey) =>\n              setSelectedIds((ids) => (shiftKey ? [id, ...(ids ?? [])] : [id]))\n            }\n            dragging={draggingIds?.includes(id)}\n            selected={selectedIds?.includes(id)}\n          >\n            Lorem ipsum dolor sit amet\n          </GridItem>\n        ))}\n      </Grid>\n    </DragDropProvider>\n  );\n}\n\ninterface GridProps {\n  reveal?: boolean;\n  onClick?(): void;\n}\n\nfunction Grid({children, onClick, reveal}: PropsWithChildren<GridProps>) {\n  const className = classNames('Grid', reveal && 'reveal');\n\n  return (\n    <div className={className} onClick={onClick}>\n      {children}\n    </div>\n  );\n}\n\ninterface GridItemProps {\n  id: UniqueIdentifier;\n  layout: Layout;\n  selected?: boolean;\n  dragging?: boolean;\n  onMove(id: UniqueIdentifier, coordinates: Coordinates): void;\n  onSelect(id: UniqueIdentifier, shiftKey: boolean): void;\n  onResize(id: UniqueIdentifier, event: ResizeEvent): void;\n}\n\nfunction GridItem({\n  id,\n  layout,\n  children,\n  dragging,\n  selected,\n  onMove,\n  onSelect,\n  onResize,\n}: PropsWithChildren<GridItemProps>) {\n  const [ref, setRef] = useState<HTMLElement | null>(null);\n  const {transform} = useDraggable({\n    handle: ref,\n    element: null,\n    id,\n  });\n  const x = transform ? Math.ceil(transform.x / CELL_WIDTH) : null;\n  const y = transform ? Math.ceil(transform.y / ROW_HEIGHT) : null;\n  const previous = useRef({x, y});\n  const showResizeControls = selected && !dragging;\n\n  useLayoutEffect(() => {\n    if (\n      x === null ||\n      y === null ||\n      (x === previous.current.x && y === previous.current.y)\n    ) {\n      previous.current = {x, y};\n      return;\n    }\n\n    const previousX = previous.current.x ?? 0;\n    const previousY = previous.current.y ?? 0;\n\n    onMove(id, {x: x - previousX, y: y - previousY});\n\n    previous.current = {x, y};\n  }, [x, y]);\n\n  const className = classNames('GridItem', selected && 'selected');\n\n  return (\n    <div\n      ref={setRef}\n      className={className}\n      style={{\n        gridArea: toString(toGridArea(layout)),\n      }}\n      onClick={(event) => {\n        event.stopPropagation();\n        onSelect(id, event.shiftKey);\n      }}\n    >\n      {children}\n      <Resizeable\n        disabled={!showResizeControls}\n        onResize={(event) => onResize(id, event)}\n      />\n    </div>\n  );\n}\n\ninterface ResizeEvent {\n  x: number;\n  y: number;\n  width: number;\n  height: number;\n}\n\ninterface ResizeableProps {\n  disabled?: boolean;\n  onResize(event: ResizeEvent): void;\n}\n\nconst DIRECTIONS: Direction[] = ['NE', 'N', 'NW', 'E', 'W', 'SE', 'S', 'SW'];\n\nexport function Resizeable({disabled, onResize}: ResizeableProps) {\n  const handles = disabled ? null : (\n    <>\n      {DIRECTIONS.map((direction) => (\n        <Handle key={direction} direction={direction} onResize={onResize} />\n      ))}\n    </>\n  );\n\n  return <DragDropProvider>{handles}</DragDropProvider>;\n}\n\ntype Direction = 'NE' | 'N' | 'NW' | 'SE' | 'S' | 'SW' | 'E' | 'W';\n\ninterface HandleProps {\n  direction: Direction;\n  onResize(event: ResizeEvent): void;\n}\n\nfunction Handle({direction, onResize}: HandleProps) {\n  const ref = useRef<HTMLSpanElement | null>(null);\n  const {transform} = useDraggable({\n    handle: ref,\n    element: null,\n    id: direction,\n    type: 'handle',\n  });\n  const previousTransform = useRef(transform);\n  const previous = useRef({x: 0, y: 0});\n\n  useEffect(() => {\n    if (\n      JSON.stringify(transform) === JSON.stringify(previousTransform.current)\n    ) {\n      return;\n    }\n\n    previousTransform.current = transform;\n\n    if (!transform) {\n      return;\n    }\n\n    const x = Math.ceil(transform.x / CELL_WIDTH) - previous.current.x;\n    const y = Math.ceil(transform.y / ROW_HEIGHT) - previous.current.y;\n\n    previous.current.x = x;\n    previous.current.y = x;\n\n    const delta = {\n      width: x,\n      height: y,\n      x: 0,\n      y: 0,\n    };\n\n    if (direction.includes('N')) {\n      delta.y = y;\n      delta.height = -1 * y;\n    }\n\n    if (direction.includes('W')) {\n      delta.x = x;\n      delta.width = -1 * x;\n    }\n\n    switch (direction) {\n      case 'N':\n      case 'S':\n        delta.width = 0;\n        break;\n      case 'E':\n      case 'W':\n        delta.height = 0;\n        break;\n    }\n\n    onResize(delta);\n  }, [transform, onResize, direction]);\n\n  return <span className=\"Handle\" data-direction={direction} ref={ref} />;\n}\n\nfunction classNames(...classes: (string | boolean | undefined | null)[]) {\n  return classes.filter(Boolean).join(' ');\n}\n"
  },
  {
    "path": "apps/stories/stories/react/Resizeable/index.ts",
    "content": "export {App} from './Resizeable';\n"
  },
  {
    "path": "apps/stories/stories/react/Sortable/CSSLayers/CSSLayers.stories.tsx",
    "content": "import type {Meta, StoryObj} from '@storybook/react-vite';\n\nimport {CSSLayersExample} from './CSSLayersExample';\n\nconst meta: Meta<typeof CSSLayersExample> = {\n  title: 'React/Sortable/CSS Layers',\n  component: CSSLayersExample,\n  tags: ['hidden'],\n};\n\nexport default meta;\ntype Story = StoryObj<typeof CSSLayersExample>;\n\nexport const BasicSetup: Story = {\n  name: 'Basic setup',\n};\n"
  },
  {
    "path": "apps/stories/stories/react/Sortable/CSSLayers/CSSLayersExample.tsx",
    "content": "import React, {useState, memo, useEffect} from 'react';\nimport type {PropsWithChildren} from 'react';\nimport type {UniqueIdentifier} from '@dnd-kit/abstract';\nimport {DragDropProvider} from '@dnd-kit/react';\nimport {useSortable} from '@dnd-kit/react/sortable';\nimport {move} from '@dnd-kit/helpers';\n\nconst LAYER_STYLES = `\n@layer base, components;\n\n@layer base {\n  .test {\n    appearance: none;\n    padding: 12px 20px;\n    border: 2px solid rgb(76, 159, 254);\n    border-radius: 8px;\n    background: rgb(232, 240, 254);\n    color: rgb(26, 58, 92);\n    font-size: 15px;\n    cursor: grab;\n    white-space: nowrap;\n    outline: none;\n  }\n}\n\n@layer components {\n  .test[data-shadow=\"true\"] {\n    opacity: 0.6;\n  }\n}\n`;\n\nexport function CSSLayersExample() {\n  const [items, setItems] = useState<UniqueIdentifier[]>([1, 2, 3, 4, 5]);\n\n  useEffect(() => {\n    const style = document.createElement('style');\n    style.setAttribute('data-test-layers', '');\n    style.textContent = LAYER_STYLES;\n    document.head.appendChild(style);\n\n    return () => {\n      style.remove();\n    };\n  }, []);\n\n  return (\n    <DragDropProvider\n      onDragEnd={(event) => {\n        setItems((items) => move(items, event));\n      }}\n    >\n      <div\n        style={{\n          display: 'flex',\n          flexDirection: 'column',\n          alignItems: 'center',\n          gap: 18,\n          padding: '0 30px',\n        }}\n      >\n        {items.map((id, index) => (\n          <LayerItem key={id} id={id} index={index} />\n        ))}\n      </div>\n    </DragDropProvider>\n  );\n}\n\nconst LayerItem = memo(function LayerItem({\n  id,\n  index,\n}: PropsWithChildren<{id: UniqueIdentifier; index: number}>) {\n  const [element, setElement] = useState<Element | null>(null);\n  const {isDragging} = useSortable({id, index, element});\n\n  return (\n    <div\n      ref={setElement}\n      className=\"test\"\n      data-shadow={isDragging || undefined}\n    >\n      Item {id}\n    </div>\n  );\n});\n"
  },
  {
    "path": "apps/stories/stories/react/Sortable/Grid/Grid.stories.tsx",
    "content": "import type {Meta, StoryObj} from '@storybook/react-vite';\nimport {pointerIntersection} from '@dnd-kit/collision';\nimport {Feedback} from '@dnd-kit/dom';\n\nimport {SortableExample} from '../SortableExample';\nimport gridSortableSource from './GridSortableApp.tsx?raw';\nimport {baseStyles, sortableStyles} from '@dnd-kit/stories-shared/styles/sandbox';\n\nconst meta: Meta<typeof SortableExample> = {\n  title: 'React/Sortable/Grid',\n  component: SortableExample,\n};\n\nexport default meta;\ntype Story = StoryObj<typeof SortableExample>;\n\nconst defaultArgs = {\n  debug: false,\n  layout: 'grid',\n} as const;\n\nexport const Grid: Story = {\n  name: 'Basic setup',\n  args: defaultArgs,\n  parameters: {\n    codesandbox: {\n      files: {\n        'src/App.tsx': gridSortableSource,\n        'src/styles.css': [baseStyles, sortableStyles].join('\\n\\n'),\n      },\n    },\n  },\n};\n\nexport const DragHandle: Story = {\n  name: 'Drag handle',\n  args: {\n    ...defaultArgs,\n    dragHandle: true,\n  },\n};\n\nexport const VariableSizes: Story = {\n  name: 'Variable sizes',\n  args: {\n    ...defaultArgs,\n    itemCount: 14,\n    collisionDetector: pointerIntersection,\n    optimistic: false,\n    getItemStyle(_: number, index: number) {\n      if (index === 0 || index === 10) {\n        return {\n          maxWidth: 'initial',\n          gridRowStart: 'span 2',\n          gridColumnStart: 'span 2',\n        };\n      }\n    },\n  },\n};\n\nexport const Clone: Story = {\n  name: 'Clone feedback',\n  args: {\n    ...defaultArgs,\n    collisionDetector: pointerIntersection,\n    optimistic: false,\n    getItemStyle(_, index) {\n      if (index === 0 || index === 2 || index === 10) {\n        return {\n          maxWidth: 'initial',\n          gridRowStart: 'span 2',\n          gridColumnStart: 'span 2',\n        };\n      }\n\n      if (index === 12) {\n        return {\n          gridRowStart: 'span 2',\n        };\n      }\n    },\n    plugins: [Feedback.configure({feedback: 'clone'})],\n  },\n};\n\nexport const Debug: Story = {\n  name: 'Debug',\n  args: {\n    ...defaultArgs,\n    debug: true,\n  },\n};\n"
  },
  {
    "path": "apps/stories/stories/react/Sortable/Grid/GridSortableApp.tsx",
    "content": "import React, {useState} from 'react';\nimport {DragDropProvider} from '@dnd-kit/react';\nimport {useSortable} from '@dnd-kit/react/sortable';\nimport {move} from '@dnd-kit/helpers';\n\nfunction Sortable({id, index}: {id: number; index: number}) {\n  const [element, setElement] = useState<Element | null>(null);\n  const {isDragging} = useSortable({id, index, element});\n\n  return (\n    <div\n      ref={setElement}\n      className=\"item\"\n      data-shadow={isDragging || undefined}\n      style={{height: '100%', justifyContent: 'center'}}\n    >\n      {id}\n    </div>\n  );\n}\n\nexport default function App() {\n  const [items, setItems] = useState(createRange(20));\n\n  return (\n    <DragDropProvider\n      onDragEnd={(event) => {\n        setItems((items) => move(items, event));\n      }}\n    >\n      <div style={{display: 'grid', gridTemplateColumns: 'repeat(auto-fill, 150px)', gridAutoRows: 150, gridAutoFlow: 'dense', gap: 18, padding: '0 30px', maxWidth: 900, marginInline: 'auto', justifyContent: 'center'}}>\n        {items.map((id, index) => (\n          <Sortable key={id} id={id} index={index} />\n        ))}\n      </div>\n    </DragDropProvider>\n  );\n}\n\nfunction createRange(length: number) {\n  return Array.from({length}, (_, i) => i + 1);\n}\n"
  },
  {
    "path": "apps/stories/stories/react/Sortable/Horizontal/Horizontal.stories.tsx",
    "content": "import type {Meta, StoryObj} from '@storybook/react-vite';\nimport {RestrictToHorizontalAxis} from '@dnd-kit/abstract/modifiers';\nimport {Feedback} from '@dnd-kit/dom';\n\nimport {SortableExample} from '../SortableExample';\nimport horizontalSortableSource from './HorizontalSortableApp.tsx?raw';\nimport {baseStyles, sortableStyles} from '@dnd-kit/stories-shared/styles/sandbox';\n\nconst meta: Meta<typeof SortableExample> = {\n  title: 'React/Sortable/Horizontal list',\n  component: SortableExample,\n};\n\nexport default meta;\ntype Story = StoryObj<typeof SortableExample>;\n\nconst defaultArgs = {\n  debug: false,\n  layout: 'horizontal',\n  getItemStyle() {\n    return {width: 180};\n  },\n} as const;\n\nexport const Horizontal: Story = {\n  name: 'Basic setup',\n  args: defaultArgs,\n  parameters: {\n    codesandbox: {\n      files: {\n        'src/App.tsx': horizontalSortableSource,\n        'src/styles.css': [baseStyles, sortableStyles].join('\\n\\n'),\n      },\n    },\n  },\n};\n\nexport const DragHandle: Story = {\n  name: 'Drag handle',\n  args: {\n    ...defaultArgs,\n    dragHandle: true,\n  },\n};\n\nexport const VariableWidths: Story = {\n  name: 'Variable widths',\n  args: {\n    ...defaultArgs,\n    getItemStyle(id) {\n      const widths = {0: 140, 2: 120, 4: 140, 5: 240, 8: 100, 12: 150};\n\n      return {\n        width: widths[id] ?? 180,\n      };\n    },\n  },\n};\n\nexport const Clone: Story = {\n  name: 'Clone feedback',\n  args: {\n    ...defaultArgs,\n    plugins: [Feedback.configure({feedback: 'clone'})],\n  },\n};\n\nexport const HorizontalAxis: Story = {\n  name: 'Restrict axis',\n  args: {\n    ...defaultArgs,\n    modifiers: [RestrictToHorizontalAxis],\n  },\n};\n\nexport const Debug: Story = {\n  name: 'Debug',\n  args: {\n    ...defaultArgs,\n    debug: true,\n  },\n};\n"
  },
  {
    "path": "apps/stories/stories/react/Sortable/Horizontal/HorizontalSortableApp.tsx",
    "content": "import React, {useState} from 'react';\nimport {DragDropProvider} from '@dnd-kit/react';\nimport {useSortable} from '@dnd-kit/react/sortable';\nimport {move} from '@dnd-kit/helpers';\n\nfunction Sortable({id, index}: {id: number; index: number}) {\n  const [element, setElement] = useState<Element | null>(null);\n  const {isDragging} = useSortable({id, index, element});\n\n  return (\n    <div\n      ref={setElement}\n      className=\"item\"\n      data-shadow={isDragging || undefined}\n      style={{aspectRatio: '1', justifyContent: 'center'}}\n    >\n      {id}\n    </div>\n  );\n}\n\nexport default function App() {\n  const [items, setItems] = useState(createRange(10));\n\n  return (\n    <DragDropProvider\n      onDragEnd={(event) => {\n        setItems((items) => move(items, event));\n      }}\n    >\n      <div style={{display: 'inline-flex', flexDirection: 'row', alignItems: 'stretch', height: 180, gap: 18, padding: '0 30px'}}>\n        {items.map((id, index) => (\n          <Sortable key={id} id={id} index={index} />\n        ))}\n      </div>\n    </DragDropProvider>\n  );\n}\n\nfunction createRange(length: number) {\n  return Array.from({length}, (_, i) => i + 1);\n}\n"
  },
  {
    "path": "apps/stories/stories/react/Sortable/Iframe/Iframe.stories.tsx",
    "content": "import type {Meta, StoryObj} from '@storybook/react-vite';\n\nimport {IframeLists} from './IframeExample.tsx';\n\nconst meta: Meta<typeof IframeLists> = {\n  title: 'React/Sortable/Iframe',\n  component: IframeLists,\n};\n\nexport default meta;\ntype Story = StoryObj<typeof IframeLists>;\n\nexport const Iframe: Story = {\n  name: 'Iframe',\n  args: {\n    debug: false,\n    itemCount: 6,\n  },\n};\n\nexport const IframeTransformed: Story = {\n  name: 'Transformed Iframe',\n  args: {\n    debug: false,\n    itemCount: 6,\n    transform: true,\n  },\n};\n"
  },
  {
    "path": "apps/stories/stories/react/Sortable/Iframe/IframeExample.tsx",
    "content": "import React, {useEffect, useRef, useState} from 'react';\nimport type {PropsWithChildren} from 'react';\nimport {DragDropProvider} from '@dnd-kit/react';\nimport {DragOverlay} from '@dnd-kit/react';\nimport {useSortable} from '@dnd-kit/react/sortable';\nimport {move} from '@dnd-kit/helpers';\nimport {Debug} from '@dnd-kit/dom/plugins/debug';\nimport AutoFrameComponent from '@measured/auto-frame-component';\n\nimport {Container, Item} from '../../components/index.ts';\nimport {createRange} from '@dnd-kit/stories-shared/utilities';\n\nconst AutoFrame = AutoFrameComponent.default || AutoFrameComponent;\n\ninterface Props {\n  debug?: boolean;\n  defaultItems?: Record<string, string[]>;\n  columnStyle?: Record<string, string>;\n  itemCount: number;\n  scrollable?: boolean;\n  transform?: boolean;\n}\n\nexport function IframeLists({\n  debug,\n  defaultItems,\n  itemCount,\n  columnStyle,\n  scrollable,\n  transform,\n}: Props) {\n  const [items, setItems] = useState(\n    defaultItems ?? {\n      host: createRange(itemCount).map((id) => `Host: ${id}`),\n      iframe: createRange(itemCount).map((id) => `Iframe: ${id}`),\n    }\n  );\n  const snapshot = useRef(structuredClone(items));\n\n  const [bodyClassName, setBodyClassName] = useState('');\n\n  useEffect(() => {\n    const body = document.querySelector('body');\n\n    if (!body) return;\n\n    if (body.classList.contains('dark')) {\n      setBodyClassName('dark');\n    }\n  }, []);\n\n  return (\n    <DragDropProvider\n      plugins={debug ? (defaults) => [...defaults, Debug] : undefined}\n      onDragStart={() => {\n        snapshot.current = structuredClone(items);\n      }}\n      onDragOver={(event) => {\n        setItems((items) => move(items, event));\n      }}\n      onDragEnd={(event) => {\n        if (event.canceled) {\n          setItems(snapshot.current);\n          return;\n        }\n      }}\n    >\n      <div\n        style={{\n          display: 'flex',\n          flexDirection: 'row',\n          gap: 20,\n        }}\n      >\n        <Column id=\"host\" scrollable={scrollable} style={columnStyle}>\n          {items.host.map((id, index) => (\n            <SortableItem key={id} id={id} column={'host'} index={index} />\n          ))}\n        </Column>\n\n        <AutoFrame\n          style={{\n            border: 'none',\n            transform: transform ? 'scale(0.8)' : undefined,\n          }}\n        >\n          <link\n            href=\"https://fonts.googleapis.com/css2?family=Poppins:wght@300;600\"\n            rel=\"stylesheet\"\n          />\n\n          <style\n            dangerouslySetInnerHTML={{\n              __html: 'body { background: transparent; margin: 0 !important; padding: 0 !important; }',\n            }}\n          />\n          <div className={bodyClassName}>\n            <Column id=\"iframe\" scrollable={scrollable} style={columnStyle}>\n              {items.iframe.map((id, index) => (\n                <SortableItem key={id} id={id} column=\"iframe\" index={index} />\n              ))}\n            </Column>\n          </div>\n        </AutoFrame>\n      </div>\n      <DragOverlay>\n        {(source) => <Item shadow={source.isDragging}>{source.id}</Item>}\n      </DragOverlay>\n    </DragDropProvider>\n  );\n}\n\ninterface SortableItemProps {\n  id: string;\n  column: string;\n  index: number;\n  style?: React.CSSProperties;\n}\n\nconst COLORS: Record<string, string> = {\n  Host: '#7193f1',\n  Iframe: '#FF851B',\n};\n\nfunction SortableItem({\n  id,\n  column,\n  index,\n  style,\n}: PropsWithChildren<SortableItemProps>) {\n  const group = column;\n  const {ref, isDragSource} = useSortable({\n    id,\n    group,\n    accept: 'item',\n    type: 'item',\n    index,\n    data: {group},\n  });\n\n  return (\n    <Item\n      ref={ref}\n      accentColor={COLORS[column]}\n      style={style}\n      transitionId={`sortable-${column}-${id}`}\n      aria-hidden={isDragSource}\n    >\n      {id}\n    </Item>\n  );\n}\n\ninterface ColumnProps {\n  id: string;\n  scrollable?: boolean;\n  style?: React.CSSProperties;\n}\n\nfunction Column({\n  children,\n  id,\n  scrollable,\n  style,\n}: PropsWithChildren<ColumnProps>) {\n  return (\n    <Container\n      label={id.charAt(0).toUpperCase() + id.slice(1)}\n      scrollable={scrollable}\n      transitionId={`sortable-column-${id}`}\n      style={style}\n    >\n      {children}\n    </Container>\n  );\n}\n"
  },
  {
    "path": "apps/stories/stories/react/Sortable/MultipleLists/MultipleLists.stories.tsx",
    "content": "import type {Meta, StoryObj} from '@storybook/react-vite';\n\nimport {MultipleLists} from './MultipleLists';\nimport MultipleListsApp from './MultipleListsApp';\nimport docs from './docs/MultipleLists.mdx';\nimport multipleListsSource from './MultipleListsApp.tsx?raw';\nimport {baseStyles, sortableStyles, multipleListsStyles} from '@dnd-kit/stories-shared/styles/sandbox';\n\nconst meta: Meta<typeof MultipleLists> = {\n  title: 'React/Sortable/Multiple lists',\n  component: MultipleLists,\n  tags: ['autodocs'],\n  parameters: {\n    docs: {\n      page: docs,\n    },\n  },\n};\n\nexport default meta;\ntype Story = StoryObj<typeof MultipleLists>;\n\nexport const Example: Story = {\n  name: 'Example',\n  render: () => <MultipleListsApp />,\n  parameters: {\n    codesandbox: {\n      files: {\n        'src/App.tsx': multipleListsSource,\n        'src/styles.css': [baseStyles, sortableStyles, multipleListsStyles].join('\\n\\n'),\n      },\n    },\n  },\n};\n\nexport const Hero: Story = {\n  name: 'Hero',\n  tags: ['hidden'],\n  args: {\n    columnStyle: {\n      '--min-width': '250px',\n      flexGrow: '1',\n      flexBasis: '33%',\n      backgroundColor: 'rgba(246, 246, 246, 0.7)',\n    },\n    defaultItems: {\n      A: ['A1', 'A2', 'A3'],\n      B: ['B1', 'B2'],\n      C: [],\n    },\n  },\n};\n\nexport const Scrollable: Story = {\n  name: 'Scrollable containers',\n  args: {\n    debug: false,\n    itemCount: 25,\n    scrollable: true,\n  },\n};\n\nexport const Grid: Story = {\n  name: 'Grid',\n  args: {\n    debug: false,\n    itemCount: 5,\n    grid: true,\n  },\n};\n\nexport const VerticalSetup: Story = {\n  name: 'Vertical',\n  args: {\n    debug: false,\n    itemCount: 3,\n    vertical: true,\n  },\n};\n\nexport const VerticalScrollable: Story = {\n  name: 'Vertical & scrollable',\n  args: {\n    debug: false,\n    itemCount: 25,\n    scrollable: true,\n    vertical: true,\n  },\n};\n\nexport const RightToLeft: Story = {\n  name: 'RTL',\n  args: {\n    rtl: true,\n    itemCount: 6,\n  },\n};\n\nexport const Debug: Story = {\n  name: 'Debug',\n  args: {\n    debug: true,\n    itemCount: 6,\n  },\n};\n"
  },
  {
    "path": "apps/stories/stories/react/Sortable/MultipleLists/MultipleLists.tsx",
    "content": "import React, {memo, useCallback, useMemo, useRef, useState} from 'react';\nimport type {PropsWithChildren} from 'react';\nimport {flushSync} from 'react-dom';\nimport {CollisionPriority} from '@dnd-kit/abstract';\nimport {DragDropProvider} from '@dnd-kit/react';\nimport {useSortable} from '@dnd-kit/react/sortable';\nimport {move} from '@dnd-kit/helpers';\nimport {Feedback, PointerSensor, KeyboardSensor} from '@dnd-kit/dom';\nimport {Debug} from '@dnd-kit/dom/plugins/debug';\nimport {supportsViewTransition} from '@dnd-kit/dom/utilities';\nimport {DragDropEventHandlers} from '@dnd-kit/react';\n\nimport {\n  Actions,\n  Container,\n  Item,\n  Handle,\n  Remove,\n} from '../../components/index.ts';\nimport {createRange} from '@dnd-kit/stories-shared/utilities';\n\ninterface Props {\n  debug?: boolean;\n  grid?: boolean;\n  defaultItems?: Record<string, string[]>;\n  columnStyle?: Record<string, string>;\n  itemCount: number;\n  rtl?: boolean;\n  scrollable?: boolean;\n  vertical?: boolean;\n}\n\nconst sensors = [\n  PointerSensor.configure({\n    activatorElements(source) {\n      return [source.element, source.handle];\n    },\n  }),\n  KeyboardSensor,\n];\n\nexport function MultipleLists({\n  debug,\n  defaultItems,\n  grid,\n  itemCount,\n  columnStyle,\n  rtl,\n  scrollable,\n  vertical,\n}: Props) {\n  const [items, setItems] = useState(\n    defaultItems ?? {\n      A: createRange(itemCount).map((id) => `A${id}`),\n      B: createRange(itemCount).map((id) => `B${id}`),\n      C: createRange(itemCount).map((id) => `C${id}`),\n      D: [],\n    }\n  );\n  const [columns] = useState(Object.keys(items));\n  const snapshot = useRef(structuredClone(items));\n  const handleRemoveItem = useCallback((id: string, column: string) => {\n    const remove = () =>\n      setItems((items) => ({\n        ...items,\n        [column]: items[column].filter((item) => item !== id),\n      }));\n\n    if (supportsViewTransition(document)) {\n      document.startViewTransition(() => flushSync(remove));\n    } else {\n      remove();\n    }\n  }, []);\n\n  return (\n    <DragDropProvider\n      plugins={debug ? (defaults) => [...defaults, Debug] : undefined}\n      sensors={sensors}\n      onDragStart={useCallback<DragDropEventHandlers['onDragStart']>(() => {\n        snapshot.current = structuredClone(items);\n      }, [items])}\n      onDragOver={useCallback<DragDropEventHandlers['onDragOver']>((event) => {\n        const {source} = event.operation;\n\n        if (source?.type === 'column') {\n          // We can rely on optimistic sorting for columns\n          return;\n        }\n\n        setItems((items) => move(items, event));\n      }, [])}\n      onDragEnd={useCallback<DragDropEventHandlers['onDragEnd']>((event) => {\n        if (event.canceled) {\n          setItems(snapshot.current);\n          return;\n        }\n      }, [])}\n    >\n      {rtl ? <style>{`:root { direction: rtl; }`}</style> : null}\n      <div\n        style={{\n          display: grid ? 'grid' : 'flex',\n          width: grid ? '60%' : undefined,\n          gridTemplateColumns: grid ? '1fr 1fr' : undefined,\n          alignItems: vertical ? 'center' : undefined,\n          margin: grid ? '0 auto' : undefined,\n          flexDirection: vertical ? 'column' : 'row',\n          gap: 20,\n        }}\n      >\n        {columns.map((column, columnIndex) => {\n          const rows = items[column];\n\n          return (\n            <SortableColumn\n              key={column}\n              id={column}\n              index={columnIndex}\n              columns={grid ? 2 : 1}\n              scrollable={scrollable}\n              style={columnStyle}\n              rows={rows}\n              onRemove={handleRemoveItem}\n            />\n          );\n        })}\n      </div>\n    </DragDropProvider>\n  );\n}\n\ninterface SortableItemProps {\n  id: string;\n  column: string;\n  index: number;\n  style?: React.CSSProperties;\n  onRemove?: (id: string, column: string) => void;\n}\n\nconst COLORS: Record<string, string> = {\n  A: '#7193f1',\n  B: '#FF851B',\n  C: '#2ECC40',\n  D: '#ff3680',\n};\n\nconst SortableItem = memo(function SortableItem({\n  id,\n  column,\n  index,\n  style,\n  onRemove,\n}: PropsWithChildren<SortableItemProps>) {\n  const group = column;\n  const {handleRef, ref, isDragging} = useSortable({\n    id,\n    group,\n    accept: 'item',\n    type: 'item',\n    plugins: [Feedback.configure({feedback: 'clone'})],\n    index,\n    data: {group},\n  });\n\n  return (\n    <Item\n      ref={ref}\n      actions={\n        <Actions>\n          {onRemove && !isDragging ? (\n            <Remove onClick={() => onRemove(id, column)} />\n          ) : null}\n          <Handle ref={handleRef} />\n        </Actions>\n      }\n      accentColor={COLORS[column]}\n      shadow={isDragging}\n      style={style}\n      transitionId={`sortable-${column}-${id}`}\n    >\n      {id}\n    </Item>\n  );\n});\n\ninterface SortableColumnProps {\n  columns: number;\n  id: string;\n  index: number;\n  scrollable?: boolean;\n  style?: React.CSSProperties;\n  rows: string[];\n  onRemove?: SortableItemProps['onRemove'];\n}\n\nconst SortableColumn = memo(function SortableColumn({\n  rows,\n  columns,\n  id,\n  index,\n  scrollable,\n  style,\n  onRemove,\n}: PropsWithChildren<SortableColumnProps>) {\n  const {handleRef, isDragging, ref} = useSortable({\n    id,\n    accept: ['column', 'item'],\n    collisionPriority: CollisionPriority.Low,\n    type: 'column',\n    index,\n  });\n  const actions = useMemo(() => {\n    return (\n      <Actions>\n        <Handle ref={handleRef} />\n      </Actions>\n    );\n  }, [handleRef]);\n  const handleRemoveItem = useCallback(\n    (itemId: string) => {\n      onRemove?.(itemId, id);\n    },\n    [id, onRemove]\n  );\n\n  return (\n    <Container\n      ref={ref}\n      label={`${id}`}\n      actions={actions}\n      columns={columns}\n      shadow={isDragging}\n      scrollable={scrollable}\n      transitionId={`sortable-column-${id}`}\n      style={style}\n    >\n      {rows.map((itemId, index) => (\n        <SortableItem\n          key={itemId}\n          id={itemId}\n          column={id}\n          index={index}\n          onRemove={handleRemoveItem}\n          style={columns === 2 ? {height: 100} : undefined}\n        />\n      ))}\n    </Container>\n  );\n});\n"
  },
  {
    "path": "apps/stories/stories/react/Sortable/MultipleLists/MultipleListsApp.tsx",
    "content": "import React, {memo, useCallback, useRef, useState} from 'react';\nimport type {PropsWithChildren} from 'react';\nimport {CollisionPriority} from '@dnd-kit/abstract';\nimport {DragDropProvider} from '@dnd-kit/react';\nimport {useSortable} from '@dnd-kit/react/sortable';\nimport {move} from '@dnd-kit/helpers';\nimport {Feedback, PointerSensor, KeyboardSensor} from '@dnd-kit/dom';\nimport {DragDropEventHandlers} from '@dnd-kit/react';\n\nfunction createRange(length: number) {\n  return Array.from({length}, (_, i) => i + 1);\n}\n\nconst ITEM_COUNT = 6;\n\nconst sensors = [\n  PointerSensor.configure({\n    activatorElements(source) {\n      return [source.element, source.handle];\n    },\n  }),\n  KeyboardSensor,\n];\n\ninterface SortableItemProps {\n  id: string;\n  column: string;\n  index: number;\n  accentColor: string;\n}\n\nconst COLORS: Record<string, string> = {\n  A: '#7193f1',\n  B: '#FF851B',\n  C: '#2ECC40',\n  D: '#ff3680',\n};\n\nconst SortableItem = memo(function SortableItem({\n  id,\n  column,\n  index,\n  accentColor,\n}: PropsWithChildren<SortableItemProps>) {\n  const group = column;\n  const {handleRef, ref, isDragging} = useSortable({\n    id,\n    group,\n    accept: 'item',\n    type: 'item',\n    plugins: [Feedback.configure({feedback: 'clone'})],\n    index,\n    data: {group},\n  });\n\n  return (\n    <div\n      ref={ref as any}\n      className=\"item\"\n      data-shadow={isDragging || undefined}\n      data-accent-color={accentColor}\n      style={{'--accent-color': accentColor} as React.CSSProperties}\n    >\n      {id}\n      <button ref={handleRef as any} className=\"handle\" />\n    </div>\n  );\n});\n\ninterface SortableColumnProps {\n  id: string;\n  index: number;\n  rows: string[];\n}\n\nconst SortableColumn = memo(function SortableColumn({\n  rows,\n  id,\n  index,\n}: PropsWithChildren<SortableColumnProps>) {\n  const {handleRef, isDragging, ref} = useSortable({\n    id,\n    accept: ['column', 'item'],\n    collisionPriority: CollisionPriority.Low,\n    type: 'column',\n    index,\n  });\n\n  return (\n    <div\n      ref={ref as any}\n      className=\"container\"\n      data-shadow={isDragging || undefined}\n    >\n      <h2>\n        {id}\n        <button ref={handleRef as any} className=\"handle\" />\n      </h2>\n      <ul id={id} style={{'--columns': 1} as React.CSSProperties}>\n        {rows.map((itemId, itemIndex) => (\n          <SortableItem\n            key={itemId}\n            id={itemId}\n            column={id}\n            index={itemIndex}\n            accentColor={COLORS[id]}\n          />\n        ))}\n      </ul>\n    </div>\n  );\n});\n\nexport default function App() {\n  const [items, setItems] = useState({\n    A: createRange(ITEM_COUNT).map((id) => `A${id}`),\n    B: createRange(ITEM_COUNT).map((id) => `B${id}`),\n    C: createRange(ITEM_COUNT).map((id) => `C${id}`),\n    D: [],\n  });\n  const [columns] = useState(Object.keys(items));\n  const snapshot = useRef(structuredClone(items));\n\n  return (\n    <DragDropProvider\n      sensors={sensors}\n      onDragStart={useCallback<DragDropEventHandlers['onDragStart']>(() => {\n        snapshot.current = structuredClone(items);\n      }, [items])}\n      onDragOver={useCallback<DragDropEventHandlers['onDragOver']>((event) => {\n        const {source} = event.operation;\n\n        if (source && source.type === 'column') {\n          return;\n        }\n\n        setItems((items) => move(items, event));\n      }, [])}\n      onDragEnd={useCallback<DragDropEventHandlers['onDragEnd']>((event) => {\n        if (event.canceled) {\n          setItems(snapshot.current);\n          return;\n        }\n      }, [])}\n    >\n      <div className=\"wrapper\">\n        {columns.map((column, columnIndex) => {\n          const rows = items[column as keyof typeof items];\n\n          return (\n            <SortableColumn\n              key={column}\n              id={column}\n              index={columnIndex}\n              rows={rows}\n            />\n          );\n        })}\n      </div>\n    </DragDropProvider>\n  );\n}\n"
  },
  {
    "path": "apps/stories/stories/react/Sortable/MultipleLists/docs/MultipleLists.mdx",
    "content": "import {Code, Preview} from '../../../../components';\n\nimport {MultipleLists} from '../MultipleLists.tsx';\nimport {Hero} from '../MultipleLists.stories.tsx';\nimport {Example} from './examples/QuickStart';\nimport ExampleSource from './examples/QuickStart?raw';\nimport ColumnSource from './examples/Column?raw';\nimport ItemSource from './examples/Item?raw';\n\n# Multiple lists\n\nReorder sortable elements across multiple lists.\n\n<Preview hero of={Hero} />\n\n## Installation\n\nBefore getting started, make sure to install the `@dnd-kit/react` package:\n\n```bash\nnpm install @dnd-kit/react\n```\n\n## Getting started\n\n<Preview\n  tabs={['App.js', 'Item.js', 'Column.js']}\n  code={[ExampleSource, ItemSource, ColumnSource]}\n>\n  <Example />\n</Preview>\n"
  },
  {
    "path": "apps/stories/stories/react/Sortable/MultipleLists/docs/examples/Column.jsx",
    "content": "import React from 'react';\nimport {useDroppable} from '@dnd-kit/react';\nimport {CollisionPriority} from '@dnd-kit/abstract';\n\nconst styles = {\n  display: 'flex',\n  flexDirection: 'column',\n  gap: 10,\n  padding: 20,\n  minWidth: 200,\n  backgroundColor: 'rgba(0,0,0,0.1)',\n  borderRadius: 10,\n};\n\nexport function Column({children, id}) {\n  const {ref} = useDroppable({\n    id,\n    type: 'column',\n    accept: ['item'],\n    collisionPriority: CollisionPriority.Low,\n  });\n\n  return (\n    <div style={styles} ref={ref}>\n      {children}\n    </div>\n  );\n}\n"
  },
  {
    "path": "apps/stories/stories/react/Sortable/MultipleLists/docs/examples/Item.jsx",
    "content": "import React from 'react';\nimport {useSortable} from '@dnd-kit/react/sortable';\n\nexport function Item({id, column, index}) {\n  const {ref} = useSortable({\n    id,\n    index,\n    group: column,\n    type: 'item',\n    accept: ['item'],\n  });\n\n  return <button ref={ref}>{id}</button>;\n}\n"
  },
  {
    "path": "apps/stories/stories/react/Sortable/MultipleLists/docs/examples/QuickStart.jsx",
    "content": "import React, {useState} from 'react';\nimport {DragDropProvider} from '@dnd-kit/react';\nimport {move} from '@dnd-kit/helpers';\n\nimport {Column} from './Column';\nimport {Item} from './Item';\n\nconst styles = {display: 'inline-flex', flexDirection: 'row', gap: 20};\n\nexport function Example({style = styles}) {\n  const [items, setItems] = useState({\n    A: ['A0', 'A1', 'A2'],\n    B: ['B0', 'B1'],\n    C: [],\n  });\n\n  return (\n    <DragDropProvider\n      onDragOver={(event) => {\n        setItems((items) => move(items, event));\n      }}\n    >\n      <div style={style}>\n        {Object.entries(items).map(([column, items]) => (\n          <Column key={column} id={column}>\n            {items.map((id, index) => (\n              <Item key={id} id={id} index={index} />\n            ))}\n          </Column>\n        ))}\n      </div>\n    </DragDropProvider>\n  );\n}\n"
  },
  {
    "path": "apps/stories/stories/react/Sortable/Quickstart.tsx",
    "content": "import {useSortable} from '@dnd-kit/react/sortable';\n\nexport function Sortable({id, index}: {id: number; index: number}) {\n  const {ref} = useSortable({id, index});\n\n  return <li ref={ref}>Item {id}</li>;\n}\n\nexport function QuickstartExample() {\n  const items = [1, 2, 3, 4];\n\n  return (\n    <ul className=\"list\">\n      {items.map((id, index) => (\n        <Sortable key={id} id={id} index={index} />\n      ))}\n    </ul>\n  );\n}\n"
  },
  {
    "path": "apps/stories/stories/react/Sortable/Sortable.stories.tsx",
    "content": "import type {Meta, StoryObj} from '@storybook/react-vite';\n\nimport SortableApp from './SortableApp.tsx';\nimport sortableSource from './SortableApp.tsx?raw';\nimport {baseStyles, sortableStyles} from '@dnd-kit/stories-shared/styles/sandbox';\nimport {QuickstartExample} from './Quickstart.tsx';\n\nimport docs from './docs/SortableDocs.mdx';\n\nconst meta: Meta<typeof SortableApp> = {\n  component: SortableApp,\n  title: 'React/Sortable',\n  tags: ['autodocs'],\n  parameters: {\n    docs: {\n      page: docs,\n    },\n    codesandbox: {\n      files: {\n        'src/App.tsx': sortableSource,\n        'src/styles.css': [baseStyles, sortableStyles].join('\\n\\n'),\n      },\n    },\n  },\n};\n\nexport default meta;\ntype Story = StoryObj<typeof SortableApp>;\n\nexport const Example: Story = {\n  name: 'Example',\n};\n\nexport const Quickstart: Story = {\n  name: 'Quickstart',\n  tags: ['hidden'],\n  render: () => <QuickstartExample />,\n};\n"
  },
  {
    "path": "apps/stories/stories/react/Sortable/SortableApp.tsx",
    "content": "import React, {useRef, useState} from 'react';\nimport {DragDropProvider} from '@dnd-kit/react';\nimport {useSortable} from '@dnd-kit/react/sortable';\nimport {move} from '@dnd-kit/helpers';\n\nfunction Sortable({id, index}: {id: number; index: number}) {\n  const [element, setElement] = useState<Element | null>(null);\n  const handleRef = useRef<HTMLButtonElement | null>(null);\n  const {isDragging} = useSortable({id, index, element, handle: handleRef});\n\n  return (\n    <li ref={setElement} className=\"item\" data-shadow={isDragging || undefined}>\n      {id}\n      <button ref={handleRef} className=\"handle\" />\n    </li>\n  );\n}\n\nexport default function App() {\n  const [items, setItems] = useState(createRange(100));\n\n  return (\n    <DragDropProvider\n      onDragEnd={(event) => {\n        setItems((items) => move(items, event));\n      }}\n    >\n      <ul className=\"list\">\n        {items.map((id, index) => (\n          <Sortable key={id} id={id} index={index} />\n        ))}\n      </ul>\n    </DragDropProvider>\n  );\n}\n\nfunction createRange(length: number) {\n  return Array.from({length}, (_, i) => i + 1);\n}\n"
  },
  {
    "path": "apps/stories/stories/react/Sortable/SortableExample.tsx",
    "content": "import React, {useRef, useState, memo} from 'react';\nimport type {CSSProperties, PropsWithChildren} from 'react';\nimport type {\n  CollisionDetector,\n  Modifiers,\n  Plugins,\n  UniqueIdentifier,\n} from '@dnd-kit/abstract';\nimport {type SortableTransition} from '@dnd-kit/dom/sortable';\nimport {DragDropProvider} from '@dnd-kit/react';\nimport {useSortable} from '@dnd-kit/react/sortable';\nimport {directionBiased} from '@dnd-kit/collision';\nimport {move} from '@dnd-kit/helpers';\nimport {Debug} from '@dnd-kit/dom/plugins/debug';\n\nimport {Item, Handle} from '../components/index.ts';\nimport {createRange} from '@dnd-kit/stories-shared/utilities';\n\ninterface Props {\n  debug?: boolean;\n  dragHandle?: boolean;\n  disabled?: UniqueIdentifier[];\n  plugins?: Plugins;\n  modifiers?: Modifiers;\n  layout?: 'vertical' | 'horizontal' | 'grid';\n  transition?: SortableTransition;\n  itemCount?: number;\n  optimistic?: boolean;\n  collisionDetector?: CollisionDetector;\n  getItemStyle?(id: UniqueIdentifier, index: number): CSSProperties;\n}\n\nexport function SortableExample({\n  debug,\n  itemCount = 15,\n  collisionDetector,\n  disabled,\n  dragHandle,\n  plugins,\n  layout = 'vertical',\n  optimistic = true,\n  modifiers,\n  transition,\n  getItemStyle,\n}: Props) {\n  const [items, setItems] = useState(createRange(itemCount));\n\n  return (\n    <DragDropProvider\n      plugins={debug ? (defaults) => [Debug, ...defaults] : undefined}\n      modifiers={modifiers}\n      onDragOver={(event) => {\n        if (optimistic) return;\n\n        setItems((items) => move(items, event));\n      }}\n      onDragEnd={(event) => {\n        setItems((items) => move(items, event));\n      }}\n    >\n      <Wrapper layout={layout}>\n        {items.map((id, index) => (\n          <SortableItem\n            key={id}\n            id={id}\n            index={index}\n            collisionDetector={collisionDetector}\n            disabled={disabled?.includes(id)}\n            dragHandle={dragHandle}\n            plugins={plugins}\n            optimistic={optimistic}\n            transition={transition}\n            style={getItemStyle?.(id, index)}\n          />\n        ))}\n      </Wrapper>\n    </DragDropProvider>\n  );\n}\n\ninterface SortableProps {\n  id: UniqueIdentifier;\n  index: number;\n  collisionDetector?: CollisionDetector;\n  disabled?: boolean;\n  dragHandle?: boolean;\n  plugins?: Plugins;\n  optimistic?: boolean;\n  transition?: SortableTransition;\n  style?: React.CSSProperties;\n}\n\nconst SortableItem = memo(function SortableItem({\n  id,\n  index,\n  collisionDetector = directionBiased,\n  disabled,\n  dragHandle,\n  plugins,\n  transition,\n  style,\n}: PropsWithChildren<SortableProps>) {\n  const [element, setElement] = useState<Element | null>(null);\n  const handleRef = useRef<HTMLButtonElement | null>(null);\n  const {isDragging} = useSortable({\n    id,\n    index,\n    element,\n    plugins,\n    transition,\n    handle: handleRef,\n    disabled,\n    collisionDetector,\n  });\n\n  return (\n    <Item\n      ref={setElement}\n      actions={dragHandle ? <Handle ref={handleRef} /> : null}\n      shadow={isDragging}\n      style={style}\n    >\n      {id}\n    </Item>\n  );\n});\n\nfunction Wrapper({\n  layout,\n  children,\n}: PropsWithChildren<{layout: 'vertical' | 'horizontal' | 'grid'}>) {\n  return <div style={getWrapperStyles(layout)}>{children}</div>;\n}\n\nfunction getWrapperStyles(\n  layout: 'vertical' | 'horizontal' | 'grid'\n): CSSProperties {\n  const baseStyles: CSSProperties = {\n    gap: 18,\n    padding: '0 30px',\n  };\n\n  switch (layout) {\n    case 'grid':\n      return {\n        ...baseStyles,\n        display: 'grid',\n        maxWidth: 900,\n        marginInline: 'auto',\n        gridTemplateColumns: 'repeat(auto-fill, 150px)',\n        gridAutoFlow: 'dense',\n        gridAutoRows: '150px',\n        justifyContent: 'center',\n      };\n    case 'horizontal':\n      return {\n        ...baseStyles,\n        display: 'inline-flex',\n        flexDirection: 'row',\n        alignItems: 'stretch',\n        height: 180,\n      };\n    case 'vertical':\n      return {\n        ...baseStyles,\n        display: 'flex',\n        flexDirection: 'column',\n        alignItems: 'center',\n      };\n  }\n}\n"
  },
  {
    "path": "apps/stories/stories/react/Sortable/Table/Table.stories.tsx",
    "content": "import type {Meta, StoryObj} from '@storybook/react-vite';\n\nimport {TableExample} from './TableExample.tsx';\n\nconst meta: Meta<typeof TableExample> = {\n  title: 'React/Sortable/Table',\n  component: TableExample,\n};\n\nexport default meta;\ntype Story = StoryObj<typeof TableExample>;\n\nexport const Example: Story = {\n  name: 'Example',\n};\n"
  },
  {
    "path": "apps/stories/stories/react/Sortable/Table/TableExample.tsx",
    "content": "import React, {useRef, useState} from 'react';\nimport type {UniqueIdentifier} from '@dnd-kit/abstract';\nimport {RestrictToHorizontalAxis} from '@dnd-kit/abstract/modifiers';\nimport {DragDropProvider} from '@dnd-kit/react';\nimport {useSortable} from '@dnd-kit/react/sortable';\nimport {move} from '@dnd-kit/helpers';\n\nimport {Handle} from '../../components/index.ts';\n\ntype ColumnKey = 'name' | 'role' | 'email' | 'status';\n\ninterface Column {\n  id: ColumnKey;\n  label: string;\n}\n\nconst initialColumns: Column[] = [\n  {id: 'name', label: 'Name'},\n  {id: 'role', label: 'Role'},\n  {id: 'email', label: 'Email'},\n  {id: 'status', label: 'Status'},\n];\n\ninterface RowData {\n  id: UniqueIdentifier;\n  name: string;\n  role: string;\n  email: string;\n  status: string;\n}\n\nconst initialData: RowData[] = [\n  {\n    id: 1,\n    name: 'Alice Johnson',\n    role: 'Engineer',\n    email: 'alice@example.com',\n    status: 'Active',\n  },\n  {\n    id: 2,\n    name: 'Bob Smith',\n    role: 'Designer',\n    email: 'bob@example.com',\n    status: 'Active',\n  },\n  {\n    id: 3,\n    name: 'Charlie Brown',\n    role: 'Manager',\n    email: 'charlie@example.com',\n    status: 'Away',\n  },\n  {\n    id: 4,\n    name: 'Diana Ross',\n    role: 'Engineer',\n    email: 'diana@example.com',\n    status: 'Active',\n  },\n  {\n    id: 5,\n    name: 'Eve Williams',\n    role: 'Designer',\n    email: 'eve@example.com',\n    status: 'Offline',\n  },\n  {\n    id: 6,\n    name: 'Frank Miller',\n    role: 'Engineer',\n    email: 'frank@example.com',\n    status: 'Active',\n  },\n  {\n    id: 7,\n    name: 'Grace Lee',\n    role: 'Manager',\n    email: 'grace@example.com',\n    status: 'Away',\n  },\n  {\n    id: 8,\n    name: 'Hank Davis',\n    role: 'Designer',\n    email: 'hank@example.com',\n    status: 'Active',\n  },\n];\n\nexport function TableExample() {\n  const [rows, setRows] = useState(initialData);\n  const [columns, setColumns] = useState(initialColumns);\n  const initialOrder = useRef({\n    columns,\n    rows,\n  });\n\n  return (\n    <DragDropProvider\n      onDragStart={() => {\n        initialOrder.current = {\n          columns,\n          rows,\n        };\n      }}\n      onDragOver={(event) => {\n        const {source} = event.operation;\n\n        if (source?.type === 'column') {\n          setColumns((columns) => move(columns, event));\n        } else {\n          setRows((rows) => move(rows, event));\n        }\n      }}\n      onDragEnd={(event) => {\n        if (event.canceled) {\n          setColumns(initialOrder.current.columns);\n          setRows(initialOrder.current.rows);\n        }\n      }}\n    >\n      <div\n        style={{\n          maxWidth: 800,\n          marginInline: 'auto',\n          overflow: 'hidden',\n          borderRadius: 8,\n          border: '1px solid #e2e8f0',\n        }}\n      >\n        <table style={tableStyles}>\n          <thead>\n            <tr>\n              <th style={thStyles} />\n              {columns.map((column, index) => (\n                <SortableColumn key={column.id} column={column} index={index} />\n              ))}\n            </tr>\n          </thead>\n          <tbody>\n            {rows.map((row, index) => (\n              <SortableRow\n                key={row.id}\n                row={row}\n                columns={columns}\n                index={index}\n                lastRow={index === rows.length - 1}\n              />\n            ))}\n          </tbody>\n        </table>\n      </div>\n    </DragDropProvider>\n  );\n}\n\ninterface SortableColumnProps {\n  column: Column;\n  index: number;\n}\n\nfunction SortableColumn({column, index}: SortableColumnProps) {\n  const {ref, isDragging} = useSortable({\n    id: column.id,\n    index,\n    type: 'column',\n    accept: 'column',\n    modifiers: [RestrictToHorizontalAxis],\n  });\n\n  return (\n    <th\n      ref={ref}\n      style={{\n        ...thStyles,\n        cursor: 'grab',\n        userSelect: 'none',\n        opacity: isDragging ? 0.5 : undefined,\n        backgroundColor: isDragging ? '#f1f5f9' : undefined,\n      }}\n    >\n      {column.label}\n    </th>\n  );\n}\n\ninterface SortableRowProps {\n  row: RowData;\n  columns: Column[];\n  index: number;\n  lastRow?: boolean;\n}\n\nfunction SortableRow({row, columns, index, lastRow}: SortableRowProps) {\n  const {ref, handleRef, isDragging} = useSortable({\n    id: row.id,\n    index,\n    type: 'row',\n    accept: 'row',\n  });\n\n  return (\n    <tr\n      ref={ref}\n      style={{\n        ...trStyles,\n        boxShadow: isDragging\n          ? '0 0 0 1px rgba(63, 63, 68, 0.05), 0px 15px 15px 0 rgba(34, 33, 81, 0.25)'\n          : undefined,\n        opacity: isDragging ? 0.9 : undefined,\n      }}\n    >\n      <td style={lastRow ? tdLastRowStyles : tdStyles}>\n        <Handle ref={handleRef} />\n      </td>\n      {columns.map((column) => (\n        <td key={column.id} style={lastRow ? tdLastRowStyles : tdStyles}>\n          {column.id === 'status' ? (\n            <span style={getStatusStyles(row[column.id])}>\n              {row[column.id]}\n            </span>\n          ) : (\n            row[column.id]\n          )}\n        </td>\n      ))}\n    </tr>\n  );\n}\n\nconst tableStyles: React.CSSProperties = {\n  width: '100%',\n  borderCollapse: 'separate',\n  borderSpacing: 0,\n  fontFamily: 'system-ui, sans-serif',\n  fontSize: 14,\n};\n\nconst thStyles: React.CSSProperties = {\n  textAlign: 'left',\n  padding: '10px 16px',\n  borderBottom: '2px solid #e2e8f0',\n  color: '#64748b',\n  fontWeight: 600,\n  fontSize: 12,\n  textTransform: 'uppercase',\n  letterSpacing: '0.05em',\n};\n\nconst trStyles: React.CSSProperties = {\n  backgroundColor: '#fff',\n};\n\nconst tdStyles: React.CSSProperties = {\n  padding: '12px 16px',\n  borderBottom: '1px solid #e2e8f0',\n};\n\nconst tdLastRowStyles: React.CSSProperties = {\n  padding: '12px 16px',\n};\n\nfunction getStatusStyles(status: string): React.CSSProperties {\n  const colors: Record<string, {bg: string; text: string}> = {\n    Active: {bg: '#dcfce7', text: '#166534'},\n    Away: {bg: '#fef9c3', text: '#854d0e'},\n    Offline: {bg: '#f1f5f9', text: '#475569'},\n  };\n\n  const {bg, text} = colors[status] ?? colors.Offline;\n\n  return {\n    padding: '2px 10px',\n    borderRadius: 12,\n    fontSize: 12,\n    fontWeight: 500,\n    backgroundColor: bg,\n    color: text,\n  };\n}\n"
  },
  {
    "path": "apps/stories/stories/react/Sortable/Transformed/Transformed.stories.tsx",
    "content": "import type {Meta, StoryObj} from '@storybook/react-vite';\n\nimport {TransformedExample} from './TransformedExample';\n\nconst meta: Meta<typeof TransformedExample> = {\n  title: 'React/Sortable/Transformed',\n  component: TransformedExample,\n};\n\nexport default meta;\ntype Story = StoryObj<typeof TransformedExample>;\n\nexport const WithoutOverlay: Story = {\n  name: 'Without overlay',\n  args: {\n    overlay: false,\n  },\n};\n\nexport const WithOverlay: Story = {\n  name: 'With overlay',\n  args: {\n    overlay: true,\n  },\n};\n"
  },
  {
    "path": "apps/stories/stories/react/Sortable/Transformed/TransformedExample.tsx",
    "content": "import React, {useState} from 'react';\nimport type {CSSProperties} from 'react';\nimport type {UniqueIdentifier} from '@dnd-kit/abstract';\nimport {DragDropProvider, DragOverlay} from '@dnd-kit/react';\nimport {useSortable} from '@dnd-kit/react/sortable';\nimport {Debug} from '@dnd-kit/dom/plugins/debug';\nimport {move} from '@dnd-kit/helpers';\n\nimport {Item} from '../../components/index.ts';\nimport {createRange} from '@dnd-kit/stories-shared/utilities';\n\nconst ITEM_HEIGHT = 62;\n\ninterface Props {\n  debug?: boolean;\n  overlay?: boolean;\n}\n\n/**\n * Sortable list where items are absolutely positioned using CSS\n * `transform: translateY()`. This mimics the positioning strategy used by\n * virtualization libraries like react-window v2 and is useful for testing\n * that @dnd-kit correctly handles elements with pre-existing CSS transforms.\n */\nexport function TransformedExample({debug, overlay}: Props) {\n  const [items, setItems] = useState<UniqueIdentifier[]>(createRange(10));\n\n  return (\n    <DragDropProvider\n      plugins={debug ? (defaults) => [Debug, ...defaults] : undefined}\n      onDragOver={(event) => {\n        setItems((items) => move(items, event));\n      }}\n      onDragEnd={(event) => {\n        setItems((items) => move(items, event));\n      }}\n    >\n      <div\n        style={{\n          position: 'relative',\n          maxWidth: 600,\n          margin: '0 auto',\n          height: items.length * ITEM_HEIGHT,\n        }}\n      >\n        {items.map((id, index) => (\n          <TransformedItem\n            key={id}\n            id={id}\n            index={index}\n            overlay={overlay}\n            style={{\n              position: 'absolute',\n              left: 0,\n              width: '100%',\n              height: ITEM_HEIGHT,\n              transform: `translateY(${index * ITEM_HEIGHT}px)`,\n            }}\n          />\n        ))}\n      </div>\n      {overlay ? (\n        <DragOverlay>\n          {(source) => (\n            <Item shadow={source.isDragging}>{source.id}</Item>\n          )}\n        </DragOverlay>\n      ) : null}\n    </DragDropProvider>\n  );\n}\n\ninterface TransformedItemProps {\n  id: UniqueIdentifier;\n  index: number;\n  overlay?: boolean;\n  style: CSSProperties;\n}\n\nfunction TransformedItem({id, index, overlay, style}: TransformedItemProps) {\n  const {isDragSource, isDragging, ref} = useSortable({\n    id,\n    index,\n  });\n\n  return (\n    <Item\n      ref={ref}\n      actions={<></>}\n      style={{\n        ...style,\n        display: 'flex',\n        justifyContent: 'center',\n        alignItems: 'center',\n        boxSizing: 'border-box',\n      }}\n      data-index={index}\n      shadow={!overlay && isDragging}\n      aria-hidden={overlay ? isDragSource : undefined}\n    >\n      {id}\n    </Item>\n  );\n}\n"
  },
  {
    "path": "apps/stories/stories/react/Sortable/Tree/Tree.module.css",
    "content": ".Tree {\n  max-width: 600px;\n  padding: 10px;\n  margin: 10% auto 0px;\n}\n\n.TreeItem {\n  position: relative;\n  display: flex;\n  align-items: center;\n  padding: 10px;\n  gap: 10px;\n  background-color: #fff;\n  border: 1px solid #dedede;\n  margin-bottom: -1px;\n  color: #222;\n  box-sizing: border-box;\n\n  &:first-child {\n    border-top-left-radius: 6px;\n    border-top-right-radius: 6px;\n  }\n\n  &:last-child {\n    border-bottom-left-radius: 6px;\n    border-bottom-right-radius: 6px;\n  }\n\n  &[data-overlay] {\n    width: max-content !important;\n    padding-right: 24px;\n    border-radius: 6px;\n    box-shadow: 0px 15px 15px 0 rgba(34, 33, 81, 0.1);\n  }\n}\n\n.TreeItem[aria-hidden=\"true\"] {\n  opacity: 0.4;\n\n  .Handle {\n    visibility: hidden;\n  }\n}\n\n.Action {\n  margin-left: auto;\n}\n\n.Badge {\n  position: absolute;\n  top: -10px;\n  right: -10px;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  width: 24px;\n  height: 24px;\n  border-radius: 50%;\n  background-color: #2389ff;\n  font-size: 0.8rem;\n  font-weight: 500;\n  color: #fff;\n}\n"
  },
  {
    "path": "apps/stories/stories/react/Sortable/Tree/Tree.stories.tsx",
    "content": "import React, {useState} from 'react';\nimport type {Meta, StoryObj} from '@storybook/react-vite';\n\nimport {Tree} from './Tree';\nimport type {Item} from './types';\n\nconst meta: Meta<typeof Tree> = {\n  title: 'React/Sortable/Tree',\n  component: Tree,\n};\n\nexport default meta;\ntype Story = StoryObj<typeof Tree>;\n\nexport const Example: Story = {\n  name: 'Example',\n  render: () => {\n    const [items, setItems] = useState<Item[]>([\n      {\n        id: 'Home',\n        children: [],\n      },\n      {\n        id: 'Collections',\n        children: [\n          {id: 'Spring', children: []},\n          {id: 'Summer', children: []},\n          {id: 'Fall', children: []},\n          {id: 'Winter', children: []},\n        ],\n      },\n      {\n        id: 'About Us',\n        children: [],\n      },\n      {\n        id: 'My Account',\n        children: [\n          {id: 'Addresses', children: []},\n          {id: 'Order History', children: []},\n        ],\n      },\n    ]);\n\n    return <Tree items={items} onChange={setItems} />;\n  },\n};\n"
  },
  {
    "path": "apps/stories/stories/react/Sortable/Tree/Tree.tsx",
    "content": "import {useRef, useState} from 'react';\nimport {DragDropProvider, DragOverlay} from '@dnd-kit/react';\nimport {isKeyboardEvent} from '@dnd-kit/dom/utilities';\nimport {move} from '@dnd-kit/helpers';\n\nimport {FlattenedItem, type Item} from './types.js';\nimport {\n  flattenTree,\n  buildTree,\n  getProjection,\n  getDragDepth,\n  getDescendants,\n} from './utilities.js';\nimport {TreeItem} from './TreeItem.js';\nimport {TreeItemOverlay} from './TreeItemOverlay.js';\nimport styles from './Tree.module.css';\n\ninterface Props {\n  items: Item[];\n  indentation?: number;\n  onChange(items: Item[]): void;\n}\n\nexport function Tree({items, indentation = 50, onChange}: Props) {\n  const [flattenedItems, setFlattenedItems] = useState<FlattenedItem[]>(() =>\n    flattenTree(items)\n  );\n  const initialDepth = useRef(0);\n  const sourceChildren = useRef<FlattenedItem[]>([]);\n\n  return (\n    <DragDropProvider\n      onDragStart={(event) => {\n        const {source} = event.operation;\n\n        if (!source) return;\n\n        const {depth} = flattenedItems.find(({id}) => id === source.id)!;\n\n        // Store the source item's initial depth for later use\n        initialDepth.current = depth;\n\n        setFlattenedItems((flattenedItems) => {\n          sourceChildren.current = [];\n\n          // Get all descendants of the source item\n          const descendants = getDescendants(flattenedItems, source.id);\n\n          return flattenedItems.filter((item) => {\n            if (descendants.has(item.id)) {\n              sourceChildren.current = [...sourceChildren.current, item];\n              return false;\n            }\n\n            return true;\n          });\n        });\n\n        initialDepth.current = depth;\n      }}\n      onDragOver={(event, manager) => {\n        const {source, target} = event.operation;\n\n        event.preventDefault();\n\n        if (source && target && source.id !== target.id) {\n          setFlattenedItems((flattenedItems) => {\n            const offsetLeft = manager.dragOperation.transform.x;\n            const dragDepth = getDragDepth(offsetLeft, indentation);\n            const projectedDepth = initialDepth.current + dragDepth;\n\n            const {depth, parentId} = getProjection(\n              flattenedItems,\n              target.id,\n              projectedDepth\n            );\n\n            const sortedItems = move(flattenedItems, event);\n            const newItems = sortedItems.map((item) =>\n              item.id === source.id ? {...item, depth, parentId} : item\n            );\n\n            return newItems;\n          });\n        }\n      }}\n      onDragMove={(event, manager) => {\n        if (event.defaultPrevented) {\n          return;\n        }\n\n        const {source, target} = event.operation;\n\n        if (source && target) {\n          const keyboard = isKeyboardEvent(event.operation.activatorEvent);\n          const currentDepth = source.data!.depth ?? 0;\n          let keyboardDepth;\n\n          if (keyboard) {\n            const isHorizontal = event.by?.x !== 0 && event.by?.y === 0;\n\n            if (isHorizontal) {\n              event.preventDefault();\n\n              keyboardDepth = currentDepth + Math.sign(event.by!.x);\n            }\n          }\n\n          const offsetLeft = manager.dragOperation.transform.x;\n          const dragDepth = getDragDepth(offsetLeft, indentation);\n\n          const projectedDepth =\n            keyboardDepth ?? initialDepth.current + dragDepth;\n\n          const {depth, parentId} = getProjection(\n            flattenedItems,\n            source.id,\n            projectedDepth\n          );\n\n          if (keyboard) {\n            if (currentDepth !== depth) {\n              const offset = indentation * (depth - currentDepth);\n\n              manager.actions.move({\n                by: {x: offset, y: 0},\n                propagate: false,\n              });\n            }\n          }\n\n          if (\n            source.data!.depth !== depth ||\n            source.data!.parentId !== parentId\n          ) {\n            setFlattenedItems((flattenedItems) => {\n              return flattenedItems.map((item) =>\n                item.id === source.id ? {...item, depth, parentId} : item\n              );\n            });\n          }\n        }\n      }}\n      onDragEnd={(event) => {\n        if (event.canceled) {\n          return setFlattenedItems(flattenTree(items));\n        }\n\n        const updatedTree = buildTree([\n          ...flattenedItems,\n          ...sourceChildren.current,\n        ]);\n\n        setFlattenedItems(flattenTree(updatedTree));\n\n        onChange(updatedTree);\n      }}\n    >\n      <ul className={styles.Tree}>\n        {flattenedItems.map((item, index) => (\n          <TreeItem\n            key={item.id}\n            {...item}\n            index={index}\n            onRemove={() => {\n              const newItems = flattenedItems.filter(({id}) => id !== item.id);\n              const tree = buildTree(newItems);\n\n              setFlattenedItems(flattenTree(tree));\n              onChange(tree);\n            }}\n          />\n        ))}\n      </ul>\n      <DragOverlay style={{width: 'min-content'}}>\n        {(source) => (\n          <TreeItemOverlay\n            id={source.id}\n            count={sourceChildren.current.length}\n          />\n        )}\n      </DragOverlay>\n    </DragDropProvider>\n  );\n}\n"
  },
  {
    "path": "apps/stories/stories/react/Sortable/Tree/TreeItem.tsx",
    "content": "import {useSortable} from '@dnd-kit/react/sortable';\n\nimport {Handle} from '../../components/Handle/Handle.tsx';\nimport {Remove} from '../../components/Actions/Remove.tsx';\n\nimport {FlattenedItem} from './types.ts';\nimport styles from './Tree.module.css';\n\nexport interface Props extends FlattenedItem {\n  onRemove?(): void;\n}\n\nconst INDENTATION = 50;\n\nconst config = {\n  alignment: {\n    x: 'start',\n    y: 'center',\n  },\n  transition: {\n    idle: true,\n  },\n} as const;\n\nexport function TreeItem({depth, id, index, parentId, onRemove}: Props) {\n  const {ref, handleRef, isDragSource} = useSortable({\n    ...config,\n    id,\n    index,\n    data: {\n      depth,\n      parentId,\n    },\n  });\n\n  return (\n    <li\n      ref={ref}\n      className={styles.TreeItem}\n      style={{\n        marginLeft: depth * INDENTATION,\n      }}\n      aria-hidden={isDragSource}\n    >\n      <span className={styles.Handle}>\n        <Handle ref={handleRef} />\n      </span>\n      {id}\n      {onRemove && (\n        <div className={styles.Action}>\n          <Remove onClick={onRemove} />\n        </div>\n      )}\n    </li>\n  );\n}\n"
  },
  {
    "path": "apps/stories/stories/react/Sortable/Tree/TreeItemOverlay.tsx",
    "content": "import type {UniqueIdentifier} from '@dnd-kit/abstract';\n\nimport {Handle} from '../../components/Handle/Handle.tsx';\nimport styles from './Tree.module.css';\n\ninterface Props {\n  id: UniqueIdentifier;\n  count: number;\n}\n\nexport function TreeItemOverlay({id, count}: Props) {\n  return (\n    <div className={styles.TreeItem} data-overlay>\n      <Handle />\n      {id}\n      {count > 0 ? <span className={styles.Badge}>{count}</span> : null}\n    </div>\n  );\n}\n"
  },
  {
    "path": "apps/stories/stories/react/Sortable/Tree/types.ts",
    "content": "export interface Item {\n  id: string;\n  children: Item[];\n  collapsed?: boolean;\n}\n\nexport interface FlattenedItem extends Item {\n  parentId: string | null;\n  depth: number;\n  index: number;\n}\n"
  },
  {
    "path": "apps/stories/stories/react/Sortable/Tree/utilities.ts",
    "content": "import {UniqueIdentifier} from '@dnd-kit/abstract';\n\nimport type {Item, FlattenedItem} from './types.ts';\n\nexport function flattenTree(\n  items: Item[],\n  parentId: string | null = null,\n  depth = 0\n): FlattenedItem[] {\n  return items.reduce<FlattenedItem[]>((acc, item, index) => {\n    return [\n      ...acc,\n      {...item, parentId, depth, index},\n      ...flattenTree(item.children, item.id, depth + 1),\n    ];\n  }, []);\n}\n\nexport function buildTree(flattenedItems: FlattenedItem[]): Item[] {\n  const root: Item = {id: 'root', children: []};\n  const nodes: Record<string, Item> = {[root.id]: root};\n  const items = flattenedItems.map((item) => ({...item, children: []}));\n\n  for (const item of items) {\n    const {id, children} = item;\n    const parentId = item.parentId ?? root.id;\n    const parent = nodes[parentId] ?? items.find(({id}) => id === parentId);\n\n    if (!parent) continue;\n\n    nodes[id] = {id, children};\n    parent.children.push(item);\n  }\n\n  return root.children;\n}\n\nexport function getDragDepth(offset: number, indentationWidth: number) {\n  return Math.round(offset / indentationWidth);\n}\n\nexport function getProjection(\n  items: FlattenedItem[],\n  targetId: UniqueIdentifier,\n  projectedDepth: number\n) {\n  const targetItemIndex = items.findIndex(({id}) => id === targetId);\n  const previousItem = items[targetItemIndex - 1];\n  const targetItem = items[targetItemIndex];\n  const nextItem = items[targetItemIndex + 1];\n  const maxDepth = getMaxDepth(targetItem, previousItem);\n  const minDepth = getMinDepth(nextItem);\n  let depth = projectedDepth;\n\n  if (projectedDepth >= maxDepth) {\n    depth = maxDepth;\n  } else if (projectedDepth < minDepth) {\n    depth = minDepth;\n  }\n\n  return {depth, maxDepth, minDepth, parentId: getParentId()};\n\n  function getParentId() {\n    if (depth === 0 || !previousItem) {\n      return null;\n    }\n\n    if (depth === previousItem.depth) {\n      return previousItem.parentId;\n    }\n\n    if (depth > previousItem.depth) {\n      return previousItem.id;\n    }\n\n    const newParent = items\n      .slice(0, targetItemIndex)\n      .reverse()\n      .find((item) => item.depth === depth)?.parentId;\n\n    return newParent ?? null;\n  }\n}\n\nfunction getMaxDepth(\n  targetItem: FlattenedItem,\n  previousItem: FlattenedItem | undefined\n) {\n  if (!previousItem) return 0;\n\n  return Math.min(targetItem.depth + 1, previousItem.depth + 1);\n}\n\nfunction getMinDepth(nextItem: FlattenedItem) {\n  return nextItem ? nextItem.depth : 0;\n}\n\nexport function getDescendants(\n  items: FlattenedItem[],\n  parentId: UniqueIdentifier\n): Set<UniqueIdentifier> {\n  const directChildren = items.filter((item) => item.parentId === parentId);\n\n  return directChildren.reduce((descendants, child) => {\n    return new Set([\n      ...descendants,\n      child.id,\n      ...getDescendants(items, child.id),\n    ]);\n  }, new Set<UniqueIdentifier>());\n}\n"
  },
  {
    "path": "apps/stories/stories/react/Sortable/Vertical/AutoScrollExample.tsx",
    "content": "import React, {useState, memo} from 'react';\nimport type {PropsWithChildren} from 'react';\nimport type {Axis} from '@dnd-kit/geometry';\nimport {AutoScroller} from '@dnd-kit/dom';\nimport {DragDropProvider} from '@dnd-kit/react';\nimport {useSortable} from '@dnd-kit/react/sortable';\nimport {move} from '@dnd-kit/helpers';\nimport {directionBiased} from '@dnd-kit/collision';\n\nimport {Item} from '../../components/index.ts';\nimport {createRange} from '@dnd-kit/stories-shared/utilities';\n\ninterface Props {\n  itemCount?: number;\n  acceleration?: number;\n  threshold?: number | Record<Axis, number>;\n}\n\nexport function AutoScrollExample({\n  itemCount = 100,\n  acceleration,\n  threshold,\n}: Props) {\n  const [items, setItems] = useState(createRange(itemCount));\n\n  const plugins =\n    acceleration != null || threshold != null\n      ? (defaults: any) => [\n          ...defaults,\n          AutoScroller.configure({acceleration, threshold}),\n        ]\n      : undefined;\n\n  return (\n    <DragDropProvider\n      plugins={plugins}\n      onDragEnd={(event) => {\n        setItems((items) => move(items, event));\n      }}\n    >\n      <div style={{display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 18, padding: '0 30px'}}>\n        {items.map((id, index) => (\n          <SortableItem key={id} id={id} index={index} />\n        ))}\n      </div>\n    </DragDropProvider>\n  );\n}\n\nconst SortableItem = memo(function SortableItem({\n  id,\n  index,\n}: PropsWithChildren<{id: number; index: number}>) {\n  const [element, setElement] = useState<Element | null>(null);\n  const {isDragging} = useSortable({\n    id,\n    index,\n    element,\n    collisionDetector: directionBiased,\n  });\n\n  return (\n    <Item ref={setElement} shadow={isDragging}>\n      {id}\n    </Item>\n  );\n});\n"
  },
  {
    "path": "apps/stories/stories/react/Sortable/Vertical/Vertical.stories.tsx",
    "content": "import type {Meta, StoryObj} from '@storybook/react-vite';\nimport {RestrictToVerticalAxis} from '@dnd-kit/abstract/modifiers';\nimport {Feedback} from '@dnd-kit/dom';\n\nimport {SortableExample} from '../SortableExample';\nimport {AutoScrollExample} from './AutoScrollExample';\n\nconst meta: Meta<typeof SortableExample> = {\n  title: 'React/Sortable/Vertical list',\n  component: SortableExample,\n};\n\nexport default meta;\ntype Story = StoryObj<typeof SortableExample>;\n\nexport const BasicSetup: Story = {\n  name: 'Basic setup',\n  args: {\n    debug: false,\n    itemCount: 100,\n  },\n};\n\nexport const WithDragHandle: Story = {\n  name: 'Drag handle',\n  args: {\n    debug: false,\n    dragHandle: true,\n    itemCount: 100,\n  },\n};\n\nexport const VariableHeights: Story = {\n  name: 'Variable heights',\n  args: {\n    debug: false,\n    getItemStyle(id: number) {\n      const heights: Record<number, number> = {\n        1: 100,\n        3: 150,\n        5: 200,\n        8: 100,\n        12: 150,\n      };\n\n      return {\n        height: heights[id],\n      };\n    },\n  },\n};\n\nexport const DynamicHeights: Story = {\n  name: 'Dynamic heights',\n  args: {\n    debug: false,\n    optimistic: false,\n    getItemStyle(_: number, index: number) {\n      const heights: Record<number, number> = {\n        1: 100,\n        3: 150,\n        5: 200,\n        8: 100,\n        12: 150,\n      };\n\n      return {\n        height: heights[index],\n      };\n    },\n  },\n};\n\nexport const Clone: Story = {\n  name: 'Clone feedback',\n  args: {\n    debug: false,\n    plugins: [Feedback.configure({feedback: 'clone'})],\n  },\n};\n\nexport const RestrictAxis: Story = {\n  name: 'Restrict axis',\n  args: {\n    debug: false,\n    modifiers: [RestrictToVerticalAxis],\n  },\n};\n\nexport const DisabledItems: Story = {\n  name: 'Disabled items',\n  args: {\n    debug: false,\n    disabled: [2, 3, 8, 12],\n  },\n};\n\nexport const CustomTransition: Story = {\n  name: 'Custom transition',\n  args: {\n    debug: false,\n    transition: {\n      duration: 300,\n      easing: 'cubic-bezier(0.34, 1.56, 0.64, 1)',\n    },\n  },\n};\n\nexport const DisableTransition: Story = {\n  name: 'Disable transition',\n  args: {\n    debug: false,\n    transition: {\n      duration: 0,\n    },\n  },\n};\n\nexport const Debug: Story = {\n  name: 'Debug',\n  args: {\n    debug: true,\n  },\n};\n\ntype AutoScrollStory = StoryObj<typeof AutoScrollExample>;\n\nexport const AutoScrollDisabled: AutoScrollStory = {\n  name: 'Auto-scroll disabled',\n  render: (args: React.ComponentProps<typeof AutoScrollExample>) => <AutoScrollExample {...args} />,\n  args: {\n    itemCount: 100,\n    threshold: 0,\n  },\n};\n\nexport const AutoScrollCustomSpeed: AutoScrollStory = {\n  name: 'Auto-scroll custom speed',\n  render: (args: React.ComponentProps<typeof AutoScrollExample>) => <AutoScrollExample {...args} />,\n  args: {\n    itemCount: 100,\n    acceleration: 50,\n  },\n};\n"
  },
  {
    "path": "apps/stories/stories/react/Sortable/Virtualized/ReactTinyVirtualListExample.tsx",
    "content": "import React, {useRef, useState} from 'react';\nimport type {UniqueIdentifier} from '@dnd-kit/abstract';\nimport {DragDropProvider} from '@dnd-kit/react';\nimport {useSortable} from '@dnd-kit/react/sortable';\nimport {Debug} from '@dnd-kit/dom/plugins/debug';\nimport {move} from '@dnd-kit/helpers';\nimport VirtualList from 'react-tiny-virtual-list';\n\nimport {Item, Handle} from '../../components';\nimport {createRange} from '@dnd-kit/stories-shared/utilities';\n\ninterface Props {\n  debug?: boolean;\n}\n\nexport function ReactTinyVirtualListExample({debug}: Props) {\n  const [items, setItems] = useState<UniqueIdentifier[]>(createRange(1000));\n  const snapshot = useRef(structuredClone(items));\n\n  return (\n    <DragDropProvider\n      plugins={debug ? (defaults) => [Debug, ...defaults] : undefined}\n      onDragStart={() => {\n        snapshot.current = structuredClone(items);\n      }}\n      onDragOver={(event) => {\n        setItems((items) => move(items, event));\n      }}\n      onDragEnd={(event) => {\n        if (event.canceled) {\n          setItems(snapshot.current);\n        }\n      }}\n    >\n      <VirtualList\n        width={window.innerWidth - 100}\n        height={window.innerHeight - 100}\n        itemCount={items.length}\n        itemSize={82}\n        renderItem={({index, style}) => {\n          const id = items[index];\n\n          return <Sortable key={id} id={id} index={index} style={style} />;\n        }}\n      />\n    </DragDropProvider>\n  );\n}\n\ninterface SortableProps {\n  id: UniqueIdentifier;\n  index: number;\n  style: React.CSSProperties;\n}\n\nfunction Sortable({id, index, style}: SortableProps) {\n  const {isDragging, ref, handleRef} = useSortable({\n    id,\n    index,\n  });\n\n  return (\n    <div\n      ref={ref}\n      style={{...style, display: 'flex', justifyContent: 'center', padding: 10}}\n    >\n      <Item\n        actions={<Handle ref={handleRef} />}\n        data-index={index}\n        shadow={isDragging}\n      >\n        {id}\n      </Item>\n    </div>\n  );\n}\n"
  },
  {
    "path": "apps/stories/stories/react/Sortable/Virtualized/ReactVirtualExample.tsx",
    "content": "import React, {forwardRef, useLayoutEffect, useRef, useState} from 'react';\nimport type {PropsWithChildren} from 'react';\nimport type {UniqueIdentifier} from '@dnd-kit/abstract';\nimport {DragDropProvider} from '@dnd-kit/react';\nimport {useSortable} from '@dnd-kit/react/sortable';\nimport {Feedback} from '@dnd-kit/dom';\nimport {Debug} from '@dnd-kit/dom/plugins/debug';\nimport {move} from '@dnd-kit/helpers';\nimport {useWindowVirtualizer} from '@tanstack/react-virtual';\n\nimport {Item, Handle} from '../../components';\nimport {createRange} from '@dnd-kit/stories-shared/utilities';\n\ninterface Props {\n  debug?: boolean;\n}\n\nexport function ReactVirtualExample({debug}: Props) {\n  const [items, setItems] = useState<UniqueIdentifier[]>(createRange(1000));\n  const snapshot = useRef(structuredClone(items));\n\n  const parentRef = React.useRef<HTMLDivElement>(null);\n  const parentOffsetRef = React.useRef(0);\n\n  const virtualizer = useWindowVirtualizer({\n    count: items.length,\n    estimateSize: () => 72,\n    scrollMargin: parentOffsetRef.current,\n    getItemKey: (index) => items[index],\n  });\n  const virtualItems = virtualizer.getVirtualItems();\n\n  useLayoutEffect(() => {\n    parentOffsetRef.current = parentRef.current?.offsetTop ?? 0;\n  }, []);\n\n  return (\n    <DragDropProvider\n      plugins={debug ? (defaults) => [Debug, ...defaults] : undefined}\n      onDragStart={() => {\n        snapshot.current = structuredClone(items);\n      }}\n      onDragOver={(event) => {\n        setItems((items) => move(items, event));\n      }}\n      onDragEnd={(event) => {\n        if (event.canceled) {\n          setItems(snapshot.current);\n        }\n      }}\n    >\n      <div ref={parentRef}>\n        <div\n          style={{\n            height: virtualizer.getTotalSize(),\n            width: '100%',\n            position: 'relative',\n          }}\n        >\n          <div\n            style={{\n              position: 'absolute',\n              inset: 0,\n              display: 'flex',\n              flexDirection: 'column',\n              padding: 20,\n              alignItems: 'center',\n              gap: 20,\n              transform: `translateY(${\n                virtualItems[0]?.start - virtualizer.options.scrollMargin\n              }px)`,\n            }}\n          >\n            {virtualItems.map(({key, index}) => {\n              return (\n                <Sortable\n                  ref={virtualizer.measureElement}\n                  key={key}\n                  id={items[index]}\n                  index={index}\n                />\n              );\n            })}\n          </div>\n        </div>\n      </div>\n    </DragDropProvider>\n  );\n}\n\ninterface SortableProps {\n  id: UniqueIdentifier;\n  index: number;\n}\n\nconst Sortable = forwardRef<Element, PropsWithChildren<SortableProps>>(\n  function Sortable({id, index}, ref) {\n    const [element, setElement] = useState<Element | null>(null);\n    const handleRef = useRef<HTMLButtonElement | null>(null);\n\n    const {isDragging} = useSortable({\n      id,\n      index,\n      element,\n      plugins: [Feedback.configure({feedback: 'clone'})],\n      handle: handleRef,\n    });\n\n    return (\n      <Item\n        ref={setElement}\n        actions={<Handle ref={handleRef} />}\n        data-index={index}\n        shadow={isDragging}\n      >\n        {id}\n      </Item>\n    );\n  }\n);\n"
  },
  {
    "path": "apps/stories/stories/react/Sortable/Virtualized/ReactWindowExample.tsx",
    "content": "import React, {useRef, useEffect, useState} from 'react';\nimport type {UniqueIdentifier} from '@dnd-kit/abstract';\nimport {DragDropProvider} from '@dnd-kit/react';\nimport {useSortable} from '@dnd-kit/react/sortable';\nimport {Debug} from '@dnd-kit/dom/plugins/debug';\nimport {move} from '@dnd-kit/helpers';\nimport {FixedSizeList as List} from 'react-window';\n\nimport {Item, Handle} from '../../components';\nimport {createRange} from '@dnd-kit/stories-shared/utilities';\n\ninterface Props {\n  debug?: boolean;\n}\n\nexport function ReactWindowExample({debug}: Props) {\n  const [items, setItems] = useState<UniqueIdentifier[]>(createRange(1000));\n  const snapshot = useRef(structuredClone(items));\n\n  return (\n    <DragDropProvider\n      plugins={debug ? (defaults) => [Debug, ...defaults] : undefined}\n      onDragStart={() => {\n        snapshot.current = structuredClone(items);\n      }}\n      onDragOver={(event) => {\n        setItems((items) => move(items, event));\n      }}\n      onDragEnd={(event) => {\n        if (event.canceled) {\n          setItems(snapshot.current);\n        }\n      }}\n    >\n      <List\n        width={window.innerWidth - 100}\n        height={window.innerHeight - 100}\n        itemCount={items.length}\n        itemSize={82}\n        itemData={items}\n        itemKey={(index) => items[index]}\n        style={{margin: '0 auto'}}\n      >\n        {Row}\n      </List>\n    </DragDropProvider>\n  );\n}\n\nfunction Row({\n  data,\n  index,\n  style,\n}: {\n  data: UniqueIdentifier[];\n  index: number;\n  style: React.CSSProperties;\n}) {\n  return <Sortable id={data[index]} index={index} style={style} />;\n}\n\ninterface SortableProps {\n  id: UniqueIdentifier;\n  index: number;\n  style: React.CSSProperties;\n}\n\nfunction Sortable({id, index, style}: SortableProps) {\n  const {isDragging, ref, handleRef} = useSortable({\n    id,\n    index,\n  });\n\n  return (\n    <div\n      ref={ref}\n      style={{...style, display: 'flex', justifyContent: 'center', padding: 10}}\n    >\n      <Item\n        actions={<Handle ref={handleRef} />}\n        data-index={index}\n        shadow={isDragging}\n      >\n        {id}\n      </Item>\n    </div>\n  );\n}\n"
  },
  {
    "path": "apps/stories/stories/react/Sortable/Virtualized/Virtualized.stories.tsx",
    "content": "import type {Meta, StoryObj} from '@storybook/react-vite';\n\nimport {ReactWindowExample} from './ReactWindowExample';\nimport {ReactVirtualExample} from './ReactVirtualExample';\nimport {ReactTinyVirtualListExample} from './ReactTinyVirtualListExample';\n\nconst meta: Meta<typeof ReactVirtualExample> = {\n  title: 'React/Sortable/Virtualized',\n};\n\nexport default meta;\ntype Story = StoryObj<typeof ReactVirtualExample>;\n\nexport const ReactWindow: Story = {\n  name: 'react-window',\n  render: ReactWindowExample,\n};\n\nexport const ReactTinyVirtualList: Story = {\n  name: 'react-tiny-virtual-list',\n  render: ReactTinyVirtualListExample,\n};\n\nexport const ReactVirtual: Story = {\n  name: 'react-virtual',\n  render: ReactVirtualExample,\n};\n"
  },
  {
    "path": "apps/stories/stories/react/Sortable/docs/SortableDocs.mdx",
    "content": "import {Code, Preview} from '../../../components';\nimport {Example as Hero} from '../Sortable.stories';\nimport BasicSetupSource from '../SortableExample?raw';\nimport {Example} from './examples/Example';\nimport {Example as UncontrolledExample} from './examples/UncontrolledExample';\nimport UncontrolledExampleSource from './examples/UncontrolledExample?raw';\nimport ControlledExampleSource from './examples/ControlledExample?raw';\nimport image from './assets/useSortable.png';\n\n# Sortable\n\nReorder elements in a list or across multiple lists.\n\n<Preview of={Hero} hero />\n\n## Installation\n\nBefore getting started, make sure to install the `@dnd-kit/react` package:\n\n```bash\nnpm install @dnd-kit/react\n```\n\n## Getting started\n\nThe fastest way to get started is to the `useSortable` hook and provide it an `id` and an `index`:\n<Preview code={UncontrolledExampleSource}>\n  <UncontrolledExample />\n</Preview>\n\nThis will create an uncontrolled sortable list that will automatically update the order of the items in the DOM when they are dragged and dropped.\n\nTo create a controlled sortable list and update the order of the items in React, we can listen to the `onDragEnd` event emitted by the `<DragDropProvider>` component:\n<Preview code={ControlledExampleSource}>\n  <Example />\n</Preview>\n\nTo create a vertical list, we can update the of the `flex-direction` style property to `column`, without any other configuration changes.\n\n<Preview>\n  <Example style={{display: 'inline-flex', flexDirection: 'column', gap: 20}} />\n</Preview>\n\nTo create a grid list, we can update the of the `display` style property to `grid`, and set the `grid-template-columns` property to the desired number of columns.\n\n<Preview>\n  <Example\n    style={{\n      display: 'grid',\n      gridTemplateColumns: 'repeat(2, 150px)',\n      gridAutoRows: '150px',\n      gap: 20,\n    }}\n  />\n</Preview>\n\n## Architecture\n\nThe sortable plugin composes the `Draggable` and `Droppable` items to provide a simple API for building sortable interfaces.\n\nThe `useSortable` hook is an abstraction that composes the `useDroppable` and `useDraggable` hooks:\n\n<img src={image} width=\"70%\" />\n\nAs a result, the `useSortable` hook accepts all of the props that the `useDraggable` and `useDroppable` hooks accept.\n\n## Modifiers\n\nBecause the `useSortable` hook invokes the `useDraggable` hook under the hood, we can pass local `modifiers` to the `useSortable` hook just as we would with the `useDraggable` hook:\n\n```jsx\nconst sortable = useSortable({\n  id,\n  modifiers: [RestrictToVerticalAxis],\n});\n```\n"
  },
  {
    "path": "apps/stories/stories/react/Sortable/docs/examples/ControlledExample.jsx",
    "content": "import React, {useState} from 'react';\nimport {DragDropProvider} from '@dnd-kit/react';\nimport {useSortable} from '@dnd-kit/react/sortable';\nimport {move} from '@dnd-kit/helpers';\n\nconst styles = {display: 'inline-flex', flexDirection: 'row', gap: 20};\n\nexport function ControlledExample() {\n  const [items, setItems] = useState([0, 1, 2, 3]);\n\n  return (\n    <DragDropProvider\n      onDragEnd={(event) => {\n        setItems((items) => move(items, event));\n      }}\n    >\n      <div style={styles}>\n        {items.map((id, index) => (\n          <Sortable key={id} id={id} index={index} />\n        ))}\n      </div>\n    </DragDropProvider>\n  );\n}\n\nfunction Sortable({id, index}) {\n  const {ref} = useSortable({id, index});\n\n  return <button ref={ref}>Item {id}</button>;\n}\n"
  },
  {
    "path": "apps/stories/stories/react/Sortable/docs/examples/Example.jsx",
    "content": "import React, {useState} from 'react';\nimport {DragDropProvider} from '@dnd-kit/react';\nimport {useSortable} from '@dnd-kit/react/sortable';\nimport {move} from '@dnd-kit/helpers';\n\nconst styles = {display: 'inline-flex', flexDirection: 'row', gap: 20};\n\nexport function Example({style = styles}) {\n  const [items, setItems] = useState([0, 1, 2, 3]);\n\n  return (\n    <DragDropProvider\n      onDragEnd={(event) => {\n        setItems((items) => move(items, event));\n      }}\n    >\n      <div style={style}>\n        {items.map((id, index) => (\n          <Sortable key={id} id={id} index={index} />\n        ))}\n      </div>\n    </DragDropProvider>\n  );\n}\n\nfunction Sortable({id, index}) {\n  const {ref} = useSortable({id, index});\n\n  return <button ref={ref}>Item {id}</button>;\n}\n"
  },
  {
    "path": "apps/stories/stories/react/Sortable/docs/examples/UncontrolledExample.jsx",
    "content": "import React, {useState} from 'react';\nimport {DragDropProvider} from '@dnd-kit/react';\nimport {useSortable} from '@dnd-kit/react/sortable';\nimport {move} from '@dnd-kit/helpers';\n\nconst styles = {display: 'inline-flex', flexDirection: 'row', gap: 20};\n\nexport function Example() {\n  const items = [0, 1, 2, 3];\n\n  return (\n    <div style={styles}>\n      {items.map((id, index) => (\n        <Sortable key={id} id={id} index={index} />\n      ))}\n    </div>\n  );\n}\n\nfunction Sortable({id, index}) {\n  const {ref} = useSortable({id, index});\n\n  return <button ref={ref}>Item {id}</button>;\n}\n"
  },
  {
    "path": "apps/stories/stories/react/components/Actions/Action.tsx",
    "content": "import React, {forwardRef, CSSProperties, Ref} from 'react';\n\nimport {classNames} from '@dnd-kit/stories-shared/utilities';\n\nimport styles from './Actions.module.css';\n\nexport interface Props extends React.HTMLAttributes<HTMLButtonElement> {\n  variant?: 'light' | 'dark' | 'destructive';\n  cursor?: CSSProperties['cursor'];\n}\n\nexport const Action = forwardRef<HTMLButtonElement, Props>(\n  ({className, cursor, style, variant = 'light', ...props}, ref) => {\n    return (\n      <button\n        ref={ref}\n        {...props}\n        className={classNames(styles.Action, styles[variant], className)}\n        style={\n          {\n            ...style,\n            cursor,\n          } as CSSProperties\n        }\n      />\n    );\n  }\n);\n"
  },
  {
    "path": "apps/stories/stories/react/components/Actions/Actions.module.css",
    "content": ".Actions {\n  display: flex;\n}\n\n.Action {\n  display: flex;\n  width: 12px;\n  padding: 15px;\n  align-items: center;\n  justify-content: center;\n  flex: 0 0 auto;\n  touch-action: none;\n  cursor: var(--cursor, pointer);\n  border-radius: 5px;\n  border: none;\n  outline: none;\n  appearance: none;\n  background-color: transparent;\n  -webkit-tap-highlight-color: transparent;\n  user-select: none;\n  -webkit-user-select: none;\n\n  --fill: #919eab;\n}\n\n.Action:hover, .Action:active {\n  background-color: var(--background, rgba(0, 0, 0, 0.05));\n}\n\n.Action:focus-visible {\n  outline: none;\n  box-shadow: 0 0 0 2px rgba(255, 255, 255, 0), inset 0 0px 0px 2.5px #4c9ffe;\n}\n\n.Action svg {\n  flex: 0 0 auto;\n  margin: auto;\n  height: 100%;\n  overflow: visible;\n  fill: var(--fill);\n}\n\n.Action:active, .Action:hover {\n  --fill: #6f7b88;\n}\n\n.dark {\n  --background: rgba(255, 255, 255, 0.1);\n}\n\n.destructive {\n  visibility: hidden;\n}\n\n.destructive:hover {\n  --fill: rgba(255, 70, 70, 0.95);\n  --background: rgba(255, 70, 70, 0.1);\n}\n\n\n*:hover > .Actions .destructive, li:hover .destructive {\n  visibility: visible;\n}\n"
  },
  {
    "path": "apps/stories/stories/react/components/Actions/Actions.tsx",
    "content": "import React, {type PropsWithChildren} from 'react';\n\nimport styles from './Actions.module.css';\n\nexport function Actions(props: PropsWithChildren) {\n  return <div className={styles.Actions}>{props.children}</div>;\n}\n"
  },
  {
    "path": "apps/stories/stories/react/components/Actions/Remove.tsx",
    "content": "import React from 'react';\n\nimport {Action, Props as ActionProps} from './Action';\n\ninterface Props extends Omit<ActionProps, 'variant'> {}\n\nexport function Remove(props: Props) {\n  return (\n    <Action variant=\"destructive\" {...props}>\n      <svg width=\"8\" viewBox=\"0 0 22 22\" xmlns=\"http://www.w3.org/2000/svg\">\n        <path d=\"M2.99998 -0.000206962C2.7441 -0.000206962 2.48794 0.0972617 2.29294 0.292762L0.292945 2.29276C-0.0980552 2.68376 -0.0980552 3.31682 0.292945 3.70682L7.58591 10.9998L0.292945 18.2928C-0.0980552 18.6838 -0.0980552 19.3168 0.292945 19.7068L2.29294 21.7068C2.68394 22.0978 3.31701 22.0978 3.70701 21.7068L11 14.4139L18.2929 21.7068C18.6829 22.0978 19.317 22.0978 19.707 21.7068L21.707 19.7068C22.098 19.3158 22.098 18.6828 21.707 18.2928L14.414 10.9998L21.707 3.70682C22.098 3.31682 22.098 2.68276 21.707 2.29276L19.707 0.292762C19.316 -0.0982383 18.6829 -0.0982383 18.2929 0.292762L11 7.58573L3.70701 0.292762C3.51151 0.0972617 3.25585 -0.000206962 2.99998 -0.000206962Z\"></path>\n      </svg>\n    </Action>\n  );\n}\n"
  },
  {
    "path": "apps/stories/stories/react/components/Actions/index.ts",
    "content": "export {Action} from './Action';\nexport type {Props as ActionProps} from './Action';\n\nexport {Actions} from './Actions';\n\nexport {Remove} from './Remove';\n"
  },
  {
    "path": "apps/stories/stories/react/components/Button/Button.tsx",
    "content": "import React, {\n  forwardRef,\n  Fragment,\n  type HTMLAttributes,\n  type PropsWithChildren,\n} from 'react';\n\nexport interface Props extends HTMLAttributes<HTMLElement> {\n  actions?: React.ReactNode;\n  shadow?: boolean;\n}\n\nexport const Button = forwardRef<HTMLButtonElement, PropsWithChildren<Props>>(\n  function Button({actions, children, shadow, ...props}, ref) {\n    return (\n      <button\n        ref={ref}\n        className=\"btn\"\n        data-shadow={shadow ? 'true' : undefined}\n        {...props}\n      >\n        {children}\n        {actions}\n      </button>\n    );\n  }\n);\n"
  },
  {
    "path": "apps/stories/stories/react/components/Container/Container.tsx",
    "content": "import React, {forwardRef} from 'react';\n\nexport interface Props {\n  children: React.ReactNode;\n  actions?: React.ReactNode;\n  columns?: number;\n  label?: string;\n  scrollable?: boolean;\n  shadow?: boolean;\n  style?: React.CSSProperties;\n  transitionId?: string;\n}\n\nexport const Container = forwardRef<HTMLDivElement, Props>(\n  (\n    {\n      actions,\n      children,\n      columns = 1,\n      label,\n      style,\n      scrollable,\n      shadow,\n      transitionId,\n      ...props\n    }: Props,\n    ref\n  ) => {\n    return React.createElement(\n      'container-component',\n      {\n        ...props,\n        ref,\n        style: {\n          ...style,\n          viewTransitionName: transitionId,\n          '--columns': columns,\n        } as React.CSSProperties,\n        'data-shadow': shadow ? 'true' : undefined,\n        'data-scrollable': scrollable ? 'true' : undefined,\n      },\n      <>\n        {label ? (\n          <div className=\"Header\">\n            {label}\n            {actions}\n          </div>\n        ) : null}\n        <ul id={label}>{children}</ul>\n      </>\n    );\n  }\n);\n"
  },
  {
    "path": "apps/stories/stories/react/components/Dropzone/Dropzone.tsx",
    "content": "import React, {forwardRef} from 'react';\n\ninterface Props {\n  children: React.ReactNode;\n  highlight?: boolean;\n}\n\nexport const Dropzone = forwardRef<HTMLDivElement, Props>(function Dropzone(\n  {children, highlight},\n  ref\n) {\n  return (\n    <div ref={ref} className={highlight ? 'droppable active' : 'droppable'}>\n      {children}\n    </div>\n  );\n});\n"
  },
  {
    "path": "apps/stories/stories/react/components/Grid/Grid.module.css",
    "content": ".Grid {\n  position: fixed;\n  inset: 0;\n  background-image: repeating-linear-gradient(\n      0deg,\n      transparent,\n      transparent calc(var(--grid-size) - 1px),\n      #ddd calc(var(--grid-size) - 1px),\n      #ddd var(--grid-size)\n    ),\n    repeating-linear-gradient(\n      -90deg,\n      transparent,\n      transparent calc(var(--grid-size) - 1px),\n      #ddd calc(var(--grid-size) - 1px),\n      #ddd var(--grid-size)\n    );\n  background-size: var(--grid-size) var(--grid-size);\n}\n"
  },
  {
    "path": "apps/stories/stories/react/components/Grid/Grid.tsx",
    "content": "import React, {type PropsWithChildren} from 'react';\n\nimport styles from './Grid.module.css';\n\nexport interface Props extends PropsWithChildren {\n  size: number;\n}\n\nexport function Grid({children, size}: Props) {\n  return (\n    <div\n      className={styles.Grid}\n      style={\n        {\n          '--grid-size': `${size}px`,\n        } as React.CSSProperties\n      }\n    >\n      {children}\n    </div>\n  );\n}\n"
  },
  {
    "path": "apps/stories/stories/react/components/Handle/Handle.tsx",
    "content": "import React, {forwardRef} from 'react';\n\nexport interface HandleProps extends React.HTMLAttributes<HTMLButtonElement> {\n  variant?: string;\n}\n\nexport const Handle = forwardRef<HTMLButtonElement, HandleProps>(\n  ({variant, ...props}, ref) => {\n    return <button ref={ref} className=\"handle\" {...props} />;\n  }\n);\n"
  },
  {
    "path": "apps/stories/stories/react/components/Item/Item.tsx",
    "content": "import React, {\n  forwardRef,\n  type CSSProperties,\n  type HTMLAttributes,\n  type PropsWithChildren,\n} from 'react';\n\nexport interface Props extends HTMLAttributes<HTMLElement> {\n  actions?: React.ReactNode;\n  accentColor?: string;\n  shadow?: boolean;\n  transitionId?: string;\n}\n\nexport const Item = forwardRef<HTMLElement, PropsWithChildren<Props>>(\n  function Button(\n    {actions, accentColor, children, shadow, style, transitionId, ...props},\n    ref\n  ) {\n    const Element = actions ? 'div' : 'button';\n\n    return (\n      <Element\n        {...props}\n        className={'Item'}\n        style={\n          {\n            ...style,\n            viewTransitionName: transitionId,\n            '--accent-color': accentColor,\n          } as CSSProperties\n        }\n        data-shadow={shadow}\n        data-accent-color={accentColor}\n        ref={ref as any}\n      >\n        {children}\n        {actions}\n      </Element>\n    );\n  }\n);\n"
  },
  {
    "path": "apps/stories/stories/react/components/index.ts",
    "content": "export {Actions, Action, Remove} from './Actions/index.ts';\n\nexport {Button} from './Button/Button.tsx';\n\nexport {Container} from './Container/Container.tsx';\n\nexport {Dropzone} from './Dropzone/Dropzone.tsx';\n\nexport {Handle} from './Handle/Handle.tsx';\n\nexport {Item} from './Item/Item.tsx';\n\nexport {Grid} from './Grid/Grid.tsx';\n"
  },
  {
    "path": "apps/stories/stories/react/icons/SortableIcon.tsx",
    "content": "import {HTMLProps} from 'react';\n\nimport sortableIcon from '@dnd-kit/stories-shared/assets/sortableIcon.svg';\n\nexport const SortableIcon = (props: HTMLProps<HTMLImageElement>) => (\n  <img\n    src={sortableIcon}\n    width=\"90\"\n    alt=\"Sortable\"\n    draggable={false}\n    {...props}\n  />\n);\n"
  },
  {
    "path": "apps/stories/stories/react/icons/index.ts",
    "content": "export {SortableIcon} from './SortableIcon.tsx';\n"
  },
  {
    "path": "apps/stories/tests/drag-offset.spec.ts",
    "content": "import {dragOffsetTests} from '../../stories-shared/tests/drag-offset.tests.ts';\n\ndragOffsetTests({\n  draggable: 'react-draggable--example',\n  sortableVertical: 'react-sortable-vertical-list--basic-setup',\n});\n"
  },
  {
    "path": "apps/stories/tests/draggable.spec.ts",
    "content": "import {draggableTests} from '../../stories-shared/tests/draggable.tests.ts';\n\ndraggableTests({\n  example: 'react-draggable--example',\n  dragHandle: 'react-draggable-drag-handles--drag-handle',\n});\n"
  },
  {
    "path": "apps/stories/tests/droppable.spec.ts",
    "content": "import {droppableTests} from '../../stories-shared/tests/droppable.tests.ts';\n\ndroppableTests({\n  example: 'react-droppable--example',\n  multipleDropTargets: 'react-droppable-multiple-drop-targets--example',\n});\n"
  },
  {
    "path": "apps/stories/tests/sortable-autoscroll-options.spec.ts",
    "content": "import {test, expect} from '../../stories-shared/tests/fixtures.ts';\n\ntest.describe('AutoScroller options', () => {\n  test.describe('threshold: 0 (disabled)', () => {\n    test.beforeEach(async ({dnd}) => {\n      await dnd.goto('react-sortable-vertical-list--auto-scroll-disabled');\n      await expect(dnd.items.first()).toBeVisible();\n    });\n\n    test('does not auto-scroll when dragging near the bottom edge', async ({\n      dnd,\n    }) => {\n      const first = dnd.items.nth(0);\n      const box = await first.boundingBox();\n      const viewport = dnd.page.viewportSize()!;\n\n      await dnd.page.mouse.move(\n        box!.x + box!.width / 2,\n        box!.y + box!.height / 2\n      );\n      await dnd.page.mouse.down();\n\n      await dnd.page.mouse.move(\n        box!.x + box!.width / 2,\n        viewport.height - 10,\n        {steps: 20}\n      );\n\n      // Wait to give auto-scroll a chance to activate (it shouldn't)\n      await dnd.page.waitForTimeout(500);\n\n      const scrollTop = await dnd.page.evaluate(\n        () => document.scrollingElement?.scrollTop ?? 0\n      );\n\n      expect(scrollTop).toBe(0);\n\n      await dnd.page.mouse.up();\n      await dnd.waitForDrop();\n    });\n  });\n\n  test.describe('custom acceleration', () => {\n    test.beforeEach(async ({dnd}) => {\n      await dnd.goto('react-sortable-vertical-list--auto-scroll-custom-speed');\n      await expect(dnd.items.first()).toBeVisible();\n    });\n\n    test('auto-scrolls when dragging near the bottom edge', async ({dnd}) => {\n      const first = dnd.items.nth(0);\n      const box = await first.boundingBox();\n      const viewport = dnd.page.viewportSize()!;\n\n      await dnd.page.mouse.move(\n        box!.x + box!.width / 2,\n        box!.y + box!.height / 2\n      );\n      await dnd.page.mouse.down();\n\n      await dnd.page.mouse.move(\n        box!.x + box!.width / 2,\n        viewport.height - 10,\n        {steps: 20}\n      );\n\n      await expect\n        .poll(\n          () =>\n            dnd.page.evaluate(\n              () => document.scrollingElement?.scrollTop ?? 0\n            ),\n          {timeout: 3_000}\n        )\n        .toBeGreaterThan(0);\n\n      await dnd.page.mouse.up();\n      await dnd.waitForDrop();\n    });\n  });\n});\n"
  },
  {
    "path": "apps/stories/tests/sortable-css-layers.spec.ts",
    "content": "import {test, expect} from '../../stories-shared/tests/fixtures.ts';\n\nconst STORY_ID = 'react-sortable-css-layers--basic-setup';\n\ntest.describe('Sortable with CSS @layer styles', () => {\n  test.beforeEach(async ({dnd}) => {\n    await dnd.goto(STORY_ID);\n    await expect(dnd.page.locator('.test').first()).toBeVisible();\n  });\n\n  test('layered styles are preserved during drag', async ({dnd}) => {\n    const items = dnd.page.locator('.test');\n    const first = items.nth(0);\n    const third = items.nth(2);\n\n    await expect(first).toHaveCSS('background-color', 'rgb(232, 240, 254)');\n    await expect(first).toHaveCSS('border-color', 'rgb(76, 159, 254)');\n\n    const sourceBox = await first.boundingBox();\n    const targetBox = await third.boundingBox();\n\n    await dnd.page.mouse.move(\n      sourceBox!.x + sourceBox!.width / 2,\n      sourceBox!.y + sourceBox!.height / 2\n    );\n    await dnd.page.mouse.down();\n    await dnd.page.mouse.move(\n      targetBox!.x + targetBox!.width / 2,\n      targetBox!.y + targetBox!.height / 2,\n      {steps: 10}\n    );\n\n    await expect(dnd.dragging).toHaveCount(1);\n\n    const draggingEl = dnd.dragging.first();\n\n    await expect(draggingEl).toHaveCSS(\n      'background-color',\n      'rgb(232, 240, 254)'\n    );\n    await expect(draggingEl).toHaveCSS('border-color', 'rgb(76, 159, 254)');\n    await expect(draggingEl).toHaveCSS('color', 'rgb(26, 58, 92)');\n    await expect(draggingEl).toHaveCSS('padding', '12px 20px');\n    await expect(draggingEl).toHaveCSS('border-radius', '8px');\n\n    await dnd.page.mouse.up();\n    await dnd.waitForDrop();\n  });\n});\n"
  },
  {
    "path": "apps/stories/tests/sortable-grid.spec.ts",
    "content": "import {test, expect} from '../../stories-shared/tests/fixtures.ts';\n\ntest.describe('Sortable grid', () => {\n  test.beforeEach(async ({dnd}) => {\n    await dnd.goto('react-sortable-grid--grid');\n    await expect(dnd.items.first()).toBeVisible();\n  });\n\n  test('drag initiates and completes in grid', async ({dnd}) => {\n    const first = dnd.items.nth(0);\n    const second = dnd.items.nth(1);\n\n    const firstText = await first.textContent();\n    const box = await first.boundingBox();\n    const targetBox = await second.boundingBox();\n\n    await dnd.page.mouse.move(box!.x + box!.width / 2, box!.y + box!.height / 2);\n    await dnd.page.mouse.down();\n    await dnd.page.mouse.move(\n      targetBox!.x + targetBox!.width / 2,\n      targetBox!.y + targetBox!.height / 2,\n      {steps: 20}\n    );\n\n    await expect(dnd.dragging).toHaveCount(1);\n\n    await dnd.page.mouse.up();\n    await dnd.waitForDrop();\n  });\n});\n"
  },
  {
    "path": "apps/stories/tests/sortable-horizontal.spec.ts",
    "content": "import {test, expect} from '../../stories-shared/tests/fixtures.ts';\n\ntest.describe('Sortable horizontal list', () => {\n  test.beforeEach(async ({dnd}) => {\n    await dnd.goto('react-sortable-horizontal-list--horizontal');\n    await expect(dnd.items.first()).toBeVisible();\n  });\n\n  test('reorder items right with pointer', async ({dnd}) => {\n    const first = dnd.items.nth(0);\n    const third = dnd.items.nth(2);\n\n    await dnd.pointer.drag(first, third);\n    await dnd.waitForDrop();\n\n    await expect(dnd.items.nth(0)).toHaveText('2');\n    await expect(dnd.items.nth(1)).toHaveText('3');\n    await expect(dnd.items.nth(2)).toHaveText('1');\n  });\n\n  test('reorder items with keyboard', async ({dnd}) => {\n    const first = dnd.items.nth(0);\n\n    await dnd.keyboard.pickup(first);\n    await dnd.keyboard.move('right', 2);\n    await dnd.keyboard.drop();\n    await dnd.waitForDrop();\n\n    await expect(dnd.items.nth(0)).toHaveText('2');\n    await expect(dnd.items.nth(1)).toHaveText('3');\n    await expect(dnd.items.nth(2)).toHaveText('1');\n  });\n});\n"
  },
  {
    "path": "apps/stories/tests/sortable-iframe.spec.ts",
    "content": "import {test, expect} from '../../stories-shared/tests/fixtures.ts';\n\ntest.describe('Sortable iframe', () => {\n  test.beforeEach(async ({dnd}) => {\n    await dnd.goto('react-sortable-iframe--iframe');\n    await expect(dnd.items.first()).toBeVisible();\n  });\n\n  test('reorder items within host list with pointer', async ({dnd}) => {\n    const hostItems = dnd.items.filter({hasText: /^Host:/});\n    const first = hostItems.nth(0);\n    const third = hostItems.nth(2);\n\n    const firstText = await first.textContent();\n\n    await dnd.pointer.drag(first, third);\n    await dnd.waitForDrop();\n\n    const newFirst = await hostItems.nth(0).textContent();\n    expect(newFirst).not.toBe(firstText);\n  });\n\n  test('move item from host to iframe list with pointer', async ({dnd}) => {\n    const hostItems = dnd.items.filter({hasText: /^Host:/});\n    const hostCount = await hostItems.count();\n\n    // The iframe column is to the right of the host column\n    const iframe = dnd.page.locator('#storybook-root iframe');\n    const iframeBox = await iframe.boundingBox();\n    const firstHost = hostItems.nth(0);\n    const box = await firstHost.boundingBox();\n\n    await dnd.page.mouse.move(\n      box!.x + box!.width / 2,\n      box!.y + box!.height / 2\n    );\n    await dnd.page.mouse.down();\n\n    // Drag into the iframe area\n    await dnd.page.mouse.move(\n      iframeBox!.x + iframeBox!.width / 2,\n      iframeBox!.y + 100,\n      {steps: 30}\n    );\n    await dnd.page.mouse.up();\n    await dnd.waitForDrop();\n\n    const newHostCount = await hostItems.count();\n    expect(newHostCount).toBe(hostCount - 1);\n  });\n});\n\ntest.describe('Sortable transformed iframe', () => {\n  test.beforeEach(async ({dnd}) => {\n    await dnd.goto('react-sortable-iframe--iframe-transformed');\n    await expect(dnd.items.first()).toBeVisible();\n  });\n\n  test('drag works in host list despite transformed iframe', async ({dnd}) => {\n    const hostItems = dnd.items.filter({hasText: /^Host:/});\n    const first = hostItems.nth(0);\n    const third = hostItems.nth(2);\n\n    const firstText = await first.textContent();\n\n    await dnd.pointer.drag(first, third);\n    await dnd.waitForDrop();\n\n    const newFirst = await hostItems.nth(0).textContent();\n    expect(newFirst).not.toBe(firstText);\n  });\n\n  test('move item from host to transformed iframe with pointer', async ({\n    dnd,\n  }) => {\n    const hostItems = dnd.items.filter({hasText: /^Host:/});\n    const hostCount = await hostItems.count();\n\n    const iframe = dnd.page.locator('#storybook-root iframe');\n    const iframeBox = await iframe.boundingBox();\n    const firstHost = hostItems.nth(0);\n    const box = await firstHost.boundingBox();\n\n    await dnd.page.mouse.move(\n      box!.x + box!.width / 2,\n      box!.y + box!.height / 2\n    );\n    await dnd.page.mouse.down();\n\n    await dnd.page.mouse.move(\n      iframeBox!.x + iframeBox!.width / 2,\n      iframeBox!.y + 100,\n      {steps: 30}\n    );\n    await dnd.page.mouse.up();\n    await dnd.waitForDrop();\n\n    const newHostCount = await hostItems.count();\n    expect(newHostCount).toBe(hostCount - 1);\n  });\n});\n"
  },
  {
    "path": "apps/stories/tests/sortable-multiple.spec.ts",
    "content": "import {test, expect} from '../../stories-shared/tests/fixtures.ts';\n\ntest.describe('Sortable multiple lists', () => {\n  const columnItems = (dnd: any, id: string) =>\n    dnd.page.locator(`#storybook-root ul#${id}`).locator('.Item, .item');\n\n  test.beforeEach(async ({dnd}) => {\n    await dnd.goto('react-sortable-multiple-lists--example');\n    await expect(dnd.items.first()).toBeVisible();\n  });\n\n  test('reorder items within a list with pointer', async ({dnd}) => {\n    const columnA = columnItems(dnd, 'A');\n    const first = columnA.nth(0);\n    const third = columnA.nth(2);\n\n    const firstText = await first.textContent();\n\n    await dnd.pointer.drag(first, third);\n    await dnd.waitForDrop();\n\n    const newFirst = await columnA.nth(0).textContent();\n    expect(newFirst).not.toBe(firstText);\n  });\n\n  test('move item from column A to column B with pointer', async ({dnd}) => {\n    const columnA = columnItems(dnd, 'A');\n    const columnB = columnItems(dnd, 'B');\n\n    const countA = await columnA.count();\n    const countB = await columnB.count();\n    const firstA = columnA.nth(0);\n    const firstB = columnB.nth(0);\n\n    await dnd.pointer.drag(firstA, firstB);\n    await dnd.waitForDrop();\n\n    const newCountA = await columnA.count();\n    const newCountB = await columnB.count();\n\n    expect(newCountA).toBe(countA - 1);\n    expect(newCountB).toBe(countB + 1);\n  });\n\n  test('move item from column A to empty column D with pointer', async ({\n    dnd,\n  }) => {\n    const columnA = columnItems(dnd, 'A');\n    const columnD = dnd.page.locator('#storybook-root ul#D');\n\n    const countA = await columnA.count();\n    const firstA = columnA.nth(0);\n    const columnDBox = await columnD.boundingBox();\n\n    // Drag into the empty column D area\n    const box = await firstA.boundingBox();\n    await dnd.page.mouse.move(\n      box!.x + box!.width / 2,\n      box!.y + box!.height / 2\n    );\n    await dnd.page.mouse.down();\n    await dnd.page.mouse.move(\n      columnDBox!.x + columnDBox!.width / 2,\n      columnDBox!.y + columnDBox!.height / 2,\n      {steps: 30}\n    );\n    await dnd.page.mouse.up();\n    await dnd.waitForDrop();\n\n    const newCountA = await columnA.count();\n    const countD = await columnItems(dnd, 'D').count();\n\n    expect(newCountA).toBe(countA - 1);\n    expect(countD).toBe(1);\n  });\n\n  test('cancel drag restores original order', async ({dnd}) => {\n    const columnA = columnItems(dnd, 'A');\n    const originalTexts = await columnA.allTextContents();\n\n    const firstHandle = dnd.handles.nth(0);\n\n    await dnd.keyboard.pickup(firstHandle);\n    await dnd.keyboard.move('down', 2);\n    await dnd.keyboard.cancel();\n    await dnd.waitForDrop();\n\n    const textsAfter = await columnA.allTextContents();\n    expect(textsAfter).toEqual(originalTexts);\n  });\n});\n"
  },
  {
    "path": "apps/stories/tests/sortable-scroll.spec.ts",
    "content": "import {test, expect} from '../../stories-shared/tests/fixtures.ts';\n\ntest.describe('Auto-scrolling', () => {\n  test.describe('Vertical list (100 items)', () => {\n    test.beforeEach(async ({dnd}) => {\n      await dnd.goto('react-sortable-vertical-list--basic-setup');\n      await expect(dnd.items.first()).toBeVisible();\n    });\n\n    test('auto-scrolls down when dragging near bottom edge with pointer', async ({\n      dnd,\n    }) => {\n      const first = dnd.items.nth(0);\n      const box = await first.boundingBox();\n      const viewport = dnd.page.viewportSize()!;\n\n      const scrollBefore = await dnd.page.evaluate(\n        () => document.scrollingElement?.scrollTop ?? 0\n      );\n\n      await dnd.page.mouse.move(\n        box!.x + box!.width / 2,\n        box!.y + box!.height / 2\n      );\n      await dnd.page.mouse.down();\n\n      // Drag toward the bottom edge of the viewport\n      await dnd.page.mouse.move(\n        box!.x + box!.width / 2,\n        viewport.height - 10,\n        {steps: 20}\n      );\n\n      // Wait for auto-scroll to kick in\n      await expect\n        .poll(\n          () =>\n            dnd.page.evaluate(\n              () => document.scrollingElement?.scrollTop ?? 0\n            ),\n          {timeout: 3_000}\n        )\n        .toBeGreaterThan(scrollBefore);\n\n      await dnd.page.mouse.up();\n      await dnd.waitForDrop();\n    });\n\n    test('scrolls when moving with keyboard arrow keys', async ({dnd}) => {\n      await dnd.page.emulateMedia({reducedMotion: 'reduce'});\n\n      // Find the last visible item (closest to bottom of viewport)\n      const viewport = dnd.page.viewportSize()!;\n      const count = await dnd.items.count();\n      let lastVisibleIndex = 0;\n\n      for (let i = 0; i < count; i++) {\n        const box = await dnd.items.nth(i).boundingBox();\n        if (!box || box.y + box.height > viewport.height) break;\n        lastVisibleIndex = i;\n      }\n\n      const item = dnd.items.nth(lastVisibleIndex);\n\n      await dnd.keyboard.pickup(item);\n      await dnd.keyboard.move('down');\n\n      await expect\n        .poll(\n          () =>\n            dnd.page.evaluate(\n              () => document.scrollingElement?.scrollTop ?? 0\n            ),\n          {timeout: 5_000}\n        )\n        .toBeGreaterThan(0);\n\n      await dnd.keyboard.drop();\n      await dnd.waitForDrop();\n    });\n  });\n\n  test.describe('Scrollable containers', () => {\n    test.beforeEach(async ({dnd}) => {\n      await dnd.goto('react-sortable-multiple-lists--scrollable');\n      await expect(dnd.items.first()).toBeVisible();\n    });\n\n    test('auto-scrolls within a scrollable container with pointer', async ({\n      dnd,\n    }) => {\n      const container = dnd.page.locator('#storybook-root ul').first();\n      const firstItem = container.locator('.Item').first();\n      const containerBox = await container.boundingBox();\n      const itemBox = await firstItem.boundingBox();\n\n      const scrollBefore = await container.evaluate((el) => el.scrollTop);\n\n      await dnd.page.mouse.move(\n        itemBox!.x + itemBox!.width / 2,\n        itemBox!.y + itemBox!.height / 2\n      );\n      await dnd.page.mouse.down();\n\n      await dnd.page.mouse.move(\n        containerBox!.x + containerBox!.width / 2,\n        containerBox!.y + containerBox!.height - 10,\n        {steps: 20}\n      );\n\n      // Wait for auto-scroll to kick in\n      await expect\n        .poll(() => container.evaluate((el) => el.scrollTop), {\n          timeout: 3_000,\n        })\n        .toBeGreaterThan(scrollBefore);\n\n      await dnd.page.mouse.up();\n      await dnd.waitForDrop();\n    });\n  });\n});\n"
  },
  {
    "path": "apps/stories/tests/sortable-table.spec.ts",
    "content": "import {test, expect} from '../../stories-shared/tests/fixtures.ts';\n\ntest.describe('Sortable table', () => {\n  test.beforeEach(async ({dnd}) => {\n    await dnd.goto('react-sortable-table--example');\n    // Wait for actual table data to render (not Storybook docs content)\n    await expect(dnd.page.locator('#storybook-root td', {hasText: 'Alice Johnson'})).toBeVisible();\n  });\n\n  test('reorder rows with pointer via drag handle', async ({dnd}) => {\n    const firstHandle = dnd.handles.nth(0);\n    const thirdHandle = dnd.handles.nth(2);\n\n    const getRowName = (index: number) =>\n      dnd.rows.nth(index).locator('td').nth(1);\n\n    const firstName = await getRowName(0).textContent();\n\n    await dnd.pointer.drag(firstHandle, thirdHandle);\n    await dnd.waitForDrop();\n\n    const newFirstName = await getRowName(0).textContent();\n    expect(newFirstName).not.toBe(firstName);\n  });\n\n  test('reorder columns with pointer', async ({dnd}) => {\n    const headerCells = dnd.page.locator('#storybook-root thead th');\n    const secondCol = headerCells.nth(1);\n    const fourthCol = headerCells.nth(3);\n\n    const originalHeader = await secondCol.textContent();\n\n    await dnd.pointer.drag(secondCol, fourthCol);\n    await dnd.waitForDrop();\n\n    const newHeader = await headerCells.nth(1).textContent();\n    expect(newHeader).not.toBe(originalHeader);\n  });\n\n  test('cell widths are preserved after row drag', async ({dnd}) => {\n    const firstHandle = dnd.handles.nth(0);\n    const secondHandle = dnd.handles.nth(1);\n\n    const getCellWidths = async () => {\n      const cells = dnd.rows.nth(0).locator('td');\n      const count = await cells.count();\n      const widths: number[] = [];\n      for (let i = 0; i < count; i++) {\n        const box = await cells.nth(i).boundingBox();\n        widths.push(Math.round(box!.width));\n      }\n      return widths;\n    };\n\n    const widthsBefore = await getCellWidths();\n\n    await dnd.pointer.drag(firstHandle, secondHandle);\n    await dnd.waitForDrop();\n\n    const widthsAfter = await getCellWidths();\n\n    for (let i = 0; i < widthsBefore.length; i++) {\n      expect(widthsAfter[i]).toBeCloseTo(widthsBefore[i], -1);\n    }\n  });\n});\n"
  },
  {
    "path": "apps/stories/tests/sortable-transformed.spec.ts",
    "content": "import {sortableTransformedTests} from '../../stories-shared/tests/sortable-transformed.tests.ts';\n\nsortableTransformedTests({\n  withOverlay: 'react-sortable-transformed--with-overlay',\n  withoutOverlay: 'react-sortable-transformed--without-overlay',\n});\n"
  },
  {
    "path": "apps/stories/tests/sortable-vertical.spec.ts",
    "content": "import {sortableVerticalTests} from '../../stories-shared/tests/sortable-vertical.tests.ts';\n\nsortableVerticalTests({\n  basicSetup: 'react-sortable-vertical-list--basic-setup',\n  withDragHandle: 'react-sortable-vertical-list--with-drag-handle',\n});\n"
  },
  {
    "path": "apps/stories/tsconfig.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/tsconfig\",\n  \"extends\": \"../../config/typescript/react.json\",\n  \"include\": [\".\"],\n  \"exclude\": [\"dist\", \"build\", \"node_modules\"]\n}\n"
  },
  {
    "path": "apps/stories-shared/components/Container/Container.css",
    "content": "container-component {\n  display: flex;\n  flex-direction: column;\n  grid-auto-rows: max-content;\n  overflow: hidden;\n  box-sizing: border-box;\n  appearance: none;\n  outline: none;\n  min-width: var(--min-width, 300px);\n  border-radius: 5px;\n  min-height: 200px;\n  transition-property: transform, background, box-shadow;\n  transition-duration: 250ms;\n  transition-timing-function: ease;\n  background-color: rgba(246, 246, 246, 1);\n  border: 1px solid rgba(0, 0, 0, 0.05);\n  font-size: 1em;\n}\n\ncontainer-component[data-shadow=\"true\"] {\n  transform: scale(1.01);\n  box-shadow: -1px 0 15px 0 rgba(34, 33, 81, 0.01), 0px 15px 15px 0 rgba(34, 33, 81, 0.25);\n}\n\ncontainer-component:hover, container-component[data-shadow=\"true\"] {\n  background-color: rgb(240, 240, 240);\n}\n\ncontainer-component[aria-hidden=\"true\"] {\n  opacity: 0.5;\n}\n\ncontainer-component > ul {\n  display: grid;\n  gap: 16px;\n  grid-template-columns: repeat(var(--columns, 1), 1fr);\n  list-style: none;\n  padding: 15px;\n  margin: 0;\n}\n\ncontainer-component[data-scrollable=\"true\"] > ul {\n  max-height: calc(80vh - 100px);\n  overflow-y: auto;\n}\n\ncontainer-component > .Header {\n  display: flex;\n  min-height: 59px;\n  padding: 8px 20px;\n  padding-inline-end: 8px;\n  align-items: center;\n  justify-content: space-between;\n  background-color: #fff;\n  border-top-left-radius: 5px;\n  border-top-right-radius: 5px;\n  border-bottom: 1px solid rgba(0, 0, 0, 0.08);\n  font-family: var(--font-family);\n}\n\n.dark container-component {\n  border: none;\n  background-color: rgb(76, 79, 80);\n\n  &:hover, &[data-shadow=\"true\"] {\n    background-color: rgb(67 69 70);\n  }\n}\n"
  },
  {
    "path": "apps/stories-shared/components/Container/Container.ts",
    "content": "import './Container.css';\n\nexport class Container extends HTMLElement {}\n"
  },
  {
    "path": "apps/stories-shared/components/Container/index.ts",
    "content": "export {Container} from './Container.ts';\n"
  },
  {
    "path": "apps/stories-shared/components/Item/Item.css",
    "content": ".Item {\n  --box-shadow: inset 0px 0px 1px rgba(0,0,0,0.4), 0 0 0 calc(1px / var(--scale-x, 1)) rgba(63, 63, 68, 0.05), 0 1px calc(3px / var(--scale-x, 1)) 0 rgba(34, 33, 81, 0.15);\n\n  display: flex;\n  align-items: center;\n  justify-content: space-between;\n  box-sizing: border-box;\n  padding: 10px 20px;\n  border: none;\n  gap: 10px;\n  background-color: rgb(255,255,255);\n  border-radius: 6px;\n  font-size: 14px !important;\n  color: #555;\n  outline: none;\n  min-height: 62px;\n  box-shadow: var(--box-shadow);\n  font-family: var(--font-family);\n  width: 100%;\n  max-width: 300px;\n  white-space: nowrap;\n  transition: transform 0.3s ease, box-shadow 0.3s ease;\n}\n\n.Item:focus-visible {\n  box-shadow: inset 0 0 0 2px #4c9ffe, var(--box-shadow);\n}\n\n.Item[aria-hidden=\"true\"] {\n  opacity: 0.5;\n}\n\n.Item[aria-disabled=\"true\"] {\n  opacity: 0.8;\n  background-color: #EEE;\n}\n\n.Item[data-shadow=\"true\"]:not([aria-hidden=\"true\"]) {\n  transform: scale(1.03);\n  backdrop-filter: blur(5px);\n  -webkit-backdrop-filter: blur(10px);\n  background-color: rgba(255,255,255,0.9);\n  --box-shadow: inset 0px 0px 1px rgba(0,0,0,0.5), -1px 0 15px 0 rgba(34, 33, 81, 0.01), 0px 15px 15px 0 rgba(34, 33, 81, 0.25);\n}\n\n:global(.dark) .shadow:not([aria-hidden=\"true\"]) {\n  background-color: rgba(255,255,255,0.98);\n}\n\n.Item:has(button) {\n  padding-inline-end: 10px;\n}\n\n.Item:not(.Item:has(button)) {\n  cursor: grab;\n}\n\n.Item[data-accent-color] {\n  border-left: 3px solid;\n  border-color: var(--accent-color);\n}\n"
  },
  {
    "path": "apps/stories-shared/components/Item/Item.ts",
    "content": "import './Item.css';\n\nexport class Item extends HTMLElement {\n  connectedCallback() {\n    this.classList.add('Item');\n  }\n}\n"
  },
  {
    "path": "apps/stories-shared/components/Item/index.ts",
    "content": "export {Item} from './Item.ts';\n"
  },
  {
    "path": "apps/stories-shared/components/index.ts",
    "content": "export {Container} from './Container/index.ts';\nexport {Item} from './Item/index.ts';\n"
  },
  {
    "path": "apps/stories-shared/package.json",
    "content": "{\n  \"name\": \"@dnd-kit/stories-shared\",\n  \"version\": \"0.0.0\",\n  \"private\": true,\n  \"type\": \"module\",\n  \"exports\": {\n    \"./components\": \"./components/index.ts\",\n    \"./components/*\": \"./components/*/index.ts\",\n    \"./utilities\": \"./utilities/index.ts\",\n    \"./assets/*\": \"./assets/*\",\n    \"./styles/sandbox\": \"./styles/sandbox.ts\",\n    \"./register\": \"./register.ts\",\n    \"./preview-head.html\": \"./preview-head.html\"\n  }\n}\n"
  },
  {
    "path": "apps/stories-shared/preview-head.html",
    "content": "<link rel=\"preconnect\" href=\"https://fonts.googleapis.com\">\n<link rel=\"preconnect\" href=\"https://fonts.gstatic.com\" crossorigin>\n<link href=\"https://fonts.googleapis.com/css2?family=Poppins:wght@300;600&Inter:wght@300;400&family=Roboto+Mono:wght@500&display=swap\" rel=\"stylesheet\">\n\n<style>\n  :root {\n    --font-family: \"Poppins\",-apple-system,\".SFNSText-Regular\",\"San Francisco\",BlinkMacSystemFont,\"Segoe UI\",\"Helvetica Neue\",Helvetica,Arial,sans-serif;\n\n    font-family: var(--font-family);\n  }\n\n  body {\n    background-color: #FCFCFC;\n  }\n\n  body.dark {\n    background-color: #2a2c2e;\n  }\n\n  body.hero {\n    --gradient: linear-gradient(65deg, #56fff420, #001AFF20, #5F6AF220, #F25FD020, #56FFF520, #F25FD020, #001AFF20, #56fff420);\n    min-height: 100vh;\n    background-image: var(--gradient);\n    animation: gradient 16s linear infinite;\n    animation-direction: alternate;\n    background-size: 600% 100%;\n    background-repeat: no-repeat;\n  }\n\n  body.dark.hero {\n    --gradient: linear-gradient(65deg, #ff56d580, #001AFF80, #5F6AF280, #F25FD080, #56FFF580, #F25FD080, #001AFF80, #56fff480);\n\n    animation: background 16s linear infinite, gradient 60s linear infinite;\n  }\n\n  @keyframes background {\n    0% {\n      background-color: #ff0000;\n    }\n    25% {\n      background-color: #7f00ff;\n    }\n    50% {\n      background-color: #00affa;\n    }\n    75% {\n      background-color: #00f594;\n    }\n    100% {\n      background-color: #ff0000\n    }\n  }\n\n  @keyframes gradient {\n    0% {background-position: 0%}\n    100% {background-position: 100%}\n  }\n\n  * {\n    box-sizing: border-box;\n  }\n\n  .sb-main-padded {\n    padding-top: 2rem !important;\n\n    @media (min-width: 750px) {\n      padding-top: 3rem !important;\n    }\n  }\n\n  section {\n    display: flex;\n    flex-wrap: wrap;\n    flex-direction: row;\n    align-items: center;\n    justify-content: space-between;\n    max-width: 700px;\n    margin: 0 auto;\n    gap: 20px;\n  }\n\n  section > * {\n    width: calc(50% - 10px);\n  }\n</style>\n"
  },
  {
    "path": "apps/stories-shared/register.ts",
    "content": "import {Container, Item} from './components/index.ts';\nimport {baseStyles, draggableStyles, droppableStyles, handleStyles, sortableStyles, multipleListsStyles} from './styles/sandbox.ts';\n\n// Inject shared styles globally for Storybook display\nif (typeof document !== 'undefined') {\n  const style = document.createElement('style');\n  style.textContent = [baseStyles, draggableStyles, droppableStyles, handleStyles, sortableStyles, multipleListsStyles].join('\\n');\n  document.head.appendChild(style);\n}\n\nif (!customElements.get('container-component')) {\n  customElements.define('container-component', Container);\n}\n\nif (!customElements.get('item-component')) {\n  customElements.define('item-component', Item);\n}\n\n// Apply dark mode and hero classes from URL query parameters.\n// This is used when stories are embedded as iframes in the docs site.\nif (typeof window !== 'undefined' && typeof document !== 'undefined') {\n  const params = new URLSearchParams(window.location.search);\n  const dark = params.get('dark');\n  const hero = params.get('hero');\n\n  if (dark === 'false') {\n    document.body.classList.remove('dark');\n  } else if (dark === 'true') {\n    document.body.classList.add('dark');\n  }\n\n  if (hero === 'true') {\n    document.body.classList.add('hero');\n  }\n}\n"
  },
  {
    "path": "apps/stories-shared/styles/index.ts",
    "content": "export * from './sandbox';\n"
  },
  {
    "path": "apps/stories-shared/styles/sandbox.ts",
    "content": "/**\n * Shared CSS styles for CodeSandbox examples.\n *\n * These use plain CSS classes on standard HTML elements, matching the\n * pattern used in the documentation examples. No web components or\n * wrapper components needed.\n */\n\nexport const draggableStyles = `\n.btn {\n  display: flex;\n  width: min-content;\n  height: min-content;\n  align-items: center;\n  gap: 6px;\n  font-family: inherit;\n  font-size: 20px;\n  font-weight: 800;\n  cursor: grab;\n  padding: 14px 18px;\n  background: #000;\n  color: #FFF;\n  border-radius: 10px;\n  border: none;\n  transition: transform 0.25s ease, box-shadow 0.2s ease, opacity 0.2s ease;\n}\n\n.btn::before {\n  content: '';\n  display: inline-block;\n  width: 34px;\n  height: 34px;\n  background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='43' height='43' viewBox='0 0 43 43' fill='none'%3E%3Cpath d='M4.55229 25.6017L20.5499 20.8985C21.4951 20.6173 22.3778 21.5001 22.1044 22.4532L17.402 38.4532C17.0817 39.5392 15.5897 39.672 15.082 38.6563L12.8401 34.1798C12.7855 34.0782 12.723 33.9767 12.6449 33.8907L5.77086 40.7657C4.79444 41.7423 3.20873 41.7423 2.23231 40.7657C1.2559 39.7892 1.2559 38.2032 2.23231 37.2267L9.10631 30.3517C9.02038 30.2735 8.92665 30.2032 8.81729 30.1563L4.34919 27.922C3.33372 27.4142 3.46651 25.922 4.55229 25.6017Z' fill='white'/%3E%3Cpath transform-origin='25 50%25' d='M22.4324 30.2031L21.3153 34H21.5028C28.408 34 34.001 28.4062 34.001 21.5C34.001 14.5938 28.408 9 21.5028 9C14.5976 9 9.00464 14.5938 9.00464 21.5V21.6875L12.801 20.5703C13.2696 16.1719 16.9878 12.75 21.5028 12.75C26.338 12.75 30.2515 16.6641 30.2515 21.5C30.2515 26.0156 26.8302 29.7344 22.4324 30.2031Z' fill='white' fill-opacity='0.7'%3E%3Canimate attributeName='fill-opacity' begin='0' values='0;0.7;0.7;0' keyTimes='0; 0.2; 0.85; 1' dur='4s' repeatCount='indefinite'/%3E%3CanimateTransform attributeName='transform' type='scale' values='0 0; 1 1; 1 1; 0 0' keyTimes='0; 0.1; 0.9; 1' begin='0s' dur='4s' repeatCount='indefinite'/%3E%3C/path%3E%3Cpath transform-origin='25 50%25' d='M37.7505 21.5C37.7505 30.4766 30.4782 37.75 21.5029 37.75V37.7422C21.0733 37.7422 20.6515 37.7266 20.2297 37.6953L19.1517 41.3594C19.925 41.4531 20.7062 41.5 21.5029 41.5C32.5482 41.5 41.5 32.5469 41.5 21.5C41.5 10.4531 32.5482 1.5 21.5029 1.5C10.4577 1.5 1.50586 10.4531 1.50586 21.5C1.50586 22.2969 1.55273 23.0781 1.64646 23.8516L5.30218 22.7734C5.27093 22.3516 5.25531 21.9297 5.25531 21.5C5.25531 12.5234 12.5277 5.25 21.5029 5.25C30.4782 5.25 37.7505 12.5234 37.7505 21.5Z' fill='white' fill-opacity='0.4'%3E%3Canimate attributeName='fill-opacity' begin='0.1s' values='0;0.4;0.4;0' keyTimes='0; 0.2; 0.85; 1' dur='4s' repeatCount='indefinite'/%3E%3CanimateTransform attributeName='transform' type='scale' values='0 0; 1 1; 1 1; 0 0' keyTimes='0; 0.1; 0.9; 1' begin='0.1s' dur='4s' repeatCount='indefinite'/%3E%3C/path%3E%3Cdiv xmlns='' style='all: initial !important;'/%3E%3C/svg%3E\");\n  background-size: contain;\n  background-repeat: no-repeat;\n}\n\n.btn:has(.handle) {\n  padding-inline-end: 10px;\n}\n\n.btn[aria-grabbed=\"true\"]:not([disabled]),\n.btn[data-shadow=\"true\"]:not([disabled]) {\n  transform: scale(1.025);\n  box-shadow: inset 0px 0px 1px rgba(0,0,0,0.5), -1px 0 15px 0 rgba(34, 33, 81, 0.01), 0px 15px 15px 0 rgba(34, 33, 81, 0.25)\n}\n\n.btn[disabled] {\n  opacity: 0.3;\n}\n`.trim();\n\nexport const droppableStyles = `\n.droppable {\n  display: flex;\n  flex-direction: column;\n  gap: 20px;\n  align-items: center;\n  justify-content: flex-start;\n  position: relative;\n  padding-top: 80px;\n  text-align: center;\n  border-radius: 10px;\n  max-width: 340px;\n  max-height: 340px;\n  flex-grow: 1;\n  min-width: 300px;\n  aspect-ratio: 1 / 1;\n  box-sizing: border-box;\n  background-color: #fff;\n  box-shadow: inset rgba(0, 0, 0, 0.1) 0 0 0 2px,\n    rgba(0, 0, 0, 0.06) 20px 14px 24px;\n  transition: box-shadow 250ms ease;\n}\n\n.droppable::after {\n  content: url(\"data:image/svg+xml,%3Csvg width='200' viewBox='0 0 279 67' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M12 0H55C61.6274 0 67 5.37258 67 12V55C67 61.6274 61.6274 67 55 67H12C5.37258 67 0 61.6274 0 55V12C0 5.37258 5.37258 0 12 0Z' fill='%237F8C96'/%3E%3Cpath transform-origin='35 35' d='M19.8652 44.5547L12.494 52.1379V44.6787H8.33374V59.2396H22.8946V55.0794H15.4354L22.9863 47.5285L19.8652 44.5547Z' fill='white'%3E%3Canimate attributeName='fill-opacity' begin='0' values='0;1;1;0' keyTimes='0; 0.2; 0.85; 1' dur='3s' repeatCount='indefinite'/%3E%3CanimateTransform attributeName='transform' type='scale' values='0 0; 1 1; 1 1; 1 1' keyTimes='0; 0.15; 0.9; 1' begin='0s' dur='3s' repeatCount='indefinite' /%3E%3C/path%3E%3Cpath transform-origin='35 35' d='M47.7082 44.5547L44.5872 47.5285L52.1381 55.0794H44.6789V59.2396H59.2397V44.6787H55.0795V52.1379L47.7082 44.5547Z' fill='white'%3E%3Canimate attributeName='fill-opacity' begin='0' values='0;1;1;0' keyTimes='0; 0.2; 0.85; 1' dur='3s' repeatCount='indefinite'/%3E%3CanimateTransform attributeName='transform' type='scale' values='0 0; 1 1; 1 1; 1 1' keyTimes='0; 0.15; 0.9; 1' begin='0s' dur='3s' repeatCount='indefinite' /%3E%3C/path%3E%3Cpath transform-origin='35 35' d='M19.8652 22.9862L22.9863 20.0124L15.4354 12.4615H22.8946V8.30127H8.33374V22.8621H12.494V15.403L19.8652 22.9862Z' fill='white'%3E%3Canimate attributeName='fill-opacity' begin='0' values='0;1;1;0' keyTimes='0; 0.2; 0.85; 1' dur='3s' repeatCount='indefinite'/%3E%3CanimateTransform attributeName='transform' type='scale' values='0 0; 1 1; 1 1; 1 1' keyTimes='0; 0.15; 0.9; 1' begin='0s' dur='3s' repeatCount='indefinite' /%3E%3C/path%3E%3Cpath transform-origin='35 35' d='M47.7082 22.9862L55.0795 15.403V22.8621H59.2397V8.30127H44.6789V12.4615H52.1381L44.5872 20.0124L47.7082 22.9862Z' fill='white'%3E%3Canimate attributeName='fill-opacity' begin='0' values='0;1;1;0' keyTimes='0; 0.2; 0.85; 1' dur='3s' repeatCount='indefinite'/%3E%3CanimateTransform attributeName='transform' type='scale' values='0 0; 1 1; 1 1; 1 1' keyTimes='0; 0.15; 0.9; 1' begin='0s' dur='3s' repeatCount='indefinite' /%3E%3C/path%3E%3Cpath d='M277.629 33.6321C277.629 34.2081 277.593 34.8081 277.521 35.4321H263.589C263.685 36.6801 264.081 37.6401 264.777 38.3121C265.497 38.9601 266.373 39.2841 267.405 39.2841C268.941 39.2841 270.009 38.6361 270.609 37.3401H277.161C276.825 38.6601 276.213 39.8481 275.325 40.9041C274.461 41.9601 273.369 42.7881 272.049 43.3881C270.729 43.9881 269.253 44.2881 267.621 44.2881C265.653 44.2881 263.901 43.8681 262.365 43.0281C260.829 42.1881 259.629 40.9881 258.765 39.4281C257.901 37.8681 257.469 36.0441 257.469 33.9561C257.469 31.8681 257.889 30.0441 258.729 28.4841C259.593 26.9241 260.793 25.7241 262.329 24.8841C263.865 24.0441 265.629 23.6241 267.621 23.6241C269.565 23.6241 271.293 24.0321 272.805 24.8481C274.317 25.6641 275.493 26.8281 276.333 28.3401C277.197 29.8521 277.629 31.6161 277.629 33.6321ZM271.329 32.0121C271.329 30.9561 270.969 30.1161 270.249 29.4921C269.529 28.8681 268.629 28.5561 267.549 28.5561C266.517 28.5561 265.641 28.8561 264.921 29.4561C264.225 30.0561 263.793 30.9081 263.625 32.0121H271.329Z' fill='%237F8C96'/%3E%3Cpath d='M254.232 16.3601V44.0001H248.076V16.3601H254.232Z' fill='%237F8C96'/%3E%3Cpath d='M229.798 26.7561C230.374 25.8201 231.202 25.0641 232.282 24.4881C233.362 23.9121 234.598 23.6241 235.99 23.6241C237.646 23.6241 239.146 24.0441 240.49 24.8841C241.834 25.7241 242.89 26.9241 243.658 28.4841C244.45 30.0441 244.846 31.8561 244.846 33.9201C244.846 35.9841 244.45 37.8081 243.658 39.3921C242.89 40.9521 241.834 42.1641 240.49 43.0281C239.146 43.8681 237.646 44.2881 235.99 44.2881C234.574 44.2881 233.338 44.0121 232.282 43.4601C231.226 42.8841 230.398 42.1281 229.798 41.1921V44.0001H223.642V16.3601H229.798V26.7561ZM238.582 33.9201C238.582 32.3841 238.15 31.1841 237.286 30.3201C236.446 29.4321 235.402 28.9881 234.154 28.9881C232.93 28.9881 231.886 29.4321 231.022 30.3201C230.182 31.2081 229.762 32.4201 229.762 33.9561C229.762 35.4921 230.182 36.7041 231.022 37.5921C231.886 38.4801 232.93 38.9241 234.154 38.9241C235.378 38.9241 236.422 38.4801 237.286 37.5921C238.15 36.6801 238.582 35.4561 238.582 33.9201Z' fill='%237F8C96'/%3E%3Cpath d='M197.985 33.9201C197.985 31.8561 198.369 30.0441 199.137 28.4841C199.929 26.9241 200.997 25.7241 202.341 24.8841C203.685 24.0441 205.185 23.6241 206.841 23.6241C208.257 23.6241 209.493 23.9121 210.549 24.4881C211.629 25.0641 212.457 25.8201 213.033 26.7561V23.9121H219.189V44.0001H213.033V41.1561C212.433 42.0921 211.593 42.8481 210.513 43.4241C209.457 44.0001 208.221 44.2881 206.805 44.2881C205.173 44.2881 203.685 43.8681 202.341 43.0281C200.997 42.1641 199.929 40.9521 199.137 39.3921C198.369 37.8081 197.985 35.9841 197.985 33.9201ZM213.033 33.9561C213.033 32.4201 212.601 31.2081 211.737 30.3201C210.897 29.4321 209.865 28.9881 208.641 28.9881C207.417 28.9881 206.373 29.4321 205.509 30.3201C204.669 31.1841 204.249 32.3841 204.249 33.9201C204.249 35.4561 204.669 36.6801 205.509 37.5921C206.373 38.4801 207.417 38.9241 208.641 38.9241C209.865 38.9241 210.897 38.4801 211.737 37.5921C212.601 36.7041 213.033 35.4921 213.033 33.9561Z' fill='%237F8C96'/%3E%3Cpath d='M180.931 26.7561C181.531 25.8201 182.359 25.0641 183.415 24.4881C184.471 23.9121 185.707 23.6241 187.123 23.6241C188.779 23.6241 190.279 24.0441 191.623 24.8841C192.967 25.7241 194.023 26.9241 194.791 28.4841C195.583 30.0441 195.979 31.8561 195.979 33.9201C195.979 35.9841 195.583 37.8081 194.791 39.3921C194.023 40.9521 192.967 42.1641 191.623 43.0281C190.279 43.8681 188.779 44.2881 187.123 44.2881C185.731 44.2881 184.495 44.0001 183.415 43.4241C182.359 42.8481 181.531 42.1041 180.931 41.1921V53.5761H174.775V23.9121H180.931V26.7561ZM189.715 33.9201C189.715 32.3841 189.283 31.1841 188.419 30.3201C187.579 29.4321 186.535 28.9881 185.287 28.9881C184.063 28.9881 183.019 29.4321 182.155 30.3201C181.315 31.2081 180.895 32.4201 180.895 33.9561C180.895 35.4921 181.315 36.7041 182.155 37.5921C183.019 38.4801 184.063 38.9241 185.287 38.9241C186.511 38.9241 187.555 38.4801 188.419 37.5921C189.283 36.6801 189.715 35.4561 189.715 33.9201Z' fill='%237F8C96'/%3E%3Cpath d='M156.497 26.7561C157.097 25.8201 157.925 25.0641 158.981 24.4881C160.037 23.9121 161.273 23.6241 162.689 23.6241C164.345 23.6241 165.845 24.0441 167.189 24.8841C168.533 25.7241 169.589 26.9241 170.357 28.4841C171.149 30.0441 171.545 31.8561 171.545 33.9201C171.545 35.9841 171.149 37.8081 170.357 39.3921C169.589 40.9521 168.533 42.1641 167.189 43.0281C165.845 43.8681 164.345 44.2881 162.689 44.2881C161.297 44.2881 160.061 44.0001 158.981 43.4241C157.925 42.8481 157.097 42.1041 156.497 41.1921V53.5761H150.341V23.9121H156.497V26.7561ZM165.281 33.9201C165.281 32.3841 164.849 31.1841 163.985 30.3201C163.145 29.4321 162.101 28.9881 160.853 28.9881C159.629 28.9881 158.585 29.4321 157.721 30.3201C156.881 31.2081 156.461 32.4201 156.461 33.9561C156.461 35.4921 156.881 36.7041 157.721 37.5921C158.585 38.4801 159.629 38.9241 160.853 38.9241C162.077 38.9241 163.121 38.4801 163.985 37.5921C164.849 36.6801 165.281 35.4561 165.281 33.9201Z' fill='%237F8C96'/%3E%3Cpath d='M136.564 44.2881C134.596 44.2881 132.82 43.8681 131.236 43.0281C129.676 42.1881 128.44 40.9881 127.528 39.4281C126.64 37.8681 126.196 36.0441 126.196 33.9561C126.196 31.8921 126.652 30.0801 127.564 28.5201C128.476 26.9361 129.724 25.7241 131.308 24.8841C132.892 24.0441 134.668 23.6241 136.636 23.6241C138.604 23.6241 140.38 24.0441 141.964 24.8841C143.548 25.7241 144.796 26.9361 145.708 28.5201C146.62 30.0801 147.076 31.8921 147.076 33.9561C147.076 36.0201 146.608 37.8441 145.672 39.4281C144.76 40.9881 143.5 42.1881 141.892 43.0281C140.308 43.8681 138.532 44.2881 136.564 44.2881ZM136.564 38.9601C137.74 38.9601 138.736 38.5281 139.552 37.6641C140.392 36.8001 140.812 35.5641 140.812 33.9561C140.812 32.3481 140.404 31.1121 139.588 30.2481C138.796 29.3841 137.812 28.9521 136.636 28.9521C135.436 28.9521 134.44 29.3841 133.648 30.2481C132.856 31.0881 132.46 32.3241 132.46 33.9561C132.46 35.5641 132.844 36.8001 133.612 37.6641C134.404 38.5281 135.388 38.9601 136.564 38.9601Z' fill='%237F8C96'/%3E%3Cpath d='M118.177 27.2601C118.897 26.1561 119.797 25.2921 120.877 24.6681C121.957 24.0201 123.157 23.6961 124.477 23.6961V30.2121H122.785C121.249 30.2121 120.097 30.5481 119.329 31.2201C118.561 31.8681 118.177 33.0201 118.177 34.6761V44.0001H112.021V23.9121H118.177V27.2601Z' fill='%237F8C96'/%3E%3Cpath d='M86.3635 33.9201C86.3635 31.8561 86.7475 30.0441 87.5155 28.4841C88.3075 26.9241 89.3755 25.7241 90.7195 24.8841C92.0635 24.0441 93.5635 23.6241 95.2195 23.6241C96.5395 23.6241 97.7395 23.9001 98.8195 24.4521C99.9235 25.0041 100.788 25.7481 101.412 26.6841V16.3601H107.568V44.0001H101.412V41.1201C100.836 42.0801 100.008 42.8481 98.9275 43.4241C97.8715 44.0001 96.6355 44.2881 95.2195 44.2881C93.5635 44.2881 92.0635 43.8681 90.7195 43.0281C89.3755 42.1641 88.3075 40.9521 87.5155 39.3921C86.7475 37.8081 86.3635 35.9841 86.3635 33.9201ZM101.412 33.9561C101.412 32.4201 100.98 31.2081 100.116 30.3201C99.2755 29.4321 98.2435 28.9881 97.0195 28.9881C95.7955 28.9881 94.7515 29.4321 93.8875 30.3201C93.0475 31.1841 92.6275 32.3841 92.6275 33.9201C92.6275 35.4561 93.0475 36.6801 93.8875 37.5921C94.7515 38.4801 95.7955 38.9241 97.0195 38.9241C98.2435 38.9241 99.2755 38.4801 100.116 37.5921C100.98 36.7041 101.412 35.4921 101.412 33.9561Z' fill='%237F8C96'/%3E%3C/svg%3E%0A\");\n  position: absolute;\n  left: 50%;\n  top: 50%;\n  transform: translate3d(-50%, -50%, 0);\n  opacity: 0.3;\n  transition: opacity 300ms ease, transform 200ms ease;\n  user-select: none;\n  pointer-events: none;\n}\n\n.droppable.active {\n  background-color: #f7f9fb;\n  box-shadow: inset #1eb99d 0 0 0 2px, rgba(0, 0, 0, 0.12) 20px 14px 24px;\n}\n\n.droppable.active:not(:empty) {\n  box-shadow: inset #1eb99d 0 0 0 2px, rgba(0, 0, 0, 0.1) 20px 14px 24px;\n}\n\n.droppable.active::after {\n  opacity: 0.5;\n}\n\n.drop-layout {\n  display: grid;\n  grid-template-columns: 2fr 1fr;\n  gap: 20px;\n  align-items: center;\n  justify-items: center;\n  max-width: 700px;\n  margin: 0 auto;\n}\n\n.drop-layout > .droppable {\n  grid-column: 2;\n  justify-self: stretch;\n}\n\n.droppable:not(:empty)::after {\n  opacity: 0.2;\n  transform: translate3d(-50%, 100%, 0) scale(0.8);\n}\n`.trim();\n\nexport const handleStyles = `\n.handle {\n  display: flex;\n  width: 12px;\n  padding: 15px;\n  align-items: center;\n  justify-content: center;\n  flex: 0 0 auto;\n  touch-action: none;\n  cursor: grab;\n  border-radius: 5px;\n  border: none;\n  outline: none;\n  appearance: none;\n  background-color: transparent;\n  -webkit-tap-highlight-color: transparent;\n  user-select: none;\n  -webkit-user-select: none;\n}\n\n.handle:hover, .handle:active {\n  background-color: rgba(0, 0, 0, 0.05);\n}\n\n.handle:focus-visible {\n  outline: none;\n  box-shadow: 0 0 0 2px rgba(255, 255, 255, 0), inset 0 0 0 2.5px #4c9ffe;\n}\n\n.handle::before {\n  content: ' ';\n  display: block;\n  width: 12px;\n  height: 12px;\n  flex-shrink: 0;\n  background-image: url(\"data:image/svg+xml,%3Csvg viewBox='0 0 20 20' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M7 2a2 2 0 1 0 .001 4.001A2 2 0 0 0 7 2zm0 6a2 2 0 1 0 .001 4.001A2 2 0 0 0 7 8zm0 6a2 2 0 1 0 .001 4.001A2 2 0 0 0 7 14zm6-8a2 2 0 1 0-.001-4.001A2 2 0 0 0 13 6zm0 2a2 2 0 1 0 .001 4.001A2 2 0 0 0 13 8zm0 6a2 2 0 1 0 .001 4.001A2 2 0 0 0 13 14z' fill='%23919eab'/%3E%3C/svg%3E\");\n  background-size: contain;\n  background-repeat: no-repeat;\n}\n\n.handle:hover::before, .handle:active::before {\n  background-image: url(\"data:image/svg+xml,%3Csvg viewBox='0 0 20 20' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M7 2a2 2 0 1 0 .001 4.001A2 2 0 0 0 7 2zm0 6a2 2 0 1 0 .001 4.001A2 2 0 0 0 7 8zm0 6a2 2 0 1 0 .001 4.001A2 2 0 0 0 7 14zm6-8a2 2 0 1 0-.001-4.001A2 2 0 0 0 13 6zm0 2a2 2 0 1 0 .001 4.001A2 2 0 0 0 13 8zm0 6a2 2 0 1 0 .001 4.001A2 2 0 0 0 13 14z' fill='%236f7b88'/%3E%3C/svg%3E\");\n}\n\n.btn .handle {\n  margin-block: -4px;\n}\n\n.btn .handle:hover, .btn .handle:active {\n  background-color: rgba(255, 255, 255, 0.1);\n}\n\n.btn .handle::before {\n  filter: brightness(0) invert(1);\n  opacity: 0.5;\n}\n\n.btn .handle:hover::before, .btn .handle:active::before {\n  filter: brightness(0) invert(1);\n  opacity: 0.8;\n}\n`.trim();\n\nexport const sortableStyles = `\n.list {\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  gap: 18px;\n  padding: 0 30px;\n  margin: 0;\n  list-style: none;\n}\n\n.item {\n  display: flex;\n  align-items: center;\n  justify-content: space-between;\n  box-sizing: border-box;\n  padding: 0 20px;\n  border: none;\n  gap: 10px;\n  background-color: rgb(255, 255, 255);\n  border-radius: 6px;\n  font-size: 14px !important;\n  font-weight: 300;\n  line-height: 1.4;\n  color: #555;\n  outline: none;\n  min-height: 60px;\n  box-shadow: inset 0 0 1px rgba(0,0,0,0.4), 0 0 0 1px rgba(63, 63, 68, 0.05), 0 1px 3px 0 rgba(34, 33, 81, 0.15);\n  font-family: system-ui, sans-serif;\n  width: 100%;\n  max-width: 300px;\n  white-space: nowrap;\n  transition: transform 0.3s ease, box-shadow 0.3s ease;\n}\n\n.item:has(.handle) {\n  padding-inline-end: 10px;\n}\n\n.item:not(:has(.handle)) {\n  cursor: grab;\n}\n\n.item[aria-grabbed=\"true\"],\n.item[data-shadow] {\n  transform: scale(1.03);\n  backdrop-filter: blur(5px);\n  -webkit-backdrop-filter: blur(10px);\n  background-color: rgba(255,255,255,0.9);\n  box-shadow: inset 0 0 1px rgba(0,0,0,0.5), -1px 0 15px 0 rgba(34, 33, 81, 0.01), 0px 15px 15px 0 rgba(34, 33, 81, 0.25);\n}\n\n.item[data-dnd-placeholder] {\n  opacity: 0.5;\n  box-shadow: none;\n  transform: none;\n}\n\n${handleStyles}\n`.trim();\n\nexport const multipleListsStyles = `\n.wrapper {\n  display: flex;\n  flex-direction: row;\n  gap: 20px;\n  padding: 20px;\n}\n\n.container {\n  display: flex;\n  flex-direction: column;\n  overflow: hidden;\n  box-sizing: border-box;\n  min-width: 300px;\n  border-radius: 5px;\n  min-height: 200px;\n  transition: transform 250ms ease, background 250ms ease, box-shadow 250ms ease;\n  background-color: rgba(246, 246, 246, 1);\n  border: 1px solid rgba(0, 0, 0, 0.05);\n}\n\n.container[data-shadow=\"true\"] {\n  transform: scale(1.01);\n  box-shadow: -1px 0 15px 0 rgba(34, 33, 81, 0.01), 0px 15px 15px 0 rgba(34, 33, 81, 0.25);\n  background-color: rgb(240, 240, 240);\n}\n\n.container > ul {\n  display: grid;\n  gap: 16px;\n  grid-template-columns: repeat(var(--columns, 1), 1fr);\n  list-style: none;\n  padding: 15px;\n  margin: 0;\n}\n\n.container > h2 {\n  display: flex;\n  min-height: 59px;\n  padding: 0px 20px;\n  margin: 0;\n  padding-inline-end: 8px;\n  align-items: center;\n  justify-content: space-between;\n  background-color: #fff;\n  border-top-left-radius: 5px;\n  border-top-right-radius: 5px;\n  border-bottom: 1px solid rgba(0, 0, 0, 0.08);\n  font-weight: 300;\n  font-size: 16px;\n  font-family: system-ui, sans-serif;\n}\n\n/* Reuses .item and .handle from sortableStyles, just adds accent color border */\n.item[data-accent-color] {\n  border-left: 3px solid;\n  border-color: var(--accent-color);\n}\n`.trim();\n\nexport const baseStyles = `\nbody {\n  padding: 1em;\n  font-family: system-ui, sans-serif;\n  -webkit-font-smoothing: antialiased;\n}\n`.trim();\n"
  },
  {
    "path": "apps/stories-shared/tests/drag-offset.tests.ts",
    "content": "import {test, expect} from './fixtures.ts';\n\ninterface DragOffsetStories {\n  draggable: string;\n  sortableVertical: string;\n}\n\nexport function dragOffsetTests(stories: DragOffsetStories) {\n  test.describe('Drag offset', () => {\n    test('dragged element follows pointer with no unexpected offset (draggable)', async ({\n      dnd,\n    }) => {\n      await dnd.goto(stories.draggable);\n      const button = dnd.buttons.first();\n      await expect(button).toBeVisible();\n\n      const box = await button.boundingBox();\n      if (!box) throw new Error('Could not get bounding box');\n\n      // Click at a known offset within the element (1/4 from top-left)\n      const clickX = box.x + box.width * 0.25;\n      const clickY = box.y + box.height * 0.25;\n\n      await dnd.page.mouse.move(clickX, clickY);\n      await dnd.page.mouse.down();\n\n      // Move enough to trigger drag activation\n      const dragTargetX = clickX + 0;\n      const dragTargetY = clickY + 80;\n\n      await dnd.page.mouse.move(dragTargetX, dragTargetY, {steps: 15});\n      await expect(dnd.dragging).toHaveCount(1, {timeout: 3_000});\n\n      // Read the dragging element's bounding box\n      const draggingBox = await dnd.dragging.boundingBox();\n      if (!draggingBox) throw new Error('Could not get dragging bounding box');\n\n      // The cursor should be at approximately the same relative position\n      // within the dragged element as where we originally clicked.\n      // Original click was at 25% from the left and 25% from the top.\n      const cursorRelativeX = dragTargetX - draggingBox.x;\n      const cursorRelativeY = dragTargetY - draggingBox.y;\n\n      const expectedRelativeX = box.width * 0.25;\n      const expectedRelativeY = box.height * 0.25;\n\n      // Allow a tolerance of 3px for rounding and sub-pixel differences\n      const tolerance = 3;\n\n      expect(cursorRelativeX).toBeGreaterThan(expectedRelativeX - tolerance);\n      expect(cursorRelativeX).toBeLessThan(expectedRelativeX + tolerance);\n      expect(cursorRelativeY).toBeGreaterThan(expectedRelativeY - tolerance);\n      expect(cursorRelativeY).toBeLessThan(expectedRelativeY + tolerance);\n\n      await dnd.page.mouse.up();\n      await dnd.waitForDrop();\n    });\n\n    test('dragged sortable element tracks pointer movement accurately', async ({\n      dnd,\n    }) => {\n      await dnd.goto(stories.sortableVertical);\n      const item = dnd.items.first();\n      await expect(item).toBeVisible();\n\n      const box = await item.boundingBox();\n      if (!box) throw new Error('Could not get bounding box');\n\n      // Click at the center of the first item\n      const clickX = box.x + box.width * 0.5;\n      const clickY = box.y + box.height * 0.5;\n\n      await dnd.page.mouse.move(clickX, clickY);\n      await dnd.page.mouse.down();\n\n      // Move down to trigger drag\n      const firstMoveX = clickX;\n      const firstMoveY = clickY + 60;\n      await dnd.page.mouse.move(firstMoveX, firstMoveY, {steps: 15});\n      await expect(dnd.dragging).toHaveCount(1, {timeout: 3_000});\n\n      // Record the initial offset between cursor and dragging element.\n      // This accounts for any scale transforms applied on drag start.\n      const initialBox = await dnd.dragging.boundingBox();\n      if (!initialBox) throw new Error('Could not get dragging bounding box');\n\n      const initialOffsetX = firstMoveX - initialBox.x;\n      const initialOffsetY = firstMoveY - initialBox.y;\n\n      // Move to a new position and verify the offset stays the same\n      const secondMoveX = clickX + 30;\n      const secondMoveY = clickY + 120;\n      await dnd.page.mouse.move(secondMoveX, secondMoveY, {steps: 10});\n      await dnd.page.waitForTimeout(50);\n\n      const movedBox = await dnd.dragging.boundingBox();\n      if (!movedBox) throw new Error('Could not get dragging bounding box');\n\n      const movedOffsetX = secondMoveX - movedBox.x;\n      const movedOffsetY = secondMoveY - movedBox.y;\n\n      const tolerance = 3;\n      expect(Math.abs(movedOffsetX - initialOffsetX)).toBeLessThan(tolerance);\n      expect(Math.abs(movedOffsetY - initialOffsetY)).toBeLessThan(tolerance);\n\n      await dnd.page.mouse.up();\n      await dnd.waitForDrop();\n    });\n\n    test('dragged element tracks pointer movement accurately', async ({\n      dnd,\n    }) => {\n      await dnd.goto(stories.draggable);\n      const button = dnd.buttons.first();\n      await expect(button).toBeVisible();\n\n      const box = await button.boundingBox();\n      if (!box) throw new Error('Could not get bounding box');\n\n      const clickX = box.x + box.width / 2;\n      const clickY = box.y + box.height / 2;\n\n      await dnd.page.mouse.move(clickX, clickY);\n      await dnd.page.mouse.down();\n\n      // Move to trigger drag activation\n      await dnd.page.mouse.move(clickX, clickY + 50, {steps: 10});\n      await expect(dnd.dragging).toHaveCount(1, {timeout: 3_000});\n\n      // Now move to several positions and check the element tracks the cursor\n      const positions = [\n        {x: clickX + 100, y: clickY + 100},\n        {x: clickX - 50, y: clickY + 200},\n        {x: clickX + 150, y: clickY - 30},\n      ];\n\n      for (const pos of positions) {\n        await dnd.page.mouse.move(pos.x, pos.y, {steps: 5});\n        // Small wait for the position to update\n        await dnd.page.waitForTimeout(50);\n\n        const draggingBox = await dnd.dragging.boundingBox();\n        if (!draggingBox)\n          throw new Error('Could not get dragging bounding box');\n\n        // The cursor should be at the center of the dragged element\n        // (since we started the drag from the center)\n        const centerX = draggingBox.x + draggingBox.width / 2;\n        const centerY = draggingBox.y + draggingBox.height / 2;\n\n        const tolerance = 5;\n        expect(Math.abs(pos.x - centerX)).toBeLessThan(tolerance);\n        expect(Math.abs(pos.y - centerY)).toBeLessThan(tolerance);\n      }\n\n      await dnd.page.mouse.up();\n      await dnd.waitForDrop();\n    });\n  });\n}\n"
  },
  {
    "path": "apps/stories-shared/tests/draggable.tests.ts",
    "content": "import {test, expect} from './fixtures.ts';\n\ninterface DraggableStories {\n  example: string;\n  dragHandle: string;\n}\n\nexport function draggableTests(stories: DraggableStories) {\n  test.describe('Draggable', () => {\n    test.beforeEach(async ({dnd}) => {\n      await dnd.goto(stories.example);\n      await expect(dnd.buttons.first()).toBeVisible();\n    });\n\n    test('can be picked up and dropped with pointer', async ({dnd}) => {\n      const button = dnd.buttons.first();\n\n      const box = await button.boundingBox();\n      await dnd.pointer.drag(button, button);\n      await dnd.waitForDrop();\n\n      const boxAfter = await button.boundingBox();\n      expect(boxAfter!.x).toBeCloseTo(box!.x, -1);\n      expect(boxAfter!.y).toBeCloseTo(box!.y, -1);\n    });\n\n    test('shows dragging state during pointer drag', async ({dnd}) => {\n      const button = dnd.buttons.first();\n      const box = await button.boundingBox();\n\n      await dnd.page.mouse.move(\n        box!.x + box!.width / 2,\n        box!.y + box!.height / 2\n      );\n      await dnd.page.mouse.down();\n      await dnd.page.mouse.move(\n        box!.x + box!.width / 2,\n        box!.y + 100,\n        {steps: 10}\n      );\n\n      await expect(dnd.dragging).toHaveCount(1);\n\n      await dnd.page.mouse.up();\n      await dnd.waitForDrop();\n    });\n  });\n\n  test.describe('Draggable with drag handle', () => {\n    test('can be dragged using the handle with keyboard', async ({dnd}) => {\n      await dnd.goto(stories.dragHandle);\n      const handle = dnd.handles.first();\n      await expect(handle).toBeVisible({timeout: 10_000});\n\n      await dnd.keyboard.pickup(handle);\n      await expect(dnd.dragging).toHaveCount(1);\n      await dnd.keyboard.drop();\n      await dnd.waitForDrop();\n    });\n  });\n}\n"
  },
  {
    "path": "apps/stories-shared/tests/droppable.tests.ts",
    "content": "import {test, expect} from './fixtures.ts';\n\ninterface DroppableStories {\n  example: string;\n  multipleDropTargets?: string;\n}\n\nexport function droppableTests(stories: DroppableStories) {\n  test.describe('Droppable', () => {\n    test.beforeEach(async ({dnd}) => {\n      await dnd.goto(stories.example);\n      await expect(dnd.buttons.first()).toBeVisible();\n    });\n\n    test('drag item into droppable zone with pointer', async ({dnd}) => {\n      const draggable = dnd.buttons.first();\n      const dropzone = dnd.dropzones.first();\n\n      await dnd.pointer.drag(draggable, dropzone);\n      await dnd.waitForDrop();\n\n      await expect(\n        dnd.buttonsIn(dropzone)\n      ).toHaveCount(1);\n    });\n\n    test('cancel drag with Escape keeps item outside dropzone', async ({dnd}) => {\n      const draggable = dnd.buttons.first();\n      const dropzone = dnd.dropzones.first();\n\n      const box = await draggable.boundingBox();\n      const dzBox = await dropzone.boundingBox();\n\n      await dnd.page.mouse.move(\n        box!.x + box!.width / 2,\n        box!.y + box!.height / 2\n      );\n      await dnd.page.mouse.down();\n      await dnd.page.mouse.move(\n        dzBox!.x + dzBox!.width / 2,\n        dzBox!.y + dzBox!.height / 2,\n        {steps: 10}\n      );\n      await dnd.page.keyboard.press('Escape');\n      await dnd.page.mouse.up();\n      await dnd.waitForDrop();\n\n      await expect(\n        dnd.buttonsIn(dropzone)\n      ).toHaveCount(0);\n    });\n  });\n\n  if (stories.multipleDropTargets) {\n    test.describe('Multiple drop targets', () => {\n      test.beforeEach(async ({dnd}) => {\n        await dnd.goto(stories.multipleDropTargets!);\n        await expect(dnd.buttons.first()).toBeVisible();\n      });\n\n      test('drag item into second droppable zone', async ({dnd}) => {\n        const draggable = dnd.buttons.first();\n        const dropzones = dnd.dropzones;\n\n        await dnd.pointer.drag(draggable, dropzones.nth(1));\n        await dnd.waitForDrop();\n\n        await expect(\n          dnd.buttonsIn(dropzones.nth(1))\n        ).toHaveCount(1);\n        await expect(\n          dnd.buttonsIn(dropzones.nth(0))\n        ).toHaveCount(0);\n      });\n\n      test('move item between droppable zones', async ({dnd}) => {\n        const draggable = dnd.buttons.first();\n        const dropzones = dnd.dropzones;\n\n        // Drag into first zone\n        await dnd.pointer.drag(draggable, dropzones.nth(0));\n        await dnd.waitForDrop();\n\n        await expect(dnd.buttonsIn(dropzones.nth(0))).toHaveCount(1);\n\n        // Move from first zone to third zone\n        const movedDraggable = dnd.buttonsIn(dropzones.nth(0)).first();\n        await dnd.pointer.drag(movedDraggable, dropzones.nth(2));\n        await dnd.waitForDrop();\n\n        await expect(dnd.buttonsIn(dropzones.nth(2))).toHaveCount(1);\n        await expect(dnd.buttonsIn(dropzones.nth(0))).toHaveCount(0);\n      });\n    });\n  }\n}\n"
  },
  {
    "path": "apps/stories-shared/tests/fixtures.ts",
    "content": "import {test as base, expect, type Page, type Locator} from '@playwright/test';\n\nexport {expect};\n\ninterface DndFixture {\n  page: Page;\n  buttons: Locator;\n  buttonsIn(parent: Locator): Locator;\n  items: Locator;\n  dragging: Locator;\n  placeholder: Locator;\n  dropzones: Locator;\n  handles: Locator;\n  rows: Locator;\n  columns: Locator;\n  goto(storyId: string): Promise<void>;\n  disableTransitions(): Promise<void>;\n  pointer: PointerActions;\n  keyboard: KeyboardActions;\n  waitForDrop(): Promise<void>;\n}\n\ninterface PointerActions {\n  drag(\n    source: Locator,\n    target: Locator,\n    options?: {steps?: number}\n  ): Promise<void>;\n}\n\ninterface KeyboardActions {\n  pickup(source: Locator): Promise<void>;\n  move(\n    direction: 'up' | 'down' | 'left' | 'right',\n    times?: number\n  ): Promise<void>;\n  drop(): Promise<void>;\n  cancel(): Promise<void>;\n}\n\nexport const test = base.extend<{dnd: DndFixture}>({\n  dnd: async ({page}, use) => {\n    const root = page.locator('#storybook-root');\n    const buttons = root.locator('.btn');\n    const items = root.locator('.Item, .item');\n    const dragging = page.locator('[data-dnd-dragging]');\n    const placeholder = page.locator('[data-dnd-placeholder]');\n    const dropzones = root.locator('.droppable');\n    const handles = root.locator('.handle');\n    const rows = root.locator('tbody tr');\n    const columns = root.locator('thead th');\n\n    const pointer: PointerActions = {\n      async drag(source, target, options) {\n        const steps = options?.steps ?? 20;\n        const sourceBox = await source.boundingBox();\n        const targetBox = await target.boundingBox();\n\n        if (!sourceBox || !targetBox) {\n          throw new Error('Could not get bounding box for source or target');\n        }\n\n        const sx = sourceBox.x + sourceBox.width / 2;\n        const sy = sourceBox.y + sourceBox.height / 2;\n        const tx = targetBox.x + targetBox.width / 2;\n        const ty = targetBox.y + targetBox.height / 2;\n\n        await page.mouse.move(sx, sy);\n        await page.mouse.down();\n        await page.mouse.move(tx, ty, {steps});\n        await expect(dragging).toHaveCount(1, {timeout: 3_000});\n        await page.mouse.up();\n      },\n    };\n\n    const keyboard: KeyboardActions = {\n      async pickup(source) {\n        await source.focus();\n        await page.keyboard.press('Space');\n        await expect(dragging).toHaveCount(1, {timeout: 3_000});\n      },\n      async move(direction, times = 1) {\n        const key =\n          direction === 'up'\n            ? 'ArrowUp'\n            : direction === 'down'\n              ? 'ArrowDown'\n              : direction === 'left'\n                ? 'ArrowLeft'\n                : 'ArrowRight';\n\n        for (let i = 0; i < times; i++) {\n          await page.keyboard.press(key);\n          await page.waitForTimeout(30);\n        }\n      },\n      async drop() {\n        await page.keyboard.press('Space');\n      },\n      async cancel() {\n        await page.keyboard.press('Escape');\n      },\n    };\n\n    const dnd: DndFixture = {\n      page,\n      buttons,\n      buttonsIn(parent: Locator) {\n        return parent.locator('.btn');\n      },\n      items,\n      dragging,\n      placeholder,\n      dropzones,\n      handles,\n      rows,\n      columns,\n\n      async goto(storyId: string) {\n        await page.goto(\n          `/iframe.html?id=${storyId}&viewMode=story`\n        );\n        await page.waitForLoadState('domcontentloaded');\n      },\n\n      async disableTransitions() {\n        await page.addStyleTag({\n          content:\n            '*, *::before, *::after { transition-duration: 0s !important; animation-duration: 0s !important; }',\n        });\n      },\n\n      pointer,\n      keyboard,\n\n      async waitForDrop() {\n        await expect(dragging).toHaveCount(0, {timeout: 5_000});\n      },\n    };\n\n    await use(dnd);\n  },\n});\n\nexpect.extend({\n  async toHaveOrder(locator: Locator, expected: string[]) {\n    const assertionName = 'toHaveOrder';\n    let actual: string[];\n    let pass: boolean;\n\n    try {\n      await expect(async () => {\n        actual = await locator.allTextContents();\n        actual = actual.map((t) => t.trim());\n        expect(actual).toEqual(expected);\n      }).toPass({timeout: 5_000});\n      pass = true;\n    } catch {\n      actual = await locator.allTextContents();\n      actual = actual.map((t) => t.trim());\n      pass = false;\n    }\n\n    return {\n      message: () =>\n        pass\n          ? `expected items NOT to have order ${JSON.stringify(expected)}`\n          : `expected items to have order ${JSON.stringify(expected)}, but got ${JSON.stringify(actual!)}`,\n      pass,\n      name: assertionName,\n      expected,\n      actual: actual!,\n    };\n  },\n\n  async toBeDragging(locator: Locator) {\n    const assertionName = 'toBeDragging';\n    let pass: boolean;\n\n    try {\n      await expect(locator).toHaveAttribute('data-dnd-dragging', 'true', {\n        timeout: 3_000,\n      });\n      pass = true;\n    } catch {\n      pass = false;\n    }\n\n    return {\n      message: () =>\n        pass\n          ? 'expected element NOT to be dragging'\n          : 'expected element to be dragging (have [data-dnd-dragging] attribute)',\n      pass,\n      name: assertionName,\n    };\n  },\n\n  async toBeDropTarget(locator: Locator) {\n    const assertionName = 'toBeDropTarget';\n    let pass: boolean;\n\n    try {\n      await expect(locator).toHaveClass(/active/, {\n        timeout: 3_000,\n      });\n      pass = true;\n    } catch {\n      pass = false;\n    }\n\n    return {\n      message: () =>\n        pass\n          ? 'expected element NOT to be a drop target'\n          : 'expected element to be a drop target (have \"active\" class)',\n      pass,\n      name: assertionName,\n    };\n  },\n});\n\ndeclare module '@playwright/test' {\n  interface Matchers<R, T> {\n    toHaveOrder(expected: string[]): R;\n    toBeDragging(): R;\n    toBeDropTarget(): R;\n  }\n}\n"
  },
  {
    "path": "apps/stories-shared/tests/sortable-transformed.tests.ts",
    "content": "import {test, expect} from './fixtures.ts';\n\ninterface SortableTransformedStories {\n  withOverlay: string;\n  withoutOverlay: string;\n}\n\nexport function sortableTransformedTests(stories: SortableTransformedStories) {\n  for (const [label, storyId, usesOverlay] of [\n    ['with overlay', stories.withOverlay, true],\n    ['without overlay', stories.withoutOverlay, false],\n  ] as const) {\n    test.describe(`Sortable with CSS transforms (${label})`, () => {\n      test.beforeEach(async ({dnd}) => {\n        await dnd.goto(storyId);\n        await expect(dnd.items.first()).toBeVisible();\n      });\n\n      test('dragged element appears at correct position for transform-positioned item', async ({\n        dnd,\n      }) => {\n        // Target the 3rd item (index 2) which has a non-trivial\n        // transform: translateY(124px). If the Feedback plugin doesn't\n        // account for the CSS transform, the dragged element will appear\n        // offset by that amount.\n        const item = dnd.items.nth(2);\n        await expect(item).toBeVisible();\n\n        const box = await item.boundingBox();\n        if (!box) throw new Error('Could not get bounding box');\n\n        const clickX = box.x + box.width / 2;\n        const clickY = box.y + box.height / 2;\n\n        await dnd.page.mouse.move(clickX, clickY);\n        await dnd.page.mouse.down();\n\n        await dnd.page.mouse.move(clickX, clickY + 60, {steps: 15});\n        await expect(dnd.dragging).toHaveCount(1, {timeout: 3_000});\n\n        const draggingBox = await dnd.dragging.boundingBox();\n        if (!draggingBox)\n          throw new Error('Could not get dragging bounding box');\n\n        // The cursor should still be at approximately the center of the\n        // dragged element relative to its width/height.\n        const cursorRelativeX = clickX - draggingBox.x;\n        const cursorRelativeY = clickY + 60 - draggingBox.y;\n\n        const expectedRelativeX = box.width / 2;\n        const expectedRelativeY = box.height / 2;\n\n        const tolerance = 10;\n\n        expect(\n          Math.abs(cursorRelativeX - expectedRelativeX),\n          `Dragged element X offset from cursor is wrong by ${Math.abs(cursorRelativeX - expectedRelativeX)}px`\n        ).toBeLessThan(tolerance);\n        expect(\n          Math.abs(cursorRelativeY - expectedRelativeY),\n          `Dragged element Y offset from cursor is wrong by ${Math.abs(cursorRelativeY - expectedRelativeY)}px. ` +\n            `This likely means the CSS transform offset was not compensated.`\n        ).toBeLessThan(tolerance);\n\n        await dnd.page.mouse.up();\n        await dnd.waitForDrop();\n      });\n\n      test('dragged element tracks pointer accurately for transform-positioned items', async ({\n        dnd,\n      }) => {\n        const item = dnd.items.nth(3);\n        await expect(item).toBeVisible();\n\n        const box = await item.boundingBox();\n        if (!box) throw new Error('Could not get bounding box');\n\n        const clickX = box.x + box.width / 2;\n        const clickY = box.y + box.height / 2;\n\n        await dnd.page.mouse.move(clickX, clickY);\n        await dnd.page.mouse.down();\n\n        const firstMoveX = clickX;\n        const firstMoveY = clickY + 60;\n        await dnd.page.mouse.move(firstMoveX, firstMoveY, {steps: 15});\n        await expect(dnd.dragging).toHaveCount(1, {timeout: 3_000});\n\n        // Record initial offset between cursor and dragged element\n        const initialBox = await dnd.dragging.boundingBox();\n        if (!initialBox)\n          throw new Error('Could not get initial dragging bounding box');\n\n        const initialOffsetX = firstMoveX - initialBox.x;\n        const initialOffsetY = firstMoveY - initialBox.y;\n\n        // Move to several positions and verify the offset stays consistent\n        const positions = [\n          {x: clickX + 50, y: clickY + 120},\n          {x: clickX - 30, y: clickY + 200},\n          {x: clickX + 100, y: clickY + 80},\n        ];\n\n        const tolerance = 5;\n\n        for (const pos of positions) {\n          await dnd.page.mouse.move(pos.x, pos.y, {steps: 5});\n          await dnd.page.waitForTimeout(50);\n\n          const movedBox = await dnd.dragging.boundingBox();\n          if (!movedBox)\n            throw new Error('Could not get dragging bounding box during move');\n\n          const movedOffsetX = pos.x - movedBox.x;\n          const movedOffsetY = pos.y - movedBox.y;\n\n          expect(\n            Math.abs(movedOffsetX - initialOffsetX),\n            `X offset drifted by ${Math.abs(movedOffsetX - initialOffsetX)}px`\n          ).toBeLessThan(tolerance);\n          expect(\n            Math.abs(movedOffsetY - initialOffsetY),\n            `Y offset drifted by ${Math.abs(movedOffsetY - initialOffsetY)}px`\n          ).toBeLessThan(tolerance);\n        }\n\n        await dnd.page.mouse.up();\n        await dnd.waitForDrop();\n      });\n\n      test('can reorder transform-positioned items with pointer', async ({\n        dnd,\n      }) => {\n        const first = dnd.items.nth(0);\n        const second = dnd.items.nth(1);\n\n        await expect(first).toHaveText('1');\n        await expect(second).toHaveText('2');\n\n        await dnd.pointer.drag(first, second);\n        await dnd.waitForDrop();\n\n        await expect(dnd.items.nth(0)).toHaveText('2');\n        await expect(dnd.items.nth(1)).toHaveText('1');\n        await expect(dnd.items.nth(2)).toHaveText('3');\n      });\n    });\n  }\n}\n"
  },
  {
    "path": "apps/stories-shared/tests/sortable-vertical.tests.ts",
    "content": "import {test, expect} from './fixtures.ts';\n\ninterface SortableVerticalStories {\n  basicSetup: string;\n  withDragHandle: string;\n}\n\nexport function sortableVerticalTests(stories: SortableVerticalStories) {\n  test.describe('Sortable vertical list', () => {\n    test.beforeEach(async ({dnd}) => {\n      await dnd.goto(stories.basicSetup);\n      await expect(dnd.items.first()).toBeVisible();\n    });\n\n    test('reorder items down with pointer', async ({dnd}) => {\n      const first = dnd.items.nth(0);\n      const third = dnd.items.nth(2);\n\n      await expect(first).toHaveText('1');\n\n      await dnd.pointer.drag(first, third);\n      await dnd.waitForDrop();\n\n      await expect(dnd.items.nth(0)).toHaveText('2');\n      await expect(dnd.items.nth(1)).toHaveText('3');\n      await expect(dnd.items.nth(2)).toHaveText('1');\n    });\n\n    test('reorder items up with pointer', async ({dnd}) => {\n      const third = dnd.items.nth(2);\n      const first = dnd.items.nth(0);\n\n      await dnd.pointer.drag(third, first);\n      await dnd.waitForDrop();\n\n      await expect(dnd.items.nth(0)).toHaveText('3');\n      await expect(dnd.items.nth(1)).toHaveText('1');\n      await expect(dnd.items.nth(2)).toHaveText('2');\n    });\n\n    test('reorder items with keyboard', async ({dnd}) => {\n      const first = dnd.items.nth(0);\n\n      await dnd.keyboard.pickup(first);\n      await dnd.keyboard.move('down', 2);\n      await dnd.keyboard.drop();\n      await dnd.waitForDrop();\n\n      await expect(dnd.items.nth(0)).toHaveText('2');\n      await expect(dnd.items.nth(1)).toHaveText('3');\n      await expect(dnd.items.nth(2)).toHaveText('1');\n    });\n\n    test('cancel keyboard drag restores order', async ({dnd}) => {\n      const first = dnd.items.nth(0);\n\n      await dnd.keyboard.pickup(first);\n      await dnd.keyboard.move('down', 3);\n      await dnd.keyboard.cancel();\n      await dnd.waitForDrop();\n\n      await expect(dnd.items.nth(0)).toHaveText('1');\n      await expect(dnd.items.nth(1)).toHaveText('2');\n      await expect(dnd.items.nth(2)).toHaveText('3');\n      await expect(dnd.items.nth(3)).toHaveText('4');\n    });\n\n    test('placeholder is visible during drag', async ({dnd}) => {\n      const first = dnd.items.nth(0);\n      const third = dnd.items.nth(2);\n\n      const sourceBox = await first.boundingBox();\n      const targetBox = await third.boundingBox();\n\n      await dnd.page.mouse.move(\n        sourceBox!.x + sourceBox!.width / 2,\n        sourceBox!.y + sourceBox!.height / 2\n      );\n      await dnd.page.mouse.down();\n      await dnd.page.mouse.move(\n        targetBox!.x + targetBox!.width / 2,\n        targetBox!.y + targetBox!.height / 2,\n        {steps: 10}\n      );\n\n      await expect(dnd.dragging).toHaveCount(1);\n      await expect(dnd.placeholder).toHaveCount(1);\n\n      await dnd.page.mouse.up();\n      await dnd.waitForDrop();\n    });\n  });\n\n  test.describe('Sortable vertical list with drag handle', () => {\n    test.beforeEach(async ({dnd}) => {\n      await dnd.goto(stories.withDragHandle);\n      await expect(dnd.items.first()).toBeVisible();\n    });\n\n    test('reorder using drag handle with keyboard', async ({dnd}) => {\n      const firstHandle = dnd.handles.nth(0);\n\n      await dnd.keyboard.pickup(firstHandle);\n      await dnd.keyboard.move('down', 2);\n      await dnd.keyboard.drop();\n      await dnd.waitForDrop();\n\n      await expect(dnd.items.nth(0)).toHaveText('2');\n      await expect(dnd.items.nth(1)).toHaveText('3');\n      await expect(dnd.items.nth(2)).toHaveText('1');\n    });\n  });\n}\n"
  },
  {
    "path": "apps/stories-shared/utilities/classnames.ts",
    "content": "export function classNames(\n  ...classes: (string | boolean | null | undefined)[]\n) {\n  return classes.filter(Boolean).join(' ');\n}\n"
  },
  {
    "path": "apps/stories-shared/utilities/createRange.ts",
    "content": "import type {UniqueIdentifier} from '@dnd-kit/abstract';\n\nexport function createRange(count: number): UniqueIdentifier[] {\n  return Array.from({length: count}, (_, i) => i + 1);\n}\n"
  },
  {
    "path": "apps/stories-shared/utilities/index.ts",
    "content": "export {classNames} from './classnames.ts';\nexport {createRange} from './createRange.ts';\n"
  },
  {
    "path": "apps/stories-solid/.storybook/main.ts",
    "content": "import {readFileSync} from 'fs';\nimport {dirname, join} from 'path';\nimport {mergeConfig} from 'vite';\n\nconst sharedPreviewHead = readFileSync(\n  join(__dirname, '..', '..', 'stories-shared', 'preview-head.html'),\n  'utf-8'\n);\n\nexport default {\n  previewHead: (head: string) => `${sharedPreviewHead}\\n${head}`,\n  stories: ['../stories/**/*.stories.tsx'],\n\n  addons: [\n    getAbsolutePath('@storybook/addon-links'),\n    getAbsolutePath('@vueless/storybook-dark-mode'),\n    getAbsolutePath('@dnd-kit/storybook-addon-codesandbox'),\n  ],\n\n  framework: {\n    name: getAbsolutePath('storybook-solidjs-vite'),\n    options: {},\n  },\n\n  async viteFinal(config) {\n    return mergeConfig(config, {\n      define: {\n        'process.env': {},\n      },\n      optimizeDeps: {\n        exclude: ['@dnd-kit/*'],\n      },\n    });\n  },\n};\n\nfunction getAbsolutePath(value) {\n  return dirname(require.resolve(join(value, 'package.json')));\n}\n"
  },
  {
    "path": "apps/stories-solid/.storybook/manager-head.html",
    "content": "<link\n  rel=\"apple-touch-icon\"\n  sizes=\"180x180\"\n  href=\"/apple-touch-icon.png\"\n/>\n<link\n  rel=\"icon\"\n  type=\"image/png\"\n  sizes=\"32x32\"\n  href=\"/favicon-32x32.png\"\n/>\n<link\n  rel=\"icon\"\n  type=\"image/png\"\n  sizes=\"16x16\"\n  href=\"/favicon-16x16.png\"\n/>\n<link rel=\"shortcut icon\" href=\"/favicon.ico\">\n<style>\n  img[src*=\"dnd-kit-banner\"] {\n    width: 100%;\n    max-width: 200px;\n    margin-bottom: 10px;\n  }\n</style>\n"
  },
  {
    "path": "apps/stories-solid/.storybook/manager.ts",
    "content": "import {addons} from 'storybook/manager-api';\n\nimport {theme} from './theme';\n\naddons.setConfig({\n  theme,\n  showPanel: false,\n});\n"
  },
  {
    "path": "apps/stories-solid/.storybook/preview.ts",
    "content": "import '@dnd-kit/stories-shared/register';\nimport {withCodeSandbox} from '@dnd-kit/storybook-addon-codesandbox/decorator-dom';\n\nconst preview = {\n  decorators: [withCodeSandbox],\n  parameters: {\n    codesandbox: {\n      files: {\n        'index.html': [\n          '<!DOCTYPE html>',\n          '<html>',\n          '<head>',\n          '  <title>Solid Demo</title>',\n          '  <meta charset=\"UTF-8\" />',\n          '</head>',\n          '<body>',\n          '  <div id=\"app\"></div>',\n          '  <script src=\"src/index.js\"></script>',\n          '</body>',\n          '</html>',\n        ].join('\\n'),\n        'src/index.js': [\n          \"import './styles.css';\",\n          \"import {render} from 'solid-js/web';\",\n          \"import App from './App';\",\n          \"\",\n          \"render(App, document.getElementById('app'));\",\n        ].join('\\n'),\n        '.babelrc': JSON.stringify(\n          {presets: ['babel-preset-solid']},\n          null,\n          2\n        ),\n        'tsconfig.json': JSON.stringify(\n          {\n            compilerOptions: {\n              jsx: 'preserve',\n              jsxImportSource: 'solid-js',\n              noEmit: true,\n            },\n          },\n          null,\n          2\n        ),\n        'package.json': JSON.stringify(\n          {\n            name: 'dnd-kit-sandbox',\n            main: 'index.html',\n            dependencies: {\n              '@dnd-kit/abstract': 'beta',\n              '@dnd-kit/dom': 'beta',\n              '@dnd-kit/solid': 'beta',\n              '@dnd-kit/helpers': 'beta',\n              '@dnd-kit/collision': 'beta',\n              'babel-preset-solid': 'latest',\n              'solid-js': '^1.9.0',\n            },\n            devDependencies: {\n              '@babel/core': '7.2.0',\n              'parcel-bundler': '^1.6.1',\n            },\n          },\n          null,\n          2\n        ),\n      },\n      mainFile: 'src/App.tsx',\n    },\n    darkMode: {\n      stylePreview: true,\n    },\n    options: {\n      storySort: {\n        order: [\n          'Draggable',\n          [\n            'Basic setup',\n            'Drag handles',\n          ],\n          'Droppable',\n          'Sortable',\n          [\n            'Vertical list',\n            'Horizontal list',\n            'Grid',\n            'Multiple lists',\n          ],\n        ],\n      },\n    },\n  },\n};\n\nexport default preview;\n"
  },
  {
    "path": "apps/stories-solid/.storybook/theme.ts",
    "content": "import {create} from 'storybook/theming/create';\nimport {default as brandImage} from './assets/dnd-kit-banner.svg';\n\nexport const theme = create({\n  base: 'light',\n  brandImage,\n  appBg: '#F9F9F9',\n});\n"
  },
  {
    "path": "apps/stories-solid/custom-elements.d.ts",
    "content": "import \"solid-js\";\n\ndeclare module \"solid-js\" {\n  namespace JSX {\n    // Allow specific data-* attributes on all elements (native and custom)\n    interface DOMAttributes<T> {\n      \"data-shadow\"?: string;\n      \"data-accent-color\"?: string;\n      \"data-highlight\"?: string;\n    }\n    // Allow attr:data-* prefix variants (used on custom elements)\n    interface ExplicitAttributes {\n      \"data-shadow\"?: string;\n      \"data-accent-color\"?: string;\n      \"data-highlight\"?: string;\n    }\n    // Declare custom elements used in stories\n    interface IntrinsicElements {\n      \"container-component\": HTMLAttributes<HTMLElement>;\n      \"item-component\": HTMLAttributes<HTMLElement>;\n    }\n  }\n}\n"
  },
  {
    "path": "apps/stories-solid/package.json",
    "content": "{\n  \"name\": \"@dnd-kit/stories-solid\",\n  \"version\": \"0.0.0\",\n  \"type\": \"module\",\n  \"private\": true,\n  \"scripts\": {\n    \"dev\": \"storybook dev -p 6009\",\n    \"build\": \"storybook build\",\n    \"clean\": \"rm -rf .turbo && rm -rf node_modules\",\n    \"test:e2e\": \"playwright test\",\n    \"test:e2e:ui\": \"playwright test --ui\"\n  },\n  \"dependencies\": {\n    \"@dnd-kit/abstract\": \"*\",\n    \"@dnd-kit/dom\": \"*\",\n    \"@dnd-kit/solid\": \"*\",\n    \"@dnd-kit/helpers\": \"*\",\n    \"@dnd-kit/stories-shared\": \"*\",\n    \"@dnd-kit/storybook-addon-codesandbox\": \"*\",\n    \"solid-js\": \"^1.9.0\"\n  },\n  \"devDependencies\": {\n    \"@playwright/test\": \"^1.58.2\",\n    \"@storybook/addon-links\": \"^9.0.15\",\n    \"@vueless/storybook-dark-mode\": \"^9.0.6\",\n    \"storybook\": \"^9.0.15\",\n    \"storybook-solidjs-vite\": \"^9.0.3\",\n    \"typescript\": \"^5.7.3\",\n    \"vite\": \"^6.0.0\",\n    \"vite-plugin-solid\": \"^2.11.0\"\n  }\n}\n"
  },
  {
    "path": "apps/stories-solid/playwright.config.ts",
    "content": "import {defineConfig} from '@playwright/test';\n\nconst CI = !!process.env.CI;\n\nexport default defineConfig({\n  testDir: './tests',\n  timeout: 15_000,\n  expect: {\n    timeout: 5_000,\n  },\n  fullyParallel: true,\n  retries: CI ? 2 : 1,\n  reporter: CI ? 'html' : 'list',\n  use: {\n    baseURL: 'http://localhost:6009',\n    actionTimeout: 5_000,\n  },\n  projects: [\n    {\n      name: 'chromium',\n      use: {browserName: 'chromium'},\n    },\n  ],\n  webServer: {\n    command: 'npx http-server storybook-static --port 6009 --silent',\n    port: 6009,\n    reuseExistingServer: !CI,\n    timeout: 120_000,\n  },\n});\n"
  },
  {
    "path": "apps/stories-solid/raw.d.ts",
    "content": "declare module '*.tsx?raw' {\n  const content: string;\n  export default content;\n}\n\ndeclare module '*.ts?raw' {\n  const content: string;\n  export default content;\n}\n"
  },
  {
    "path": "apps/stories-solid/stories/Draggable/DragHandles/DragHandles.stories.tsx",
    "content": "import type {Meta, StoryObj} from 'storybook-solidjs';\n\nimport DragHandlesApp from './DragHandlesApp';\nimport dragHandlesSource from './DragHandlesApp.tsx?raw';\nimport {\n  baseStyles,\n  draggableStyles,\n  handleStyles,\n} from '@dnd-kit/stories-shared/styles/sandbox';\n\nconst meta: Meta = {\n  title: 'Draggable/Drag handles',\n  component: DragHandlesApp,\n  decorators: [\n    (Story) => (\n      <>\n        <style>{baseStyles}</style>\n        <style>{draggableStyles}</style>\n        <style>{handleStyles}</style>\n        <Story />\n      </>\n    ),\n  ],\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const Example: Story = {\n  parameters: {\n    codesandbox: {\n      files: {\n        'src/App.tsx': dragHandlesSource,\n        'src/styles.css': [baseStyles, draggableStyles, handleStyles].join(\n          '\\n\\n'\n        ),\n      },\n    },\n  },\n};\n"
  },
  {
    "path": "apps/stories-solid/stories/Draggable/DragHandles/DragHandlesApp.tsx",
    "content": "import {DragDropProvider, useDraggable} from '@dnd-kit/solid';\n\nfunction Draggable() {\n  const {isDragging, ref, handleRef} = useDraggable({id: 'draggable'});\n\n  return (\n    <div class=\"btn\" ref={ref} data-shadow={isDragging() ? 'true' : undefined}>\n      draggable\n      <button ref={handleRef} class=\"handle\" />\n    </div>\n  );\n}\n\nexport default function App() {\n  return (\n    <DragDropProvider>\n      <Draggable />\n    </DragDropProvider>\n  );\n}\n"
  },
  {
    "path": "apps/stories-solid/stories/Draggable/Draggable.stories.tsx",
    "content": "import type {Meta, StoryObj} from 'storybook-solidjs';\n\nimport App from './DraggableApp';\nimport draggableSource from './DraggableApp.tsx?raw';\nimport {baseStyles, draggableStyles} from '@dnd-kit/stories-shared/styles/sandbox';\n\nconst meta: Meta = {\n  title: 'Draggable/Basic setup',\n  component: App,\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const Example: Story = {\n  parameters: {\n    codesandbox: {\n      files: {\n        'src/App.tsx': draggableSource,\n        'src/styles.css': [baseStyles, draggableStyles].join('\\n\\n'),\n      },\n    },\n  },\n};\n"
  },
  {
    "path": "apps/stories-solid/stories/Draggable/DraggableApp.tsx",
    "content": "import {DragDropProvider, useDraggable} from '@dnd-kit/solid';\n\nfunction Draggable() {\n  const {ref} = useDraggable({id: 'draggable'});\n\n  return <button ref={ref} class=\"btn\">draggable</button>;\n}\n\nexport default function App() {\n  return (\n    <DragDropProvider>\n      <Draggable />\n    </DragDropProvider>\n  );\n}\n"
  },
  {
    "path": "apps/stories-solid/stories/Droppable/Droppable.stories.tsx",
    "content": "import type {Meta, StoryObj} from 'storybook-solidjs';\n\nimport App from './DroppableApp';\nimport droppableSource from './DroppableApp.tsx?raw';\nimport {baseStyles, draggableStyles, droppableStyles} from '@dnd-kit/stories-shared/styles/sandbox';\n\nconst meta: Meta = {\n  title: 'Droppable/Basic setup',\n  component: App,\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const Example: Story = {\n  parameters: {\n    codesandbox: {\n      files: {\n        'src/App.tsx': droppableSource,\n        'src/styles.css': [baseStyles, draggableStyles, droppableStyles].join('\\n\\n'),\n      },\n    },\n  },\n};\n"
  },
  {
    "path": "apps/stories-solid/stories/Droppable/DroppableApp.tsx",
    "content": "import {createSignal} from 'solid-js';\nimport {DragDropProvider, useDraggable, useDroppable} from '@dnd-kit/solid';\n\nfunction Draggable() {\n  const {ref} = useDraggable({id: 'draggable'});\n\n  return <button ref={ref} class=\"btn\">draggable</button>;\n}\n\nfunction Droppable(props: {children?: any}) {\n  const {isDropTarget, ref} = useDroppable({id: 'droppable'});\n\n  return (\n    <div ref={ref} class={isDropTarget() ? 'droppable active' : 'droppable'}>\n      {props.children}\n    </div>\n  );\n}\n\nexport default function App() {\n  const [parent, setParent] = createSignal<string | undefined>();\n\n  return (\n    <DragDropProvider\n      onDragEnd={(event) => {\n        if (event.canceled) return;\n        setParent(event.operation.target?.id as string);\n      }}\n    >\n      <section class=\"drop-layout\">\n        {parent() == null ? <Draggable /> : null}\n        <Droppable>\n          {parent() === 'droppable' ? <Draggable /> : null}\n        </Droppable>\n      </section>\n    </DragDropProvider>\n  );\n}\n"
  },
  {
    "path": "apps/stories-solid/stories/Droppable/MultipleDroppable/MultipleDroppable.stories.tsx",
    "content": "import type {Meta, StoryObj} from 'storybook-solidjs';\n\nimport App from './MultipleDroppableApp';\nimport multipleDroppableSource from './MultipleDroppableApp.tsx?raw';\nimport {baseStyles, draggableStyles, droppableStyles} from '@dnd-kit/stories-shared/styles/sandbox';\n\nconst meta: Meta = {\n  title: 'Droppable/Multiple drop targets',\n  component: App,\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const Example: Story = {\n  parameters: {\n    codesandbox: {\n      files: {\n        'src/App.tsx': multipleDroppableSource,\n        'src/styles.css': [baseStyles, draggableStyles, droppableStyles].join('\\n\\n'),\n      },\n    },\n  },\n};\n"
  },
  {
    "path": "apps/stories-solid/stories/Droppable/MultipleDroppable/MultipleDroppableApp.tsx",
    "content": "import {createSignal, For} from 'solid-js';\nimport {DragDropProvider, useDraggable, useDroppable} from '@dnd-kit/solid';\n\nfunction Draggable() {\n  const {ref} = useDraggable({id: 'draggable'});\n\n  return <button ref={ref} class=\"btn\">draggable</button>;\n}\n\nfunction Droppable(props: {id: string; children?: any}) {\n  const {isDropTarget, ref} = useDroppable({id: props.id});\n\n  return (\n    <div ref={ref} class={isDropTarget() ? 'droppable active' : 'droppable'}>\n      {props.children}\n    </div>\n  );\n}\n\nexport default function App() {\n  const [parent, setParent] = createSignal<string | undefined>();\n  const droppables = ['A', 'B', 'C'];\n\n  return (\n    <DragDropProvider\n      onDragEnd={(event) => {\n        if (event.canceled) return;\n        setParent(event.operation.target?.id as string);\n      }}\n    >\n      <div style={{display: 'grid', 'grid-template-columns': '1fr 1fr', gap: '20px', 'max-width': '500px', margin: '0 auto'}}>\n        <div style={{display: 'flex', 'align-items': 'center', 'justify-content': 'center'}}>\n          {parent() == null ? <Draggable /> : null}\n        </div>\n        <For each={droppables}>\n          {(id) => (\n            <Droppable id={id}>\n              {parent() === id ? <Draggable /> : null}\n            </Droppable>\n          )}\n        </For>\n      </div>\n    </DragDropProvider>\n  );\n}\n"
  },
  {
    "path": "apps/stories-solid/stories/Sortable/Grid/Grid.stories.tsx",
    "content": "import type {Meta, StoryObj} from 'storybook-solidjs';\n\nimport App from './GridSortableApp';\nimport gridSortableSource from './GridSortableApp.tsx?raw';\nimport {baseStyles, sortableStyles} from '@dnd-kit/stories-shared/styles/sandbox';\n\nconst meta: Meta = {\n  title: 'Sortable/Grid',\n  component: App,\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const BasicSetup: Story = {\n  name: 'Basic setup',\n  parameters: {\n    codesandbox: {\n      files: {\n        'src/App.tsx': gridSortableSource,\n        'src/styles.css': [baseStyles, sortableStyles].join('\\n\\n'),\n      },\n    },\n  },\n};\n"
  },
  {
    "path": "apps/stories-solid/stories/Sortable/Grid/GridSortableApp.tsx",
    "content": "import {createSignal, For} from 'solid-js';\nimport {DragDropProvider} from '@dnd-kit/solid';\nimport {useSortable} from '@dnd-kit/solid/sortable';\nimport {move} from '@dnd-kit/helpers';\n\nfunction Sortable(props: {id: number; index: number}) {\n  const {isDragging, ref} = useSortable({\n    get id() { return props.id; },\n    get index() { return props.index; },\n  });\n\n  return (\n    <div\n      ref={ref}\n      class=\"item\"\n      data-shadow={isDragging() ? '' : undefined}\n      style={{height: '100%', 'justify-content': 'center'}}\n    >\n      {props.id}\n    </div>\n  );\n}\n\nexport default function App() {\n  const [items, setItems] = createSignal(createRange(20));\n\n  return (\n    <DragDropProvider\n      onDragEnd={(event) => {\n        setItems((items) => move(items, event));\n      }}\n    >\n      <div style={{display: 'grid', 'grid-template-columns': 'repeat(auto-fill, 150px)', 'grid-auto-rows': '150px', 'grid-auto-flow': 'dense', gap: '18px', padding: '0 30px', 'max-width': '900px', 'margin-inline': 'auto', 'justify-content': 'center'}}>\n        <For each={items()}>\n          {(id, index) => <Sortable id={id} index={index()} />}\n        </For>\n      </div>\n    </DragDropProvider>\n  );\n}\n\nfunction createRange(length: number) {\n  return Array.from({length}, (_, i) => i + 1);\n}\n"
  },
  {
    "path": "apps/stories-solid/stories/Sortable/Horizontal/Horizontal.stories.tsx",
    "content": "import type {Meta, StoryObj} from 'storybook-solidjs';\n\nimport App from './HorizontalSortableApp';\nimport horizontalSortableSource from './HorizontalSortableApp.tsx?raw';\nimport {baseStyles, sortableStyles} from '@dnd-kit/stories-shared/styles/sandbox';\n\nconst meta: Meta = {\n  title: 'Sortable/Horizontal list',\n  component: App,\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const BasicSetup: Story = {\n  name: 'Basic setup',\n  parameters: {\n    codesandbox: {\n      files: {\n        'src/App.tsx': horizontalSortableSource,\n        'src/styles.css': [baseStyles, sortableStyles].join('\\n\\n'),\n      },\n    },\n  },\n};\n"
  },
  {
    "path": "apps/stories-solid/stories/Sortable/Horizontal/HorizontalSortableApp.tsx",
    "content": "import {createSignal, For} from 'solid-js';\nimport {DragDropProvider} from '@dnd-kit/solid';\nimport {useSortable} from '@dnd-kit/solid/sortable';\nimport {move} from '@dnd-kit/helpers';\n\nfunction Sortable(props: {id: number; index: number}) {\n  const {isDragging, ref} = useSortable({\n    get id() { return props.id; },\n    get index() { return props.index; },\n  });\n\n  return (\n    <div\n      ref={ref}\n      class=\"item\"\n      data-shadow={isDragging() ? '' : undefined}\n      style={{'aspect-ratio': '1', 'justify-content': 'center'}}\n    >\n      {props.id}\n    </div>\n  );\n}\n\nexport default function App() {\n  const [items, setItems] = createSignal(createRange(10));\n\n  return (\n    <DragDropProvider\n      onDragEnd={(event) => {\n        setItems((items) => move(items, event));\n      }}\n    >\n      <div style={{display: 'inline-flex', 'flex-direction': 'row', 'align-items': 'stretch', height: '180px', gap: '18px', padding: '0 30px'}}>\n        <For each={items()}>\n          {(id, index) => <Sortable id={id} index={index()} />}\n        </For>\n      </div>\n    </DragDropProvider>\n  );\n}\n\nfunction createRange(length: number) {\n  return Array.from({length}, (_, i) => i + 1);\n}\n"
  },
  {
    "path": "apps/stories-solid/stories/Sortable/MultipleLists/MultipleLists.stories.tsx",
    "content": "import type {Meta, StoryObj} from 'storybook-solidjs';\n\nimport MultipleListsApp from './MultipleListsApp.tsx';\nimport multipleListsSource from './MultipleListsApp.tsx?raw';\nimport {baseStyles, sortableStyles, multipleListsStyles} from '@dnd-kit/stories-shared/styles/sandbox';\n\nconst styles = [baseStyles, sortableStyles, multipleListsStyles].join('\\n\\n');\n\nconst meta: Meta = {\n  title: 'Sortable/Multiple lists',\n  component: MultipleListsApp,\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const BasicSetup: Story = {\n  name: 'Basic setup',\n  render: () => (\n    <>\n      <style>{styles}</style>\n      <MultipleListsApp />\n    </>\n  ),\n  parameters: {\n    codesandbox: {\n      files: {\n        'src/App.tsx': multipleListsSource,\n        'src/styles.css': styles,\n      },\n    },\n  },\n};\n"
  },
  {
    "path": "apps/stories-solid/stories/Sortable/MultipleLists/MultipleListsApp.tsx",
    "content": "import {createSignal, For} from 'solid-js';\nimport {CollisionPriority} from '@dnd-kit/abstract';\nimport {DragDropProvider} from '@dnd-kit/solid';\nimport {useSortable} from '@dnd-kit/solid/sortable';\nimport {defaultPreset, PointerSensor, KeyboardSensor} from '@dnd-kit/dom';\nimport {move} from '@dnd-kit/helpers';\n\nfunction createRange(length: number) {\n  return Array.from({length}, (_, i) => i + 1);\n}\n\nconst ITEM_COUNT = 6;\n\nconst COLORS: Record<string, string> = {\n  A: '#7193f1',\n  B: '#FF851B',\n  C: '#2ECC40',\n  D: '#ff3680',\n};\n\nconst sensors = [\n  PointerSensor.configure({\n    activatorElements(source) {\n      return [source.element, source.handle];\n    },\n  }),\n  KeyboardSensor,\n];\n\nfunction SortableItem(props: {id: string; column: string; index: number}) {\n  const {isDragging, ref, handleRef} = useSortable({\n    get id() {\n      return props.id;\n    },\n    get index() {\n      return props.index;\n    },\n    get group() {\n      return props.column;\n    },\n    get data() {\n      return {group: props.column};\n    },\n    accept: 'item',\n    type: 'item',\n    feedback: 'clone',\n  });\n\n  return (\n    <li\n      ref={ref}\n      class=\"item\"\n      data-shadow={isDragging() ? 'true' : undefined}\n      data-accent-color={props.column}\n      style={{'--accent-color': COLORS[props.column]}}\n    >\n      {props.id}\n      <button ref={handleRef} class=\"handle\" />\n    </li>\n  );\n}\n\nfunction SortableColumn(props: {id: string; index: number; rows: string[]}) {\n  const {isDragging, ref, handleRef} = useSortable({\n    get id() {\n      return props.id;\n    },\n    get index() {\n      return props.index;\n    },\n    accept: ['column', 'item'],\n    collisionPriority: CollisionPriority.Low,\n    type: 'column',\n  });\n\n  return (\n    <div\n      ref={ref}\n      class=\"container\"\n      data-shadow={isDragging() ? 'true' : undefined}\n    >\n      <h2>\n        {props.id}\n        <button ref={handleRef} class=\"handle\" />\n      </h2>\n      <ul>\n        <For each={props.rows}>\n          {(itemId, itemIndex) => (\n            <SortableItem id={itemId} column={props.id} index={itemIndex()} />\n          )}\n        </For>\n      </ul>\n    </div>\n  );\n}\n\nexport default function App() {\n  const [items, setItems] = createSignal<Record<string, string[]>>({\n    A: createRange(ITEM_COUNT).map((id) => `A${id}`),\n    B: createRange(ITEM_COUNT).map((id) => `B${id}`),\n    C: createRange(ITEM_COUNT).map((id) => `C${id}`),\n    D: [],\n  });\n\n  const columns = Object.keys(items());\n  let snapshot = structuredClone(items());\n\n  return (\n    <DragDropProvider\n      plugins={defaultPreset.plugins}\n      sensors={sensors}\n      onDragStart={() => {\n        snapshot = structuredClone(items());\n      }}\n      onDragOver={(event) => {\n        const {source} = event.operation;\n        if (source && source.type === 'column') return;\n        event.preventDefault();\n        setItems((items) => move(items, event));\n      }}\n      onDragEnd={(event) => {\n        if (event.canceled) {\n          setItems(snapshot);\n        }\n      }}\n    >\n      <div class=\"wrapper\">\n        <For each={columns}>\n          {(column, columnIndex) => (\n            <SortableColumn\n              id={column}\n              index={columnIndex()}\n              rows={items()[column]}\n            />\n          )}\n        </For>\n      </div>\n    </DragDropProvider>\n  );\n}\n"
  },
  {
    "path": "apps/stories-solid/stories/Sortable/SortableApp.tsx",
    "content": "import {createSignal, For} from 'solid-js';\nimport {DragDropProvider} from '@dnd-kit/solid';\nimport {useSortable} from '@dnd-kit/solid/sortable';\nimport {move} from '@dnd-kit/helpers';\n\nfunction Sortable(props: {id: number; index: number}) {\n  const {isDragging, ref} = useSortable({\n    get id() {\n      return props.id;\n    },\n    get index() {\n      return props.index;\n    },\n  });\n\n  return (\n    <li ref={ref} class=\"item\" data-shadow={isDragging() ? '' : undefined}>\n      {props.id}\n    </li>\n  );\n}\n\nexport default function App() {\n  const [items, setItems] = createSignal(createRange(100));\n\n  return (\n    <DragDropProvider\n      onDragEnd={(event) => {\n        setItems((items) => move(items, event));\n      }}\n    >\n      <ul class=\"list\">\n        <For each={items()}>\n          {(id, index) => <Sortable id={id} index={index()} />}\n        </For>\n      </ul>\n    </DragDropProvider>\n  );\n}\n\nfunction createRange(length: number) {\n  return Array.from({length}, (_, i) => i + 1);\n}\n"
  },
  {
    "path": "apps/stories-solid/stories/Sortable/SortableDragHandleApp.tsx",
    "content": "import {createSignal, For} from 'solid-js';\nimport {DragDropProvider} from '@dnd-kit/solid';\nimport {useSortable} from '@dnd-kit/solid/sortable';\nimport {move} from '@dnd-kit/helpers';\n\nfunction Sortable(props: {id: number; index: number}) {\n  const {isDragging, ref, handleRef} = useSortable({\n    get id() {\n      return props.id;\n    },\n    get index() {\n      return props.index;\n    },\n  });\n\n  return (\n    <li ref={ref} class=\"item\" data-shadow={isDragging() ? '' : undefined}>\n      {props.id}\n      <button ref={handleRef} class=\"handle\" />\n    </li>\n  );\n}\n\nexport default function App() {\n  const [items, setItems] = createSignal(createRange(100));\n\n  return (\n    <DragDropProvider\n      onDragEnd={(event) => {\n        setItems((items) => move(items, event));\n      }}\n    >\n      <ul class=\"list\">\n        <For each={items()}>\n          {(id, index) => <Sortable id={id} index={index()} />}\n        </For>\n      </ul>\n    </DragDropProvider>\n  );\n}\n\nfunction createRange(length: number) {\n  return Array.from({length}, (_, i) => i + 1);\n}\n"
  },
  {
    "path": "apps/stories-solid/stories/Sortable/Vertical/Vertical.stories.tsx",
    "content": "import type {Meta, StoryObj} from 'storybook-solidjs';\n\nimport App from '../SortableApp';\nimport sortableSource from '../SortableApp.tsx?raw';\nimport DragHandleApp from '../SortableDragHandleApp';\nimport sortableDragHandleSource from '../SortableDragHandleApp.tsx?raw';\nimport {\n  baseStyles,\n  handleStyles,\n  sortableStyles,\n} from '@dnd-kit/stories-shared/styles/sandbox';\n\nconst meta: Meta = {\n  title: 'Sortable/Vertical list',\n  component: App,\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const BasicSetup: Story = {\n  name: 'Basic setup',\n  parameters: {\n    codesandbox: {\n      files: {\n        'src/App.tsx': sortableSource,\n        'src/styles.css': [baseStyles, sortableStyles].join('\\n\\n'),\n      },\n    },\n  },\n};\n\nexport const WithDragHandle: Story = {\n  name: 'Drag handle',\n  render: () => <DragHandleApp />,\n  decorators: [\n    (Story) => (\n      <>\n        <style>{handleStyles}</style>\n        <Story />\n      </>\n    ),\n  ],\n  parameters: {\n    codesandbox: {\n      files: {\n        'src/App.tsx': sortableDragHandleSource,\n        'src/styles.css': [baseStyles, sortableStyles, handleStyles].join('\\n\\n'),\n      },\n    },\n  },\n};\n"
  },
  {
    "path": "apps/stories-solid/tests/draggable.spec.ts",
    "content": "import {draggableTests} from '../../stories-shared/tests/draggable.tests.ts';\n\ndraggableTests({\n  example: 'draggable-basic-setup--example',\n  dragHandle: 'draggable-drag-handles--example',\n});\n"
  },
  {
    "path": "apps/stories-solid/tests/droppable.spec.ts",
    "content": "import {droppableTests} from '../../stories-shared/tests/droppable.tests.ts';\n\ndroppableTests({\n  example: 'droppable-basic-setup--example',\n  multipleDropTargets: 'droppable-multiple-drop-targets--example',\n});\n"
  },
  {
    "path": "apps/stories-solid/tests/sortable-vertical.spec.ts",
    "content": "import {sortableVerticalTests} from '../../stories-shared/tests/sortable-vertical.tests.ts';\n\nsortableVerticalTests({\n  basicSetup: 'sortable-vertical-list--basic-setup',\n  withDragHandle: 'sortable-vertical-list--with-drag-handle',\n});\n"
  },
  {
    "path": "apps/stories-solid/tsconfig.json",
    "content": "{\n  \"extends\": \"../../config/typescript/solid.json\",\n  \"include\": [\".\"],\n  \"exclude\": [\"dist\", \"build\", \"node_modules\"]\n}\n"
  },
  {
    "path": "apps/stories-svelte/.storybook/main.ts",
    "content": "import {readFileSync} from 'fs';\nimport {join} from 'path';\n\nconst sharedPreviewHead = readFileSync(\n  join(__dirname, '..', '..', 'stories-shared', 'preview-head.html'),\n  'utf-8'\n);\n\nexport default {\n  previewHead: (head: string) => `${sharedPreviewHead}\\n${head}`,\n  stories: ['../stories/**/*.stories.ts'],\n\n  addons: [\n    '@storybook/addon-links',\n    '@vueless/storybook-dark-mode',\n    '@dnd-kit/storybook-addon-codesandbox',\n  ],\n\n  framework: '@storybook/svelte-vite',\n\n  async viteFinal(config: any) {\n    config.define = {\n      ...config.define,\n      'process.env': {},\n    };\n    config.optimizeDeps = {\n      ...config.optimizeDeps,\n      exclude: [...(config.optimizeDeps?.exclude || []), '@dnd-kit/*'],\n    };\n    return config;\n  },\n};\n"
  },
  {
    "path": "apps/stories-svelte/.storybook/manager.ts",
    "content": "import {addons} from 'storybook/manager-api';\n\nimport {theme} from './theme';\n\naddons.setConfig({\n  theme,\n  showPanel: false,\n});\n"
  },
  {
    "path": "apps/stories-svelte/.storybook/preview.ts",
    "content": "import '@dnd-kit/stories-shared/register';\nimport {withCodeSandbox} from '@dnd-kit/storybook-addon-codesandbox/decorator-dom';\n\nconst preview = {\n  decorators: [withCodeSandbox],\n  parameters: {\n    codesandbox: {\n      provider: 'stackblitz',\n      files: {\n        'index.html': [\n          '<!DOCTYPE html>',\n          '<html>',\n          '<head>',\n          '  <meta charset=\"UTF-8\" />',\n          '</head>',\n          '<body>',\n          '  <div id=\"app\"></div>',\n          '  <script type=\"module\" src=\"/src/main.js\"></script>',\n          '</body>',\n          '</html>',\n        ].join('\\n'),\n        'src/main.js': [\n          \"import './styles.css';\",\n          \"import {mount} from 'svelte';\",\n          \"import App from './App.svelte';\",\n          '',\n          \"mount(App, {target: document.getElementById('app')});\",\n        ].join('\\n'),\n        'vite.config.js': [\n          \"import {svelte} from '@sveltejs/vite-plugin-svelte';\",\n          \"import {defineConfig} from 'vite';\",\n          '',\n          'export default defineConfig({',\n          '  plugins: [svelte()],',\n          '});',\n        ].join('\\n'),\n        'package.json': JSON.stringify(\n          {\n            name: 'dnd-kit-sandbox',\n            private: true,\n            type: 'module',\n            scripts: {\n              dev: 'vite dev',\n              start: 'vite dev',\n            },\n            dependencies: {\n              '@dnd-kit/abstract': 'beta',\n              '@dnd-kit/dom': 'beta',\n              '@dnd-kit/svelte': 'beta',\n              '@dnd-kit/helpers': 'beta',\n              '@dnd-kit/collision': 'beta',\n              svelte: '^5.29.0',\n            },\n            devDependencies: {\n              vite: '^6.0.0',\n              '@sveltejs/vite-plugin-svelte': '^5.0.0',\n            },\n          },\n          null,\n          2\n        ),\n      },\n      mainFile: 'src/App.svelte',\n    },\n    darkMode: {\n      stylePreview: true,\n    },\n    options: {\n      storySort: {\n        order: [\n          'Draggable',\n          ['Basic setup', 'Drag handles', 'Drag overlay'],\n          'Droppable',\n          'Sortable',\n          ['Vertical list', 'Horizontal list', 'Grid', 'Multiple lists'],\n        ],\n      },\n    },\n  },\n};\n\nexport default preview;\n"
  },
  {
    "path": "apps/stories-svelte/.storybook/theme.ts",
    "content": "import {create} from 'storybook/theming/create';\nimport {default as brandImage} from './assets/dnd-kit-banner.svg';\n\nexport const theme = create({\n  base: 'light',\n  brandImage,\n  appBg: '#F9F9F9',\n});\n"
  },
  {
    "path": "apps/stories-svelte/package.json",
    "content": "{\n  \"name\": \"@dnd-kit/stories-svelte\",\n  \"version\": \"0.0.0\",\n  \"type\": \"module\",\n  \"private\": true,\n  \"scripts\": {\n    \"dev\": \"storybook dev -p 6010\",\n    \"build\": \"storybook build\",\n    \"clean\": \"rm -rf .turbo && rm -rf node_modules\",\n    \"test:e2e\": \"playwright test\",\n    \"test:e2e:ui\": \"playwright test --ui\"\n  },\n  \"dependencies\": {\n    \"@dnd-kit/abstract\": \"*\",\n    \"@dnd-kit/dom\": \"*\",\n    \"@dnd-kit/svelte\": \"*\",\n    \"@dnd-kit/helpers\": \"*\",\n    \"@dnd-kit/stories-shared\": \"*\",\n    \"@dnd-kit/storybook-addon-codesandbox\": \"*\",\n    \"svelte\": \"^5.29.0\"\n  },\n  \"devDependencies\": {\n    \"@playwright/test\": \"^1.58.2\",\n    \"@storybook/addon-links\": \"^9.0.15\",\n    \"@storybook/svelte-vite\": \"9.1.17\",\n    \"@sveltejs/vite-plugin-svelte\": \"^5.0.0\",\n    \"@vueless/storybook-dark-mode\": \"^9.0.6\",\n    \"storybook\": \"9.1.17\",\n    \"typescript\": \"^5.7.3\",\n    \"vite\": \"^6.0.0\"\n  }\n}\n"
  },
  {
    "path": "apps/stories-svelte/playwright.config.ts",
    "content": "import {defineConfig} from '@playwright/test';\n\nconst CI = !!process.env.CI;\n\nexport default defineConfig({\n  testDir: './tests',\n  timeout: 15_000,\n  expect: {\n    timeout: 5_000,\n  },\n  fullyParallel: true,\n  retries: CI ? 2 : 1,\n  reporter: CI ? 'html' : 'list',\n  use: {\n    baseURL: 'http://localhost:6010',\n    actionTimeout: 5_000,\n  },\n  projects: [\n    {\n      name: 'chromium',\n      use: {browserName: 'chromium'},\n    },\n  ],\n  webServer: {\n    command: 'npx http-server storybook-static --port 6010 --silent',\n    port: 6010,\n    reuseExistingServer: !CI,\n    timeout: 120_000,\n  },\n});\n"
  },
  {
    "path": "apps/stories-svelte/raw.d.ts",
    "content": "declare module '*.svelte?raw' {\n  const content: string;\n  export default content;\n}\n"
  },
  {
    "path": "apps/stories-svelte/stories/Draggable/DragHandles/DragHandles.stories.ts",
    "content": "import type {Meta, StoryObj} from '@storybook/svelte-vite';\n\nimport DragHandlesApp from './DragHandlesApp.svelte';\nimport dragHandlesSource from './DragHandlesApp.svelte?raw';\nimport draggableWithHandleSource from './DraggableWithHandle.svelte?raw';\nimport {\n  baseStyles,\n  draggableStyles,\n  handleStyles,\n} from '@dnd-kit/stories-shared/styles/sandbox';\n\nconst meta: Meta<typeof DragHandlesApp> = {\n  title: 'Draggable/Drag handles',\n  component: DragHandlesApp,\n};\n\nexport default meta;\ntype Story = StoryObj<typeof DragHandlesApp>;\n\nexport const Example: Story = {\n  parameters: {\n    codesandbox: {\n      files: {\n        'src/App.svelte': dragHandlesSource,\n        'src/DraggableWithHandle.svelte': draggableWithHandleSource,\n        'src/styles.css': [baseStyles, draggableStyles, handleStyles].join(\n          '\\n\\n'\n        ),\n      },\n    },\n  },\n};\n"
  },
  {
    "path": "apps/stories-svelte/stories/Draggable/DragHandles/DragHandlesApp.svelte",
    "content": "<script lang=\"ts\">\n  import {DragDropProvider} from '@dnd-kit/svelte';\n  import DraggableWithHandle from './DraggableWithHandle.svelte';\n</script>\n\n<DragDropProvider>\n  <DraggableWithHandle />\n</DragDropProvider>\n"
  },
  {
    "path": "apps/stories-svelte/stories/Draggable/DragHandles/DraggableWithHandle.svelte",
    "content": "<script lang=\"ts\">\n  import {createDraggable} from '@dnd-kit/svelte';\n\n  const draggable = createDraggable({id: 'draggable'});\n</script>\n\n<div\n  {@attach draggable.attach}\n  class=\"btn\"\n  data-shadow={draggable.isDragging ? 'true' : undefined}\n>\n  draggable\n  <button {@attach draggable.attachHandle} class=\"handle\" aria-label=\"Drag handle\"></button>\n</div>\n"
  },
  {
    "path": "apps/stories-svelte/stories/Draggable/DragOverlay/DragOverlay.stories.ts",
    "content": "import type {Meta, StoryObj} from '@storybook/svelte-vite';\n\nimport DragOverlayApp from './DragOverlayApp.svelte';\nimport dragOverlaySource from './DragOverlayApp.svelte?raw';\nimport draggableItemSource from './DraggableItem.svelte?raw';\nimport {\n  baseStyles,\n  draggableStyles,\n} from '@dnd-kit/stories-shared/styles/sandbox';\n\nconst meta: Meta<typeof DragOverlayApp> = {\n  title: 'Draggable/Drag overlay',\n  component: DragOverlayApp,\n};\n\nexport default meta;\ntype Story = StoryObj<typeof DragOverlayApp>;\n\nexport const Example: Story = {\n  parameters: {\n    codesandbox: {\n      files: {\n        'src/App.svelte': dragOverlaySource,\n        'src/DraggableItem.svelte': draggableItemSource,\n        'src/styles.css': [baseStyles, draggableStyles].join('\\n\\n'),\n      },\n    },\n  },\n};\n"
  },
  {
    "path": "apps/stories-svelte/stories/Draggable/DragOverlay/DragOverlayApp.svelte",
    "content": "<script lang=\"ts\">\n  import {DragDropProvider, DragOverlay} from '@dnd-kit/svelte';\n  import DraggableItem from './DraggableItem.svelte';\n</script>\n\n<DragDropProvider>\n  <div>\n    <DraggableItem />\n    <DragOverlay>\n      {#snippet children(source)}\n        <button class=\"btn\" data-shadow=\"true\">overlay</button>\n      {/snippet}\n    </DragOverlay>\n  </div>\n</DragDropProvider>\n"
  },
  {
    "path": "apps/stories-svelte/stories/Draggable/DragOverlay/DraggableItem.svelte",
    "content": "<script lang=\"ts\">\n  import {createDraggable} from '@dnd-kit/svelte';\n\n  const draggable = createDraggable({id: 'draggable'});\n</script>\n\n<button\n  {@attach draggable.attach}\n  class=\"btn\"\n  disabled={draggable.isDragging || undefined}\n>\n  draggable\n</button>\n"
  },
  {
    "path": "apps/stories-svelte/stories/Draggable/Draggable.stories.ts",
    "content": "import type {Meta, StoryObj} from '@storybook/svelte-vite';\n\nimport DraggableApp from './DraggableApp.svelte';\nimport draggableSource from './DraggableApp.svelte?raw';\nimport draggableComponentSource from './Draggable.svelte?raw';\nimport {\n  baseStyles,\n  draggableStyles,\n} from '@dnd-kit/stories-shared/styles/sandbox';\n\nconst meta: Meta<typeof DraggableApp> = {\n  title: 'Draggable/Basic setup',\n  component: DraggableApp,\n};\n\nexport default meta;\ntype Story = StoryObj<typeof DraggableApp>;\n\nexport const Example: Story = {\n  parameters: {\n    codesandbox: {\n      files: {\n        'src/App.svelte': draggableSource,\n        'src/Draggable.svelte': draggableComponentSource,\n        'src/styles.css': [baseStyles, draggableStyles].join('\\n\\n'),\n      },\n    },\n  },\n};\n"
  },
  {
    "path": "apps/stories-svelte/stories/Draggable/Draggable.svelte",
    "content": "<script lang=\"ts\">\n  import {createDraggable} from '@dnd-kit/svelte';\n\n  const draggable = createDraggable({id: 'draggable'});\n</script>\n\n<button {@attach draggable.attach} class=\"btn\">draggable</button>\n"
  },
  {
    "path": "apps/stories-svelte/stories/Draggable/DraggableApp.svelte",
    "content": "<script lang=\"ts\">\n  import {DragDropProvider} from '@dnd-kit/svelte';\n  import Draggable from './Draggable.svelte';\n</script>\n\n<DragDropProvider>\n  <Draggable />\n</DragDropProvider>\n"
  },
  {
    "path": "apps/stories-svelte/stories/Droppable/DraggableItem.svelte",
    "content": "<script lang=\"ts\">\n  import {createDraggable} from '@dnd-kit/svelte';\n\n  const draggable = createDraggable({id: 'draggable'});\n</script>\n\n<button {@attach draggable.attach} class=\"btn\">draggable</button>\n"
  },
  {
    "path": "apps/stories-svelte/stories/Droppable/Droppable.stories.ts",
    "content": "import type {Meta, StoryObj} from '@storybook/svelte-vite';\n\nimport DroppableApp from './DroppableApp.svelte';\nimport droppableSource from './DroppableApp.svelte?raw';\nimport draggableItemSource from './DraggableItem.svelte?raw';\nimport droppableZoneSource from './DroppableZone.svelte?raw';\nimport {\n  baseStyles,\n  draggableStyles,\n  droppableStyles,\n} from '@dnd-kit/stories-shared/styles/sandbox';\n\nconst meta: Meta<typeof DroppableApp> = {\n  title: 'Droppable/Basic setup',\n  component: DroppableApp,\n};\n\nexport default meta;\ntype Story = StoryObj<typeof DroppableApp>;\n\nexport const Example: Story = {\n  parameters: {\n    codesandbox: {\n      files: {\n        'src/App.svelte': droppableSource,\n        'src/DraggableItem.svelte': draggableItemSource,\n        'src/DroppableZone.svelte': droppableZoneSource,\n        'src/styles.css': [baseStyles, draggableStyles, droppableStyles].join(\n          '\\n\\n'\n        ),\n      },\n    },\n  },\n};\n"
  },
  {
    "path": "apps/stories-svelte/stories/Droppable/DroppableApp.svelte",
    "content": "<script lang=\"ts\">\n  import {DragDropProvider} from '@dnd-kit/svelte';\n  import DraggableItem from './DraggableItem.svelte';\n  import DroppableZone from './DroppableZone.svelte';\n\n  let parent = $state<string | undefined>(undefined);\n\n  function onDragEnd(event: any) {\n    if (event.canceled) return;\n    parent = event.operation.target?.id;\n  }\n</script>\n\n<DragDropProvider {onDragEnd}>\n  <section class=\"drop-layout\">\n    {#if parent == null}\n      <DraggableItem />\n    {/if}\n    <DroppableZone id=\"droppable\">\n      {#if parent === 'droppable'}\n        <DraggableItem />\n      {/if}\n    </DroppableZone>\n  </section>\n</DragDropProvider>\n"
  },
  {
    "path": "apps/stories-svelte/stories/Droppable/DroppableZone.svelte",
    "content": "<script lang=\"ts\">\n  import type {Snippet} from 'svelte';\n  import {createDroppable} from '@dnd-kit/svelte';\n\n  let {id, children}: {id: string; children?: Snippet} = $props();\n\n  const droppable = createDroppable({get id() { return id; }});\n</script>\n\n<div\n  {@attach droppable.attach}\n  class=\"droppable\"\n  class:active={droppable.isDropTarget}\n>\n  {@render children?.()}\n</div>\n"
  },
  {
    "path": "apps/stories-svelte/stories/Droppable/MultipleDroppable/MultipleDroppable.stories.ts",
    "content": "import type {Meta, StoryObj} from '@storybook/svelte-vite';\n\nimport MultipleDroppableApp from './MultipleDroppableApp.svelte';\nimport multipleDroppableSource from './MultipleDroppableApp.svelte?raw';\nimport draggableItemSource from '../DraggableItem.svelte?raw';\nimport droppableZoneSource from '../DroppableZone.svelte?raw';\nimport {\n  baseStyles,\n  draggableStyles,\n  droppableStyles,\n} from '@dnd-kit/stories-shared/styles/sandbox';\n\nconst meta: Meta<typeof MultipleDroppableApp> = {\n  title: 'Droppable/Multiple drop targets',\n  component: MultipleDroppableApp,\n};\n\nexport default meta;\ntype Story = StoryObj<typeof MultipleDroppableApp>;\n\nexport const Example: Story = {\n  parameters: {\n    codesandbox: {\n      files: {\n        'src/App.svelte': multipleDroppableSource.replace(\n          /from '\\.\\.\\/(\\w+\\.svelte)'/g,\n          \"from './$1'\"\n        ),\n        'src/DraggableItem.svelte': draggableItemSource,\n        'src/DroppableZone.svelte': droppableZoneSource,\n        'src/styles.css': [baseStyles, draggableStyles, droppableStyles].join(\n          '\\n\\n'\n        ),\n      },\n    },\n  },\n};\n"
  },
  {
    "path": "apps/stories-svelte/stories/Droppable/MultipleDroppable/MultipleDroppableApp.svelte",
    "content": "<script lang=\"ts\">\n  import {DragDropProvider} from '@dnd-kit/svelte';\n  import DraggableItem from '../DraggableItem.svelte';\n  import DroppableZone from '../DroppableZone.svelte';\n\n  let parent = $state<string | undefined>(undefined);\n  const droppables = ['A', 'B', 'C'];\n\n  function onDragEnd(event: any) {\n    if (event.canceled) return;\n    parent = event.operation.target?.id;\n  }\n</script>\n\n<DragDropProvider {onDragEnd}>\n  <div style=\"display: grid; grid-template-columns: 1fr 1fr; gap: 20px; max-width: 500px; margin: 0 auto;\">\n    <div style=\"display: flex; align-items: center; justify-content: center;\">\n      {#if parent == null}\n        <DraggableItem />\n      {/if}\n    </div>\n    {#each droppables as id (id)}\n      <DroppableZone {id}>\n        {#if parent === id}\n          <DraggableItem />\n        {/if}\n      </DroppableZone>\n    {/each}\n  </div>\n</DragDropProvider>\n"
  },
  {
    "path": "apps/stories-svelte/stories/Sortable/Grid/Grid.stories.ts",
    "content": "import type {Meta, StoryObj} from '@storybook/svelte-vite';\n\nimport GridSortableApp from './GridSortableApp.svelte';\nimport gridSortableSource from './GridSortableApp.svelte?raw';\nimport gridSortableItemSource from './GridSortableItem.svelte?raw';\nimport {\n  baseStyles,\n  sortableStyles,\n} from '@dnd-kit/stories-shared/styles/sandbox';\n\nconst meta: Meta = {\n  title: 'Sortable/Grid',\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const BasicSetup: Story = {\n  name: 'Basic setup',\n  render: () => ({Component: GridSortableApp}),\n  parameters: {\n    codesandbox: {\n      files: {\n        'src/App.svelte': gridSortableSource,\n        'src/GridSortableItem.svelte': gridSortableItemSource,\n        'src/styles.css': [baseStyles, sortableStyles].join('\\n\\n'),\n      },\n    },\n  },\n};\n"
  },
  {
    "path": "apps/stories-svelte/stories/Sortable/Grid/GridSortableApp.svelte",
    "content": "<script lang=\"ts\">\n  import {DragDropProvider} from '@dnd-kit/svelte';\n  import {move} from '@dnd-kit/helpers';\n  import GridSortableItem from './GridSortableItem.svelte';\n\n  let items = $state(Array.from({length: 20}, (_, i) => i + 1));\n\n  function onDragEnd(event: any) {\n    items = move(items, event);\n  }\n</script>\n\n<DragDropProvider {onDragEnd}>\n  <div style=\"display: grid; grid-template-columns: repeat(auto-fill, 150px); grid-auto-rows: 150px; grid-auto-flow: dense; gap: 18px; padding: 0 30px; max-width: 900px; margin-inline: auto; justify-content: center;\">\n    {#each items as id, index (id)}\n      <GridSortableItem {id} {index} />\n    {/each}\n  </div>\n</DragDropProvider>\n"
  },
  {
    "path": "apps/stories-svelte/stories/Sortable/Grid/GridSortableItem.svelte",
    "content": "<script lang=\"ts\">\n  import {createSortable} from '@dnd-kit/svelte/sortable';\n\n  let {id, index}: {id: number; index: number} = $props();\n\n  const sortable = createSortable({\n    get id() { return id; },\n    get index() { return index; },\n  });\n</script>\n\n<div\n  {@attach sortable.attach}\n  class=\"item\"\n  data-shadow={sortable.isDragging ? 'true' : undefined}\n  style=\"height: 100%; justify-content: center;\"\n>\n  {id}\n</div>\n"
  },
  {
    "path": "apps/stories-svelte/stories/Sortable/Horizontal/Horizontal.stories.ts",
    "content": "import type {Meta, StoryObj} from '@storybook/svelte-vite';\n\nimport HorizontalSortableApp from './HorizontalSortableApp.svelte';\nimport horizontalSortableSource from './HorizontalSortableApp.svelte?raw';\nimport horizontalSortableItemSource from './HorizontalSortableItem.svelte?raw';\nimport {\n  baseStyles,\n  sortableStyles,\n} from '@dnd-kit/stories-shared/styles/sandbox';\n\nconst meta: Meta = {\n  title: 'Sortable/Horizontal list',\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const BasicSetup: Story = {\n  name: 'Basic setup',\n  render: () => ({Component: HorizontalSortableApp}),\n  parameters: {\n    codesandbox: {\n      files: {\n        'src/App.svelte': horizontalSortableSource,\n        'src/HorizontalSortableItem.svelte': horizontalSortableItemSource,\n        'src/styles.css': [baseStyles, sortableStyles].join('\\n\\n'),\n      },\n    },\n  },\n};\n"
  },
  {
    "path": "apps/stories-svelte/stories/Sortable/Horizontal/HorizontalSortableApp.svelte",
    "content": "<script lang=\"ts\">\n  import {DragDropProvider} from '@dnd-kit/svelte';\n  import {move} from '@dnd-kit/helpers';\n  import HorizontalSortableItem from './HorizontalSortableItem.svelte';\n\n  let items = $state(Array.from({length: 10}, (_, i) => i + 1));\n\n  function onDragEnd(event: any) {\n    items = move(items, event);\n  }\n</script>\n\n<DragDropProvider {onDragEnd}>\n  <div style=\"display: inline-flex; flex-direction: row; align-items: stretch; height: 180px; gap: 18px; padding: 0 30px;\">\n    {#each items as id, index (id)}\n      <HorizontalSortableItem {id} {index} />\n    {/each}\n  </div>\n</DragDropProvider>\n"
  },
  {
    "path": "apps/stories-svelte/stories/Sortable/Horizontal/HorizontalSortableItem.svelte",
    "content": "<script lang=\"ts\">\n  import {createSortable} from '@dnd-kit/svelte/sortable';\n\n  let {id, index}: {id: number; index: number} = $props();\n\n  const sortable = createSortable({\n    get id() { return id; },\n    get index() { return index; },\n  });\n</script>\n\n<div\n  {@attach sortable.attach}\n  class=\"item\"\n  data-shadow={sortable.isDragging ? 'true' : undefined}\n  style=\"aspect-ratio: 1; justify-content: center;\"\n>\n  {id}\n</div>\n"
  },
  {
    "path": "apps/stories-svelte/stories/Sortable/MultipleLists/MultipleLists.stories.ts",
    "content": "import type {Meta, StoryObj} from '@storybook/svelte-vite';\n\nimport MultipleListsApp from './MultipleListsApp.svelte';\nimport multipleListsSource from './MultipleListsApp.svelte?raw';\nimport sortableColumnSource from './SortableColumn.svelte?raw';\nimport sortableItemSource from './SortableItem.svelte?raw';\nimport {\n  baseStyles,\n  sortableStyles,\n  multipleListsStyles,\n} from '@dnd-kit/stories-shared/styles/sandbox';\n\nconst styles = [baseStyles, sortableStyles, multipleListsStyles].join('\\n\\n');\n\nconst meta: Meta<typeof MultipleListsApp> = {\n  title: 'Sortable/Multiple lists',\n  component: MultipleListsApp,\n};\n\nexport default meta;\ntype Story = StoryObj<typeof MultipleListsApp>;\n\nexport const BasicSetup: Story = {\n  name: 'Basic setup',\n  parameters: {\n    codesandbox: {\n      files: {\n        'src/App.svelte': multipleListsSource,\n        'src/SortableColumn.svelte': sortableColumnSource,\n        'src/SortableItem.svelte': sortableItemSource,\n        'src/styles.css': styles,\n      },\n    },\n  },\n};\n"
  },
  {
    "path": "apps/stories-svelte/stories/Sortable/MultipleLists/MultipleListsApp.svelte",
    "content": "<script lang=\"ts\">\n  import {DragDropProvider, PointerSensor, KeyboardSensor} from '@dnd-kit/svelte';\n  import {defaultPreset} from '@dnd-kit/dom';\n  import {move} from '@dnd-kit/helpers';\n\n  import SortableColumn from './SortableColumn.svelte';\n\n  function createRange(length: number) {\n    return Array.from({length}, (_, i) => i + 1);\n  }\n\n  const ITEM_COUNT = 6;\n\n  const COLORS: Record<string, string> = {\n    A: '#7193f1',\n    B: '#FF851B',\n    C: '#2ECC40',\n    D: '#ff3680',\n  };\n\n  const sensors = [\n    PointerSensor.configure({\n      activatorElements(source) {\n        return [source.element, source.handle];\n      },\n    }),\n    KeyboardSensor,\n  ];\n\n  const initialItems: Record<string, string[]> = {\n    A: createRange(ITEM_COUNT).map((id) => `A${id}`),\n    B: createRange(ITEM_COUNT).map((id) => `B${id}`),\n    C: createRange(ITEM_COUNT).map((id) => `C${id}`),\n    D: [],\n  };\n\n  let items = $state<Record<string, string[]>>(initialItems);\n\n  const columns = Object.keys(initialItems);\n  let snapshot = $state(structuredClone(initialItems));\n\n  function onDragStart() {\n    snapshot = structuredClone(items);\n  }\n\n  function onDragOver(event: any) {\n    const {source} = event.operation;\n    if (source && source.type === 'column') return;\n    items = move(items, event);\n  }\n\n  function onDragEnd(event: any) {\n    if (event.canceled) {\n      items = snapshot;\n    }\n  }\n</script>\n\n<DragDropProvider\n  plugins={defaultPreset.plugins}\n  {sensors}\n  {onDragStart}\n  {onDragOver}\n  {onDragEnd}\n>\n  <div class=\"wrapper\">\n    {#each columns as column, columnIndex (column)}\n      <SortableColumn\n        id={column}\n        index={columnIndex}\n        rows={items[column]}\n        colors={COLORS}\n      />\n    {/each}\n  </div>\n</DragDropProvider>\n"
  },
  {
    "path": "apps/stories-svelte/stories/Sortable/MultipleLists/SortableColumn.svelte",
    "content": "<script lang=\"ts\">\n  import {CollisionPriority} from '@dnd-kit/abstract';\n  import {createSortable} from '@dnd-kit/svelte/sortable';\n\n  import SortableItem from './SortableItem.svelte';\n\n  let {\n    id,\n    index,\n    rows,\n    colors,\n  }: {\n    id: string;\n    index: number;\n    rows: string[];\n    colors: Record<string, string>;\n  } = $props();\n\n  const sortable = createSortable({\n    get id() { return id; },\n    get index() { return index; },\n    accept: ['column', 'item'],\n    collisionPriority: CollisionPriority.Low,\n    type: 'column',\n  });\n</script>\n\n<div\n  {@attach sortable.attach}\n  class=\"container\"\n  data-shadow={sortable.isDragging ? 'true' : undefined}\n>\n  <h2>\n    {id}\n    <button {@attach sortable.attachHandle} class=\"handle\" aria-label=\"Drag handle\"></button>\n  </h2>\n  <ul>\n    {#each rows as itemId, itemIndex (itemId)}\n      <SortableItem\n        id={itemId}\n        column={id}\n        index={itemIndex}\n        accentColor={colors[id]}\n      />\n    {/each}\n  </ul>\n</div>\n"
  },
  {
    "path": "apps/stories-svelte/stories/Sortable/MultipleLists/SortableItem.svelte",
    "content": "<script lang=\"ts\">\n  import {createSortable} from '@dnd-kit/svelte/sortable';\n\n  let {\n    id,\n    column,\n    index,\n    accentColor,\n  }: {\n    id: string;\n    column: string;\n    index: number;\n    accentColor: string;\n  } = $props();\n\n  const sortable = createSortable({\n    get id() { return id; },\n    get index() { return index; },\n    get group() { return column; },\n    accept: 'item',\n    type: 'item',\n    feedback: 'clone',\n    get data() { return {group: column}; },\n  });\n</script>\n\n<li\n  {@attach sortable.attach}\n  class=\"item\"\n  data-shadow={sortable.isDragging ? 'true' : undefined}\n  data-accent-color={column}\n  style:--accent-color={accentColor}\n>\n  {id}\n  <button {@attach sortable.attachHandle} class=\"handle\" aria-label=\"Drag handle\"></button>\n</li>\n"
  },
  {
    "path": "apps/stories-svelte/stories/Sortable/SortableApp.svelte",
    "content": "<script lang=\"ts\">\n  import {DragDropProvider} from '@dnd-kit/svelte';\n  import {move} from '@dnd-kit/helpers';\n  import SortableItem from './SortableItem.svelte';\n\n  let items = $state(Array.from({length: 100}, (_, i) => i + 1));\n\n  function onDragEnd(event: any) {\n    items = move(items, event);\n  }\n</script>\n\n<DragDropProvider {onDragEnd}>\n  <ul class=\"list\">\n    {#each items as id, index (id)}\n      <SortableItem {id} {index} />\n    {/each}\n  </ul>\n</DragDropProvider>\n"
  },
  {
    "path": "apps/stories-svelte/stories/Sortable/SortableDragHandleApp.svelte",
    "content": "<script lang=\"ts\">\n  import {DragDropProvider} from '@dnd-kit/svelte';\n  import {move} from '@dnd-kit/helpers';\n  import SortableItemWithHandle from './SortableItemWithHandle.svelte';\n\n  let items = $state(Array.from({length: 100}, (_, i) => i + 1));\n\n  function onDragEnd(event: any) {\n    items = move(items, event);\n  }\n</script>\n\n<DragDropProvider {onDragEnd}>\n  <ul class=\"list\">\n    {#each items as id, index (id)}\n      <SortableItemWithHandle {id} {index} />\n    {/each}\n  </ul>\n</DragDropProvider>\n"
  },
  {
    "path": "apps/stories-svelte/stories/Sortable/SortableItem.svelte",
    "content": "<script lang=\"ts\">\n  import {createSortable} from '@dnd-kit/svelte/sortable';\n\n  let {id, index}: {id: number; index: number} = $props();\n\n  const sortable = createSortable({\n    get id() { return id; },\n    get index() { return index; },\n  });\n</script>\n\n<li\n  {@attach sortable.attach}\n  class=\"item\"\n  data-shadow={sortable.isDragging ? 'true' : undefined}\n>\n  {id}\n</li>\n"
  },
  {
    "path": "apps/stories-svelte/stories/Sortable/SortableItemWithHandle.svelte",
    "content": "<script lang=\"ts\">\n  import {createSortable} from '@dnd-kit/svelte/sortable';\n\n  let {id, index}: {id: number; index: number} = $props();\n\n  const sortable = createSortable({\n    get id() { return id; },\n    get index() { return index; },\n  });\n</script>\n\n<li\n  {@attach sortable.attach}\n  class=\"item\"\n  data-shadow={sortable.isDragging ? 'true' : undefined}\n>\n  {id}\n  <button {@attach sortable.attachHandle} class=\"handle\" aria-label=\"Drag handle\"></button>\n</li>\n"
  },
  {
    "path": "apps/stories-svelte/stories/Sortable/Vertical/Vertical.stories.ts",
    "content": "import type {Meta, StoryObj} from '@storybook/svelte-vite';\n\nimport SortableApp from '../SortableApp.svelte';\nimport sortableSource from '../SortableApp.svelte?raw';\nimport sortableItemSource from '../SortableItem.svelte?raw';\nimport SortableDragHandleApp from '../SortableDragHandleApp.svelte';\nimport sortableDragHandleSource from '../SortableDragHandleApp.svelte?raw';\nimport sortableItemWithHandleSource from '../SortableItemWithHandle.svelte?raw';\nimport {\n  baseStyles,\n  handleStyles,\n  sortableStyles,\n} from '@dnd-kit/stories-shared/styles/sandbox';\n\nconst meta: Meta = {\n  title: 'Sortable/Vertical list',\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const BasicSetup: Story = {\n  name: 'Basic setup',\n  render: () => ({Component: SortableApp}),\n  parameters: {\n    codesandbox: {\n      files: {\n        'src/App.svelte': sortableSource,\n        'src/SortableItem.svelte': sortableItemSource,\n        'src/styles.css': [baseStyles, sortableStyles].join('\\n\\n'),\n      },\n    },\n  },\n};\n\nexport const WithDragHandle: Story = {\n  name: 'Drag handle',\n  render: () => ({Component: SortableDragHandleApp}),\n  parameters: {\n    codesandbox: {\n      files: {\n        'src/App.svelte': sortableDragHandleSource,\n        'src/SortableItemWithHandle.svelte': sortableItemWithHandleSource,\n        'src/styles.css': [baseStyles, sortableStyles, handleStyles].join(\n          '\\n\\n'\n        ),\n      },\n    },\n  },\n};\n"
  },
  {
    "path": "apps/stories-svelte/tests/draggable.spec.ts",
    "content": "import {draggableTests} from '../../stories-shared/tests/draggable.tests.ts';\n\ndraggableTests({\n  example: 'draggable-basic-setup--example',\n  dragHandle: 'draggable-drag-handles--example',\n});\n"
  },
  {
    "path": "apps/stories-svelte/tests/droppable.spec.ts",
    "content": "import {droppableTests} from '../../stories-shared/tests/droppable.tests.ts';\n\ndroppableTests({\n  example: 'droppable-basic-setup--example',\n  multipleDropTargets: 'droppable-multiple-drop-targets--example',\n});\n"
  },
  {
    "path": "apps/stories-svelte/tests/sortable-vertical.spec.ts",
    "content": "import {sortableVerticalTests} from '../../stories-shared/tests/sortable-vertical.tests.ts';\n\nsortableVerticalTests({\n  basicSetup: 'sortable-vertical-list--basic-setup',\n  withDragHandle: 'sortable-vertical-list--with-drag-handle',\n});\n"
  },
  {
    "path": "apps/stories-svelte/vite.config.ts",
    "content": "import {defineConfig} from 'vite';\nimport {svelte} from '@sveltejs/vite-plugin-svelte';\n\nexport default defineConfig({\n  plugins: [\n    svelte(),\n  ],\n});\n"
  },
  {
    "path": "apps/stories-vanilla/.storybook/main.ts",
    "content": "import {readFileSync} from 'fs';\nimport {dirname, join} from 'path';\nimport {mergeConfig} from 'vite';\n\nconst sharedPreviewHead = readFileSync(\n  join(__dirname, '..', '..', 'stories-shared', 'preview-head.html'),\n  'utf-8'\n);\n\nexport default {\n  previewHead: (head: string) => `${sharedPreviewHead}\\n${head}`,\n  stories: ['../stories/**/*.stories.ts'],\n\n  addons: [\n    getAbsolutePath('@storybook/addon-links'),\n    getAbsolutePath('@vueless/storybook-dark-mode'),\n    getAbsolutePath('@dnd-kit/storybook-addon-codesandbox'),\n  ],\n\n  framework: {\n    name: getAbsolutePath('@storybook/html-vite'),\n    options: {},\n  },\n\n  async viteFinal(config) {\n    return mergeConfig(config, {\n      define: {\n        'process.env': {},\n      },\n      optimizeDeps: {\n        exclude: ['@dnd-kit/*'],\n      },\n    });\n  },\n};\n\nfunction getAbsolutePath(value) {\n  return dirname(require.resolve(join(value, 'package.json')));\n}\n"
  },
  {
    "path": "apps/stories-vanilla/.storybook/manager-head.html",
    "content": "<link\n  rel=\"apple-touch-icon\"\n  sizes=\"180x180\"\n  href=\"/apple-touch-icon.png\"\n/>\n<link\n  rel=\"icon\"\n  type=\"image/png\"\n  sizes=\"32x32\"\n  href=\"/favicon-32x32.png\"\n/>\n<link\n  rel=\"icon\"\n  type=\"image/png\"\n  sizes=\"16x16\"\n  href=\"/favicon-16x16.png\"\n/>\n<link rel=\"shortcut icon\" href=\"/favicon.ico\">\n<style>\n  img[src*=\"dnd-kit-banner\"] {\n    width: 100%;\n    max-width: 200px;\n    margin-bottom: 10px;\n  }\n</style>\n"
  },
  {
    "path": "apps/stories-vanilla/.storybook/manager.ts",
    "content": "import {addons} from 'storybook/manager-api';\n\nimport {theme} from './theme';\n\naddons.setConfig({\n  theme,\n  showPanel: false,\n});\n"
  },
  {
    "path": "apps/stories-vanilla/.storybook/preview.ts",
    "content": "import '@dnd-kit/stories-shared/register';\nimport {withCodeSandbox} from '@dnd-kit/storybook-addon-codesandbox/decorator-dom';\n\nconst preview = {\n  decorators: [withCodeSandbox],\n  parameters: {\n    codesandbox: {\n      dependencies: {\n        '@dnd-kit/abstract': 'beta',\n        '@dnd-kit/dom': 'beta',\n        '@dnd-kit/helpers': 'beta',\n        '@dnd-kit/collision': 'beta',\n      },\n      entry: [\n        \"import './styles.css';\",\n        \"import App from './App';\",\n        \"\",\n        \"App();\",\n      ].join('\\n'),\n      mainFile: 'src/App.ts',\n    },\n    darkMode: {\n      stylePreview: true,\n    },\n    options: {\n      storySort: {\n        order: [\n          'Draggable',\n          [\n            'Basic setup',\n            'Drag handle',\n          ],\n          'Droppable',\n          'Sortable',\n          [\n            'Vertical list',\n            'Horizontal list',\n            'Grid',\n            'Multiple lists',\n          ],\n        ],\n      },\n    },\n  },\n};\n\nexport default preview;\n"
  },
  {
    "path": "apps/stories-vanilla/.storybook/theme.ts",
    "content": "import {create} from 'storybook/theming/create';\nimport {default as brandImage} from './assets/dnd-kit-banner.svg';\n\nexport const theme = create({\n  base: 'light',\n  brandImage,\n  appBg: '#F9F9F9',\n});\n"
  },
  {
    "path": "apps/stories-vanilla/package.json",
    "content": "{\n  \"name\": \"@dnd-kit/stories-vanilla\",\n  \"version\": \"0.0.0\",\n  \"type\": \"module\",\n  \"private\": true,\n  \"scripts\": {\n    \"dev\": \"storybook dev -p 6007\",\n    \"build\": \"storybook build\",\n    \"clean\": \"rm -rf .turbo && rm -rf node_modules\"\n  },\n  \"dependencies\": {\n    \"@dnd-kit/abstract\": \"*\",\n    \"@dnd-kit/dom\": \"*\",\n    \"@dnd-kit/helpers\": \"*\",\n    \"@dnd-kit/stories-shared\": \"*\",\n    \"@dnd-kit/storybook-addon-codesandbox\": \"*\"\n  },\n  \"devDependencies\": {\n    \"@storybook/addon-links\": \"^9.0.15\",\n    \"@storybook/html-vite\": \"^9.0.15\",\n    \"@vueless/storybook-dark-mode\": \"^9.0.6\",\n    \"storybook\": \"^9.0.15\",\n    \"typescript\": \"^5.7.3\",\n    \"vite\": \"^6.0.0\"\n  }\n}\n"
  },
  {
    "path": "apps/stories-vanilla/raw.d.ts",
    "content": "declare module '*.ts?raw' {\n  const content: string;\n  export default content;\n}\n\ndeclare module '*.js?raw' {\n  const content: string;\n  export default content;\n}\n"
  },
  {
    "path": "apps/stories-vanilla/stories/Draggable/DragHandle/DragHandle.stories.ts",
    "content": "import type {Meta, StoryObj} from '@storybook/html-vite';\n\nimport App from './DragHandleApp.ts';\nimport dragHandleSource from './DragHandleApp.ts?raw';\nimport {baseStyles, draggableStyles, handleStyles} from '@dnd-kit/stories-shared/styles/sandbox';\n\nconst meta: Meta = {\n  title: 'Draggable/Drag handle',\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const Example: Story = {\n  render: () => App(),\n  parameters: {\n    codesandbox: {\n      files: {\n        'src/App.ts': dragHandleSource,\n        'src/styles.css': [baseStyles, draggableStyles, handleStyles].join('\\n\\n'),\n      },\n    },\n  },\n};\n"
  },
  {
    "path": "apps/stories-vanilla/stories/Draggable/DragHandle/DragHandleApp.ts",
    "content": "import {DragDropManager, Draggable} from '@dnd-kit/dom';\n\nexport default function App() {\n  const root = document.createElement('div');\n\n  const button = document.createElement('div');\n  button.className = 'btn';\n  button.append('draggable');\n\n  const handle = document.createElement('button');\n  handle.className = 'handle';\n  button.appendChild(handle);\n\n  root.appendChild(button);\n\n  const manager = new DragDropManager();\n\n  new Draggable(\n    {\n      id: 'draggable',\n      element: button,\n      handle,\n    },\n    manager\n  );\n\n  return root;\n}\n"
  },
  {
    "path": "apps/stories-vanilla/stories/Draggable/Draggable.stories.ts",
    "content": "import type {Meta, StoryObj} from '@storybook/html-vite';\n\nimport App from './DraggableApp.ts';\nimport draggableSource from './DraggableApp.ts?raw';\nimport {baseStyles, draggableStyles} from '@dnd-kit/stories-shared/styles/sandbox';\n\nconst meta: Meta = {\n  title: 'Draggable/Basic setup',\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const Example: Story = {\n  render: () => App(),\n  parameters: {\n    codesandbox: {\n      files: {\n        'src/App.ts': draggableSource,\n        'src/styles.css': [baseStyles, draggableStyles].join('\\n\\n'),\n      },\n    },\n  },\n};\n"
  },
  {
    "path": "apps/stories-vanilla/stories/Draggable/DraggableApp.ts",
    "content": "import {DragDropManager, Draggable} from '@dnd-kit/dom';\n\nexport default function App() {\n  const root = document.createElement('div');\n\n  const button = document.createElement('button');\n  button.className = 'btn';\n  button.textContent = 'draggable';\n  root.appendChild(button);\n\n  const manager = new DragDropManager();\n  new Draggable({id: 'draggable', element: button}, manager);\n\n  return root;\n}\n"
  },
  {
    "path": "apps/stories-vanilla/stories/Droppable/Droppable.stories.ts",
    "content": "import type {Meta, StoryObj} from '@storybook/html-vite';\n\nimport App from './DroppableApp.ts';\nimport droppableSource from './DroppableApp.ts?raw';\nimport {\n  baseStyles,\n  draggableStyles,\n  droppableStyles,\n} from '@dnd-kit/stories-shared/styles/sandbox';\n\nconst meta: Meta = {\n  title: 'Droppable/Basic setup',\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const Example: Story = {\n  render: () => App(),\n  parameters: {\n    codesandbox: {\n      files: {\n        'src/App.ts': droppableSource,\n        'src/styles.css': [baseStyles, draggableStyles, droppableStyles].join(\n          '\\n\\n'\n        ),\n      },\n    },\n  },\n};\n"
  },
  {
    "path": "apps/stories-vanilla/stories/Droppable/DroppableApp.ts",
    "content": "import {DragDropManager, Draggable, Droppable} from '@dnd-kit/dom';\n\nexport default function App() {\n  const section = document.createElement('section');\n  section.className = 'drop-layout';\n\n  const button = document.createElement('button');\n  button.className = 'btn';\n  button.textContent = 'draggable';\n\n  const dropzone = document.createElement('div');\n  dropzone.className = 'droppable';\n\n  section.append(button, dropzone);\n\n  const manager = new DragDropManager();\n\n  const draggable = new Draggable({id: 'draggable', element: button}, manager);\n\n  const droppable = new Droppable(\n    {\n      id: 'droppable',\n      element: dropzone,\n      effects: () => [\n        () => {\n          if (droppable.isDropTarget) {\n            dropzone.classList.add('active');\n            return () => dropzone.classList.remove('active');\n          }\n        },\n      ],\n    },\n    manager\n  );\n\n  manager.monitor.addEventListener('dragend', (event) => {\n    if (event.canceled) return;\n\n    const isInside = dropzone.contains(button);\n\n    if (event.operation.target?.id === 'droppable') {\n      if (!isInside) dropzone.appendChild(button);\n    } else if (isInside) {\n      section.prepend(button);\n    }\n  });\n\n  return section;\n}\n"
  },
  {
    "path": "apps/stories-vanilla/stories/Droppable/MultipleDroppable/MultipleDroppable.stories.ts",
    "content": "import type {Meta, StoryObj} from '@storybook/html-vite';\n\nimport App from './MultipleDroppableApp.ts';\nimport multipleDroppableSource from './MultipleDroppableApp.ts?raw';\nimport {\n  baseStyles,\n  draggableStyles,\n  droppableStyles,\n} from '@dnd-kit/stories-shared/styles/sandbox';\n\nconst meta: Meta = {\n  title: 'Droppable/Multiple drop targets',\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const Example: Story = {\n  render: () => App(),\n  parameters: {\n    codesandbox: {\n      files: {\n        'src/App.ts': multipleDroppableSource,\n        'src/styles.css': [baseStyles, draggableStyles, droppableStyles].join(\n          '\\n\\n'\n        ),\n      },\n    },\n  },\n};\n"
  },
  {
    "path": "apps/stories-vanilla/stories/Droppable/MultipleDroppable/MultipleDroppableApp.ts",
    "content": "import {DragDropManager, Draggable, Droppable} from '@dnd-kit/dom';\n\nexport default function App() {\n  const root = document.createElement('div');\n  root.style.display = 'grid';\n  root.style.gridTemplateColumns = '1fr 1fr';\n  root.style.gap = '20px';\n  root.style.maxWidth = '500px';\n  root.style.margin = '0 auto';\n\n  const buttonWrapper = document.createElement('div');\n  buttonWrapper.style.display = 'flex';\n  buttonWrapper.style.alignItems = 'center';\n  buttonWrapper.style.justifyContent = 'center';\n\n  const button = document.createElement('button');\n  button.className = 'btn';\n  button.textContent = 'draggable';\n\n  buttonWrapper.appendChild(button);\n  root.appendChild(buttonWrapper);\n\n  const manager = new DragDropManager();\n  const droppableIds = ['A', 'B', 'C'];\n  const dropzones: Record<string, HTMLElement> = {};\n\n  new Draggable({id: 'draggable', element: button}, manager);\n\n  for (const id of droppableIds) {\n    const dropzone = document.createElement('div');\n    dropzone.className = 'droppable';\n    dropzones[id] = dropzone;\n    root.appendChild(dropzone);\n\n    const droppable = new Droppable(\n      {\n        id,\n        element: dropzone,\n        effects: () => [\n          () => {\n            if (droppable.isDropTarget) {\n              dropzone.classList.add('active');\n              return () => dropzone.classList.remove('active');\n            }\n          },\n        ],\n      },\n      manager\n    );\n  }\n\n  manager.monitor.addEventListener('dragend', (event) => {\n    if (event.canceled) return;\n\n    const targetId = event.operation.target?.id as string;\n\n    // Find which dropzone currently contains the button\n    const currentParent = Object.entries(dropzones).find(([, el]) =>\n      el.contains(button)\n    );\n\n    if (targetId && dropzones[targetId]) {\n      if (!dropzones[targetId].contains(button)) {\n        dropzones[targetId].appendChild(button);\n      }\n    } else if (currentParent) {\n      buttonWrapper.appendChild(button);\n    }\n  });\n\n  return root;\n}\n"
  },
  {
    "path": "apps/stories-vanilla/stories/Sortable/Grid/Grid.stories.ts",
    "content": "import type {Meta, StoryObj} from '@storybook/html-vite';\n\nimport App from './GridSortableApp.ts';\nimport gridSortableSource from './GridSortableApp.ts?raw';\nimport {baseStyles, sortableStyles} from '@dnd-kit/stories-shared/styles/sandbox';\n\nconst meta: Meta = {\n  title: 'Sortable/Grid',\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const BasicSetup: Story = {\n  name: 'Basic setup',\n  render: () => App(),\n  parameters: {\n    codesandbox: {\n      files: {\n        'src/App.ts': gridSortableSource,\n        'src/styles.css': [baseStyles, sortableStyles].join('\\n\\n'),\n      },\n    },\n  },\n};\n"
  },
  {
    "path": "apps/stories-vanilla/stories/Sortable/Grid/GridSortableApp.ts",
    "content": "import {DragDropManager} from '@dnd-kit/dom';\nimport {Sortable} from '@dnd-kit/dom/sortable';\n\nexport default function App() {\n  const wrapper = document.createElement('div');\n  wrapper.style.display = 'grid';\n  wrapper.style.gridTemplateColumns = 'repeat(auto-fill, 150px)';\n  wrapper.style.gridAutoRows = '150px';\n  wrapper.style.gridAutoFlow = 'dense';\n  wrapper.style.gap = '18px';\n  wrapper.style.padding = '0 30px';\n  wrapper.style.maxWidth = '900px';\n  wrapper.style.marginInline = 'auto';\n  wrapper.style.justifyContent = 'center';\n\n  const manager = new DragDropManager();\n  const items = createRange(20);\n\n  for (const id of items) {\n    const element = document.createElement('div');\n    element.classList.add('item');\n    element.textContent = String(id);\n    element.style.height = '100%';\n    element.style.justifyContent = 'center';\n\n    wrapper.appendChild(element);\n\n    const sortable = new Sortable(\n      {\n        id,\n        element,\n        index: id - 1,\n        effects: () => [\n          () => {\n            if (sortable.isDragging) {\n              element.dataset.shadow = '';\n              return () => delete element.dataset.shadow;\n            }\n          },\n        ],\n      },\n      manager\n    );\n  }\n\n  return wrapper;\n}\n\nfunction createRange(length: number) {\n  return Array.from({length}, (_, i) => i + 1);\n}\n"
  },
  {
    "path": "apps/stories-vanilla/stories/Sortable/Horizontal/Horizontal.stories.ts",
    "content": "import type {Meta, StoryObj} from '@storybook/html-vite';\n\nimport App from './HorizontalSortableApp.ts';\nimport horizontalSortableSource from './HorizontalSortableApp.ts?raw';\nimport {baseStyles, sortableStyles} from '@dnd-kit/stories-shared/styles/sandbox';\n\nconst meta: Meta = {\n  title: 'Sortable/Horizontal list',\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const BasicSetup: Story = {\n  name: 'Basic setup',\n  render: () => App(),\n  parameters: {\n    codesandbox: {\n      files: {\n        'src/App.ts': horizontalSortableSource,\n        'src/styles.css': [baseStyles, sortableStyles].join('\\n\\n'),\n      },\n    },\n  },\n};\n"
  },
  {
    "path": "apps/stories-vanilla/stories/Sortable/Horizontal/HorizontalSortableApp.ts",
    "content": "import {DragDropManager} from '@dnd-kit/dom';\nimport {Sortable} from '@dnd-kit/dom/sortable';\n\nexport default function App() {\n  const wrapper = document.createElement('div');\n  wrapper.style.display = 'inline-flex';\n  wrapper.style.flexDirection = 'row';\n  wrapper.style.alignItems = 'stretch';\n  wrapper.style.height = '180px';\n  wrapper.style.gap = '18px';\n  wrapper.style.padding = '0 30px';\n\n  const manager = new DragDropManager();\n  const items = createRange(10);\n\n  for (const id of items) {\n    const element = document.createElement('div');\n    element.classList.add('item');\n    element.textContent = String(id);\n    element.style.aspectRatio = '1';\n    element.style.justifyContent = 'center';\n\n    wrapper.appendChild(element);\n\n    const sortable = new Sortable(\n      {\n        id,\n        element,\n        index: id - 1,\n        effects: () => [\n          () => {\n            if (sortable.isDragging) {\n              element.dataset.shadow = '';\n              return () => delete element.dataset.shadow;\n            }\n          },\n        ],\n      },\n      manager\n    );\n  }\n\n  return wrapper;\n}\n\nfunction createRange(length: number) {\n  return Array.from({length}, (_, i) => i + 1);\n}\n"
  },
  {
    "path": "apps/stories-vanilla/stories/Sortable/Sortable.stories.ts",
    "content": "import type {Meta, StoryObj} from '@storybook/html-vite';\n\nimport App from './SortableApp.ts';\nimport sortableSource from './SortableApp.ts?raw';\nimport {baseStyles, sortableStyles} from '@dnd-kit/stories-shared/styles/sandbox';\n\nconst meta: Meta = {\n  title: 'Sortable/Vertical list',\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const BasicSetup: Story = {\n  name: 'Basic setup',\n  render: () => App(),\n  parameters: {\n    codesandbox: {\n      files: {\n        'src/App.ts': sortableSource,\n        'src/styles.css': [baseStyles, sortableStyles].join('\\n\\n'),\n      },\n    },\n  },\n};\n"
  },
  {
    "path": "apps/stories-vanilla/stories/Sortable/SortableApp.ts",
    "content": "import {DragDropManager} from '@dnd-kit/dom';\nimport {Sortable} from '@dnd-kit/dom/sortable';\n\nexport default function App() {\n  const list = document.createElement('ul');\n  list.className = 'list';\n\n  const manager = new DragDropManager();\n  const items = createRange(100);\n\n  for (const id of items) {\n    const li = document.createElement('li');\n    li.className = 'item';\n    li.textContent = String(id);\n\n    list.appendChild(li);\n\n    const sortable = new Sortable(\n      {\n        id,\n        element: li,\n        index: id - 1,\n        effects: () => [\n          () => {\n            if (sortable.isDragging) {\n              li.dataset.shadow = '';\n              return () => delete li.dataset.shadow;\n            }\n          },\n        ],\n      },\n      manager\n    );\n  }\n\n  return list;\n}\n\nfunction createRange(length: number) {\n  return Array.from({length}, (_, i) => i + 1);\n}\n"
  },
  {
    "path": "apps/stories-vue/.storybook/main.ts",
    "content": "import {readFileSync} from 'fs';\nimport {dirname, join} from 'path';\nimport {mergeConfig} from 'vite';\nimport vue from '@vitejs/plugin-vue';\n\nconst sharedPreviewHead = readFileSync(\n  join(__dirname, '..', '..', 'stories-shared', 'preview-head.html'),\n  'utf-8'\n);\n\nexport default {\n  previewHead: (head: string) => `${sharedPreviewHead}\\n${head}`,\n  stories: ['../stories/**/*.stories.ts'],\n\n  addons: [\n    getAbsolutePath('@storybook/addon-links'),\n    getAbsolutePath('@vueless/storybook-dark-mode'),\n    getAbsolutePath('@dnd-kit/storybook-addon-codesandbox'),\n  ],\n\n  framework: {\n    name: getAbsolutePath('@storybook/vue3-vite'),\n    options: {},\n  },\n\n  async viteFinal(config) {\n    return mergeConfig(config, {\n      plugins: [\n        vue({\n          template: {\n            compilerOptions: {\n              isCustomElement: (tag) => tag.includes('-'),\n            },\n          },\n        }),\n      ],\n      define: {\n        'process.env': {},\n      },\n      optimizeDeps: {\n        exclude: ['@dnd-kit/*'],\n      },\n    });\n  },\n};\n\nfunction getAbsolutePath(value) {\n  return dirname(require.resolve(join(value, 'package.json')));\n}\n"
  },
  {
    "path": "apps/stories-vue/.storybook/manager-head.html",
    "content": "<link\n  rel=\"apple-touch-icon\"\n  sizes=\"180x180\"\n  href=\"/apple-touch-icon.png\"\n/>\n<link\n  rel=\"icon\"\n  type=\"image/png\"\n  sizes=\"32x32\"\n  href=\"/favicon-32x32.png\"\n/>\n<link\n  rel=\"icon\"\n  type=\"image/png\"\n  sizes=\"16x16\"\n  href=\"/favicon-16x16.png\"\n/>\n<link rel=\"shortcut icon\" href=\"/favicon.ico\">\n<style>\n  img[src*=\"dnd-kit-banner\"] {\n    width: 100%;\n    max-width: 200px;\n    margin-bottom: 10px;\n  }\n</style>\n"
  },
  {
    "path": "apps/stories-vue/.storybook/manager.ts",
    "content": "import {addons} from 'storybook/manager-api';\n\nimport {theme} from './theme';\n\naddons.setConfig({\n  theme,\n  showPanel: false,\n});\n"
  },
  {
    "path": "apps/stories-vue/.storybook/preview.ts",
    "content": "import '@dnd-kit/stories-shared/register';\nimport {withCodeSandbox} from '@dnd-kit/storybook-addon-codesandbox/decorator-dom';\n\nconst preview = {\n  decorators: [withCodeSandbox],\n  parameters: {\n    codesandbox: {\n      template: 'vue-cli',\n      files: {\n        'src/main.js': [\n          \"import {createApp} from 'vue';\",\n          \"import App from './App.vue';\",\n          \"import './styles.css';\",\n          \"\",\n          \"createApp(App).mount('#app');\",\n        ].join('\\n'),\n        'package.json': JSON.stringify(\n          {\n            name: 'dnd-kit-sandbox',\n            version: '0.1.0',\n            private: true,\n            main: '/src/main.js',\n            alias: {\n              vue: 'vue/dist/vue.esm-bundler.js',\n            },\n            scripts: {\n              serve: 'vue-cli-service serve',\n              build: 'vue-cli-service build',\n            },\n            dependencies: {\n              'core-js': '^3.26.1',\n              '@dnd-kit/abstract': 'beta',\n              '@dnd-kit/dom': 'beta',\n              '@dnd-kit/vue': 'beta',\n              '@dnd-kit/helpers': 'beta',\n              '@dnd-kit/collision': 'beta',\n              'vue': '^3.5.0',\n            },\n            devDependencies: {\n              '@vue/cli-plugin-babel': '^5.0.8',\n              '@vue/cli-plugin-typescript': '^5.0.8',\n              '@vue/cli-service': '^5.0.8',\n              'typescript': '^4.9.3',\n            },\n          },\n          null,\n          2\n        ),\n      },\n      mainFile: 'src/App.vue',\n    },\n    darkMode: {\n      stylePreview: true,\n    },\n    options: {\n      storySort: {\n        order: [\n          'Draggable',\n          [\n            'Basic setup',\n            'Drag handles',\n            'Drag overlay',\n          ],\n          'Droppable',\n          'Sortable',\n          [\n            'Vertical list',\n            'Horizontal list',\n            'Grid',\n            'Multiple lists',\n          ],\n        ],\n      },\n    },\n  },\n};\n\nexport default preview;\n"
  },
  {
    "path": "apps/stories-vue/.storybook/theme.ts",
    "content": "import {create} from 'storybook/theming/create';\nimport {default as brandImage} from './assets/dnd-kit-banner.svg';\n\nexport const theme = create({\n  base: 'light',\n  brandImage,\n  appBg: '#F9F9F9',\n});\n"
  },
  {
    "path": "apps/stories-vue/package.json",
    "content": "{\n  \"name\": \"@dnd-kit/stories-vue\",\n  \"version\": \"0.0.0\",\n  \"type\": \"module\",\n  \"private\": true,\n  \"scripts\": {\n    \"dev\": \"storybook dev -p 6008\",\n    \"build\": \"storybook build\",\n    \"clean\": \"rm -rf .turbo && rm -rf node_modules\",\n    \"test:e2e\": \"playwright test\",\n    \"test:e2e:ui\": \"playwright test --ui\"\n  },\n  \"dependencies\": {\n    \"@dnd-kit/abstract\": \"*\",\n    \"@dnd-kit/dom\": \"*\",\n    \"@dnd-kit/vue\": \"*\",\n    \"@dnd-kit/helpers\": \"*\",\n    \"@dnd-kit/stories-shared\": \"*\",\n    \"@dnd-kit/storybook-addon-codesandbox\": \"*\",\n    \"vue\": \"^3.5.0\"\n  },\n  \"devDependencies\": {\n    \"@playwright/test\": \"^1.58.2\",\n    \"@storybook/addon-links\": \"^9.0.15\",\n    \"@storybook/vue3-vite\": \"^9.0.15\",\n    \"@vitejs/plugin-vue\": \"^5.0.0\",\n    \"@vueless/storybook-dark-mode\": \"^9.0.6\",\n    \"storybook\": \"^9.0.15\",\n    \"typescript\": \"^5.7.3\",\n    \"vite\": \"^6.0.0\"\n  }\n}\n"
  },
  {
    "path": "apps/stories-vue/playwright.config.ts",
    "content": "import {defineConfig} from '@playwright/test';\n\nconst CI = !!process.env.CI;\n\nexport default defineConfig({\n  testDir: './tests',\n  timeout: 15_000,\n  expect: {\n    timeout: 5_000,\n  },\n  fullyParallel: true,\n  retries: CI ? 2 : 1,\n  reporter: CI ? 'html' : 'list',\n  use: {\n    baseURL: 'http://localhost:6008',\n    actionTimeout: 5_000,\n  },\n  projects: [\n    {\n      name: 'chromium',\n      use: {browserName: 'chromium'},\n    },\n  ],\n  webServer: {\n    command: 'npx http-server storybook-static --port 6008 --silent',\n    port: 6008,\n    reuseExistingServer: !CI,\n    timeout: 120_000,\n  },\n});\n"
  },
  {
    "path": "apps/stories-vue/raw.d.ts",
    "content": "declare module '*.vue?raw' {\n  const content: string;\n  export default content;\n}\n\ndeclare module '*.ts?raw' {\n  const content: string;\n  export default content;\n}\n"
  },
  {
    "path": "apps/stories-vue/stories/Draggable/DragHandles/DragHandles.stories.ts",
    "content": "import {h} from 'vue';\nimport type {Meta, StoryObj} from '@storybook/vue3-vite';\n\nimport DragHandlesApp from './DragHandlesApp.vue';\nimport dragHandlesSource from './DragHandlesApp.vue?raw';\nimport {\n  baseStyles,\n  draggableStyles,\n  handleStyles,\n} from '@dnd-kit/stories-shared/styles/sandbox';\n\nconst meta: Meta<typeof DragHandlesApp> = {\n  title: 'Draggable/Drag handles',\n  component: DragHandlesApp,\n};\n\nexport default meta;\ntype Story = StoryObj<typeof DragHandlesApp>;\n\nexport const Example: Story = {\n  decorators: [\n    (story) => ({\n      setup() {\n        return () =>\n          h('div', [\n            h('style', baseStyles),\n            h('style', draggableStyles),\n            h('style', handleStyles),\n            h(story()),\n          ]);\n      },\n    }),\n  ],\n  parameters: {\n    codesandbox: {\n      files: {\n        'src/App.vue': dragHandlesSource,\n        'src/styles.css': [baseStyles, draggableStyles, handleStyles].join(\n          '\\n\\n'\n        ),\n      },\n    },\n  },\n};\n"
  },
  {
    "path": "apps/stories-vue/stories/Draggable/DragHandles/DragHandlesApp.vue",
    "content": "<script setup lang=\"ts\">\nimport {ref} from 'vue';\nimport {DragDropProvider, useDraggable} from '@dnd-kit/vue';\n</script>\n\n<script lang=\"ts\">\nimport {defineComponent} from 'vue';\n\nconst Draggable = defineComponent({\n  setup() {\n    const element = ref<HTMLElement | null>(null);\n    const handle = ref<HTMLElement | null>(null);\n    const {isDragging} = useDraggable({id: 'draggable', element, handle});\n    return {element, handle, isDragging};\n  },\n  template: `\n    <div class=\"btn\" ref=\"element\" :data-shadow=\"isDragging || undefined\">\n      draggable\n      <button ref=\"handle\" class=\"handle\" />\n    </div>\n  `,\n});\n\nexport default defineComponent({components: {Draggable}});\n</script>\n\n<template>\n  <DragDropProvider>\n    <Draggable />\n  </DragDropProvider>\n</template>\n"
  },
  {
    "path": "apps/stories-vue/stories/Draggable/DragOverlay/DragOverlay.stories.ts",
    "content": "import {h} from 'vue';\nimport type {Meta, StoryObj} from '@storybook/vue3-vite';\n\nimport DragOverlayApp from './DragOverlayApp.vue';\nimport dragOverlaySource from './DragOverlayApp.vue?raw';\nimport {\n  baseStyles,\n  draggableStyles,\n} from '@dnd-kit/stories-shared/styles/sandbox';\n\nconst meta: Meta<typeof DragOverlayApp> = {\n  title: 'Draggable/Drag overlay',\n  component: DragOverlayApp,\n};\n\nexport default meta;\ntype Story = StoryObj<typeof DragOverlayApp>;\n\nexport const Example: Story = {\n  decorators: [\n    (story) => ({\n      setup() {\n        return () =>\n          h('div', [\n            h('style', baseStyles),\n            h('style', draggableStyles),\n            h(story()),\n          ]);\n      },\n    }),\n  ],\n  parameters: {\n    codesandbox: {\n      files: {\n        'src/App.vue': dragOverlaySource,\n        'src/styles.css': [baseStyles, draggableStyles].join('\\n\\n'),\n      },\n    },\n  },\n};\n"
  },
  {
    "path": "apps/stories-vue/stories/Draggable/DragOverlay/DragOverlayApp.vue",
    "content": "<script setup lang=\"ts\">\nimport {ref} from 'vue';\nimport {DragDropProvider, DragOverlay, useDraggable} from '@dnd-kit/vue';\n</script>\n\n<script lang=\"ts\">\nimport {defineComponent} from 'vue';\n\nconst Draggable = defineComponent({\n  setup() {\n    const element = ref<HTMLElement | null>(null);\n    const {isDragging} = useDraggable({id: 'draggable', element});\n    return {element, isDragging};\n  },\n  template: `\n    <button class=\"btn\" ref=\"element\" :disabled=\"isDragging || undefined\">\n      draggable\n    </button>\n  `,\n});\n\nexport default defineComponent({components: {Draggable, DragOverlay}});\n</script>\n\n<template>\n  <DragDropProvider>\n    <div>\n      <Draggable />\n      <DragOverlay>\n        <button class=\"btn\" data-shadow=\"true\">\n          overlay\n        </button>\n      </DragOverlay>\n    </div>\n  </DragDropProvider>\n</template>\n"
  },
  {
    "path": "apps/stories-vue/stories/Draggable/Draggable.stories.ts",
    "content": "import {h} from 'vue';\nimport type {Meta, StoryObj} from '@storybook/vue3-vite';\n\nimport DraggableApp from './DraggableApp.vue';\nimport draggableSource from './DraggableApp.vue?raw';\nimport {\n  baseStyles,\n  draggableStyles,\n} from '@dnd-kit/stories-shared/styles/sandbox';\n\nconst meta: Meta<typeof DraggableApp> = {\n  title: 'Draggable/Basic setup',\n  component: DraggableApp,\n};\n\nexport default meta;\ntype Story = StoryObj<typeof DraggableApp>;\n\nexport const Example: Story = {\n  decorators: [\n    (story) => ({\n      setup() {\n        return () =>\n          h('div', [\n            h('style', baseStyles),\n            h('style', draggableStyles),\n            h(story()),\n          ]);\n      },\n    }),\n  ],\n  parameters: {\n    codesandbox: {\n      files: {\n        'src/App.vue': draggableSource,\n        'src/styles.css': [baseStyles, draggableStyles].join('\\n\\n'),\n      },\n    },\n  },\n};\n"
  },
  {
    "path": "apps/stories-vue/stories/Draggable/DraggableApp.vue",
    "content": "<script setup lang=\"ts\">\nimport {ref} from 'vue';\nimport {DragDropProvider, useDraggable} from '@dnd-kit/vue';\n</script>\n\n<script lang=\"ts\">\nimport {defineComponent} from 'vue';\n\nconst Draggable = defineComponent({\n  setup() {\n    const element = ref<HTMLElement | null>(null);\n    useDraggable({id: 'draggable', element});\n    return {element};\n  },\n  template: `<button ref=\"element\" class=\"btn\">draggable</button>`,\n});\n\nexport default defineComponent({components: {Draggable}});\n</script>\n\n<template>\n  <DragDropProvider>\n    <Draggable />\n  </DragDropProvider>\n</template>\n"
  },
  {
    "path": "apps/stories-vue/stories/Droppable/Droppable.stories.ts",
    "content": "import type {Meta, StoryObj} from '@storybook/vue3-vite';\n\nimport DroppableApp from './DroppableApp.vue';\nimport droppableSource from './DroppableApp.vue?raw';\nimport {baseStyles, draggableStyles, droppableStyles} from '@dnd-kit/stories-shared/styles/sandbox';\n\nconst meta: Meta<typeof DroppableApp> = {\n  title: 'Droppable/Basic setup',\n  component: DroppableApp,\n};\n\nexport default meta;\ntype Story = StoryObj<typeof DroppableApp>;\n\nexport const Example: Story = {\n  parameters: {\n    codesandbox: {\n      files: {\n        'src/App.vue': droppableSource,\n        'src/styles.css': [baseStyles, draggableStyles, droppableStyles].join('\\n\\n'),\n      },\n    },\n  },\n};\n"
  },
  {
    "path": "apps/stories-vue/stories/Droppable/DroppableApp.vue",
    "content": "<script setup lang=\"ts\">\nimport {ref} from 'vue';\nimport {DragDropProvider, useDraggable, useDroppable} from '@dnd-kit/vue';\n\nconst parent = ref<string | undefined>(undefined);\n\nfunction onDragEnd(event: any) {\n  if (event.canceled) return;\n  parent.value = event.operation.target?.id;\n}\n</script>\n\n<script lang=\"ts\">\nimport {defineComponent} from 'vue';\n\nconst DraggableItem = defineComponent({\n  setup() {\n    const element = ref<HTMLElement | null>(null);\n    useDraggable({id: 'draggable', element});\n    return {element};\n  },\n  template: `<button ref=\"element\" class=\"btn\">draggable</button>`,\n});\n\nconst DroppableZone = defineComponent({\n  setup() {\n    const element = ref<HTMLElement | null>(null);\n    const {isDropTarget} = useDroppable({id: 'droppable', element});\n    return {element, isDropTarget};\n  },\n  template: `<div ref=\"element\" :class=\"['droppable', isDropTarget && 'active']\"><slot /></div>`,\n});\n\nexport default defineComponent({components: {DraggableItem, DroppableZone}});\n</script>\n\n<template>\n  <DragDropProvider @dragEnd=\"onDragEnd\">\n    <section class=\"drop-layout\">\n      <DraggableItem v-if=\"parent == null\" />\n      <DroppableZone>\n        <DraggableItem v-if=\"parent === 'droppable'\" />\n      </DroppableZone>\n    </section>\n  </DragDropProvider>\n</template>\n"
  },
  {
    "path": "apps/stories-vue/stories/Droppable/MultipleDroppable/MultipleDroppable.stories.ts",
    "content": "import type {Meta, StoryObj} from '@storybook/vue3-vite';\n\nimport MultipleDroppableApp from './MultipleDroppableApp.vue';\nimport multipleDroppableSource from './MultipleDroppableApp.vue?raw';\nimport {baseStyles, draggableStyles, droppableStyles} from '@dnd-kit/stories-shared/styles/sandbox';\n\nconst meta: Meta<typeof MultipleDroppableApp> = {\n  title: 'Droppable/Multiple drop targets',\n  component: MultipleDroppableApp,\n};\n\nexport default meta;\ntype Story = StoryObj<typeof MultipleDroppableApp>;\n\nexport const Example: Story = {\n  parameters: {\n    codesandbox: {\n      files: {\n        'src/App.vue': multipleDroppableSource,\n        'src/styles.css': [baseStyles, draggableStyles, droppableStyles].join('\\n\\n'),\n      },\n    },\n  },\n};\n"
  },
  {
    "path": "apps/stories-vue/stories/Droppable/MultipleDroppable/MultipleDroppableApp.vue",
    "content": "<script setup lang=\"ts\">\nimport {ref} from 'vue';\nimport {DragDropProvider} from '@dnd-kit/vue';\n\nconst parent = ref<string | undefined>(undefined);\nconst droppables = ['A', 'B', 'C'];\n\nfunction onDragEnd(event: any) {\n  if (event.canceled) return;\n  parent.value = event.operation.target?.id;\n}\n</script>\n\n<script lang=\"ts\">\nimport {defineComponent} from 'vue';\nimport {useDraggable, useDroppable} from '@dnd-kit/vue';\n\nconst DraggableItem = defineComponent({\n  setup() {\n    const element = ref<HTMLElement | null>(null);\n    useDraggable({id: 'draggable', element});\n    return {element};\n  },\n  template: `<button ref=\"element\" class=\"btn\">draggable</button>`,\n});\n\nconst DroppableZone = defineComponent({\n  props: {\n    id: {type: String, required: true},\n  },\n  setup(props) {\n    const element = ref<HTMLElement | null>(null);\n    const {isDropTarget} = useDroppable({id: props.id, element});\n    return {element, isDropTarget};\n  },\n  template: `<div ref=\"element\" :class=\"['droppable', isDropTarget && 'active']\"><slot /></div>`,\n});\n\nexport default defineComponent({components: {DraggableItem, DroppableZone}});\n</script>\n\n<template>\n  <DragDropProvider @dragEnd=\"onDragEnd\">\n    <div :style=\"{display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '20px', maxWidth: '500px', margin: '0 auto'}\">\n      <div :style=\"{display: 'flex', alignItems: 'center', justifyContent: 'center'}\">\n        <DraggableItem v-if=\"parent == null\" />\n      </div>\n      <DroppableZone v-for=\"id in droppables\" :key=\"id\" :id=\"id\">\n        <DraggableItem v-if=\"parent === id\" />\n      </DroppableZone>\n    </div>\n  </DragDropProvider>\n</template>\n"
  },
  {
    "path": "apps/stories-vue/stories/Sortable/Grid/Grid.stories.ts",
    "content": "import type {Meta, StoryObj} from '@storybook/vue3-vite';\n\nimport GridSortableApp from './GridSortableApp.vue';\nimport gridSortableSource from './GridSortableApp.vue?raw';\nimport {baseStyles, sortableStyles} from '@dnd-kit/stories-shared/styles/sandbox';\n\nconst meta: Meta = {\n  title: 'Sortable/Grid',\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const BasicSetup: Story = {\n  name: 'Basic setup',\n  render: () => ({components: {GridSortableApp}, template: '<GridSortableApp />'}),\n  parameters: {\n    codesandbox: {\n      files: {\n        'src/App.vue': gridSortableSource,\n        'src/styles.css': [baseStyles, sortableStyles].join('\\n\\n'),\n      },\n    },\n  },\n};\n"
  },
  {
    "path": "apps/stories-vue/stories/Sortable/Grid/GridSortableApp.vue",
    "content": "<script setup lang=\"ts\">\nimport {ref, computed} from 'vue';\nimport {DragDropProvider} from '@dnd-kit/vue';\nimport {useSortable} from '@dnd-kit/vue/sortable';\nimport {move} from '@dnd-kit/helpers';\n\nconst items = ref(Array.from({length: 20}, (_, i) => i + 1));\n\nfunction onDragEnd(event: any) {\n  items.value = move(items.value, event);\n}\n</script>\n\n<script lang=\"ts\">\nimport {defineComponent} from 'vue';\n\nconst SortableItem = defineComponent({\n  props: {\n    id: {type: Number, required: true},\n    index: {type: Number, required: true},\n  },\n  setup(props) {\n    const element = ref<HTMLElement | null>(null);\n    const {isDragging} = useSortable({\n      id: computed(() => props.id),\n      index: computed(() => props.index),\n      element,\n    });\n    return {element, isDragging};\n  },\n  template: `\n    <div ref=\"element\" class=\"item\" :data-shadow=\"isDragging || undefined\"\n      :style=\"{height: '100%', justifyContent: 'center'}\">\n      {{ id }}\n    </div>\n  `,\n});\n\nexport default defineComponent({components: {SortableItem}});\n</script>\n\n<template>\n  <DragDropProvider @dragEnd=\"onDragEnd\">\n    <div :style=\"{display: 'grid', gridTemplateColumns: 'repeat(auto-fill, 150px)', gridAutoRows: '150px', gridAutoFlow: 'dense', gap: '18px', padding: '0 30px', maxWidth: '900px', marginInline: 'auto', justifyContent: 'center'}\">\n      <SortableItem\n        v-for=\"(id, index) in items\"\n        :key=\"id\"\n        :id=\"id\"\n        :index=\"index\"\n      />\n    </div>\n  </DragDropProvider>\n</template>\n"
  },
  {
    "path": "apps/stories-vue/stories/Sortable/Horizontal/Horizontal.stories.ts",
    "content": "import type {Meta, StoryObj} from '@storybook/vue3-vite';\n\nimport HorizontalSortableApp from './HorizontalSortableApp.vue';\nimport horizontalSortableSource from './HorizontalSortableApp.vue?raw';\nimport {baseStyles, sortableStyles} from '@dnd-kit/stories-shared/styles/sandbox';\n\nconst meta: Meta = {\n  title: 'Sortable/Horizontal list',\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const BasicSetup: Story = {\n  name: 'Basic setup',\n  render: () => ({components: {HorizontalSortableApp}, template: '<HorizontalSortableApp />'}),\n  parameters: {\n    codesandbox: {\n      files: {\n        'src/App.vue': horizontalSortableSource,\n        'src/styles.css': [baseStyles, sortableStyles].join('\\n\\n'),\n      },\n    },\n  },\n};\n"
  },
  {
    "path": "apps/stories-vue/stories/Sortable/Horizontal/HorizontalSortableApp.vue",
    "content": "<script setup lang=\"ts\">\nimport {ref, computed} from 'vue';\nimport {DragDropProvider} from '@dnd-kit/vue';\nimport {useSortable} from '@dnd-kit/vue/sortable';\nimport {move} from '@dnd-kit/helpers';\n\nconst items = ref(Array.from({length: 10}, (_, i) => i + 1));\n\nfunction onDragEnd(event: any) {\n  items.value = move(items.value, event);\n}\n</script>\n\n<script lang=\"ts\">\nimport {defineComponent} from 'vue';\n\nconst SortableItem = defineComponent({\n  props: {\n    id: {type: Number, required: true},\n    index: {type: Number, required: true},\n  },\n  setup(props) {\n    const element = ref<HTMLElement | null>(null);\n    const {isDragging} = useSortable({\n      id: computed(() => props.id),\n      index: computed(() => props.index),\n      element,\n    });\n    return {element, isDragging};\n  },\n  template: `\n    <div ref=\"element\" class=\"item\" :data-shadow=\"isDragging || undefined\"\n      :style=\"{aspectRatio: '1', justifyContent: 'center'}\">\n      {{ id }}\n    </div>\n  `,\n});\n\nexport default defineComponent({components: {SortableItem}});\n</script>\n\n<template>\n  <DragDropProvider @dragEnd=\"onDragEnd\">\n    <div :style=\"{display: 'inline-flex', flexDirection: 'row', alignItems: 'stretch', height: '180px', gap: '18px', padding: '0 30px'}\">\n      <SortableItem\n        v-for=\"(id, index) in items\"\n        :key=\"id\"\n        :id=\"id\"\n        :index=\"index\"\n      />\n    </div>\n  </DragDropProvider>\n</template>\n"
  },
  {
    "path": "apps/stories-vue/stories/Sortable/MultipleLists/MultipleLists.stories.ts",
    "content": "import type {Meta, StoryObj} from '@storybook/vue3-vite';\nimport {h} from 'vue';\n\nimport MultipleListsApp from './MultipleListsApp.vue';\nimport multipleListsSource from './MultipleListsApp.vue?raw';\nimport sortableColumnSource from './SortableColumn.vue?raw';\nimport sortableItemSource from './SortableItem.vue?raw';\nimport {baseStyles, sortableStyles, multipleListsStyles} from '@dnd-kit/stories-shared/styles/sandbox';\n\nconst styles = [baseStyles, sortableStyles, multipleListsStyles].join('\\n\\n');\n\nconst meta: Meta<typeof MultipleListsApp> = {\n  title: 'Sortable/Multiple lists',\n  component: MultipleListsApp,\n};\n\nexport default meta;\ntype Story = StoryObj<typeof MultipleListsApp>;\n\nexport const BasicSetup: Story = {\n  name: 'Basic setup',\n  render: () => ({\n    setup() {\n      return () => h('div', [h('style', styles), h(MultipleListsApp)]);\n    },\n  }),\n  parameters: {\n    codesandbox: {\n      files: {\n        'src/App.vue': multipleListsSource,\n        'src/SortableColumn.vue': sortableColumnSource,\n        'src/SortableItem.vue': sortableItemSource,\n        'src/styles.css': styles,\n      },\n    },\n  },\n};\n"
  },
  {
    "path": "apps/stories-vue/stories/Sortable/MultipleLists/MultipleListsApp.vue",
    "content": "<script setup lang=\"ts\">\nimport {ref, toRaw} from 'vue';\nimport {DragDropProvider, PointerSensor, KeyboardSensor} from '@dnd-kit/vue';\nimport {defaultPreset} from '@dnd-kit/dom';\nimport {move} from '@dnd-kit/helpers';\n\nimport SortableColumn from './SortableColumn.vue';\n\nfunction createRange(length: number) {\n  return Array.from({length}, (_, i) => i + 1);\n}\n\nconst ITEM_COUNT = 6;\n\nconst COLORS: Record<string, string> = {\n  A: '#7193f1',\n  B: '#FF851B',\n  C: '#2ECC40',\n  D: '#ff3680',\n};\n\nconst sensors = [\n  PointerSensor.configure({\n    activatorElements(source) {\n      return [source.element, source.handle];\n    },\n  }),\n  KeyboardSensor,\n];\n\nconst items = ref<Record<string, string[]>>({\n  A: createRange(ITEM_COUNT).map((id) => `A${id}`),\n  B: createRange(ITEM_COUNT).map((id) => `B${id}`),\n  C: createRange(ITEM_COUNT).map((id) => `C${id}`),\n  D: [],\n});\n\nconst columns = Object.keys(items.value);\nlet snapshot = structuredClone(toRaw(items.value));\n\nfunction onDragStart() {\n  snapshot = structuredClone(toRaw(items.value));\n}\n\nfunction onDragOver(event: any) {\n  const {source} = event.operation;\n  if (source && source.type === 'column') return;\n  items.value = move(items.value, event);\n}\n\nfunction onDragEnd(event: any) {\n  if (event.canceled) {\n    items.value = snapshot;\n  }\n}\n</script>\n\n<template>\n  <DragDropProvider\n    :plugins=\"defaultPreset.plugins\"\n    :sensors=\"sensors\"\n    @dragStart=\"onDragStart\"\n    @dragOver=\"onDragOver\"\n    @dragEnd=\"onDragEnd\"\n  >\n    <div class=\"wrapper\">\n      <SortableColumn\n        v-for=\"(column, columnIndex) in columns\"\n        :key=\"column\"\n        :id=\"column\"\n        :index=\"columnIndex\"\n        :rows=\"items[column]\"\n        :colors=\"COLORS\"\n      />\n    </div>\n  </DragDropProvider>\n</template>\n"
  },
  {
    "path": "apps/stories-vue/stories/Sortable/MultipleLists/SortableColumn.vue",
    "content": "<script setup lang=\"ts\">\nimport {ref, computed} from 'vue';\nimport {CollisionPriority} from '@dnd-kit/abstract';\nimport {useSortable} from '@dnd-kit/vue/sortable';\n\nimport SortableItem from './SortableItem.vue';\n\nconst props = defineProps<{\n  id: string;\n  index: number;\n  rows: string[];\n  colors: Record<string, string>;\n}>();\n\nconst element = ref<HTMLElement | null>(null);\nconst handle = ref<HTMLElement | null>(null);\n\nconst {isDragging} = useSortable({\n  id: computed(() => props.id),\n  index: computed(() => props.index),\n  element,\n  handle,\n  accept: ['column', 'item'],\n  collisionPriority: CollisionPriority.Low,\n  type: 'column',\n});\n</script>\n\n<template>\n  <div\n    ref=\"element\"\n    class=\"container\"\n    :data-shadow=\"isDragging ? 'true' : undefined\"\n  >\n    <h2>\n      {{ id }}\n      <button ref=\"handle\" class=\"handle\" />\n    </h2>\n    <ul>\n      <SortableItem\n        v-for=\"(itemId, itemIndex) in rows\"\n        :key=\"itemId\"\n        :id=\"itemId\"\n        :column=\"id\"\n        :index=\"itemIndex\"\n        :accent-color=\"colors[id]\"\n      />\n    </ul>\n  </div>\n</template>\n"
  },
  {
    "path": "apps/stories-vue/stories/Sortable/MultipleLists/SortableItem.vue",
    "content": "<script setup lang=\"ts\">\nimport {ref, computed} from 'vue';\nimport {useSortable} from '@dnd-kit/vue/sortable';\n\nconst props = defineProps<{\n  id: string;\n  column: string;\n  index: number;\n  accentColor: string;\n}>();\n\nconst element = ref<HTMLElement | null>(null);\nconst handle = ref<HTMLElement | null>(null);\n\nconst {isDragging} = useSortable({\n  id: computed(() => props.id),\n  index: computed(() => props.index),\n  group: computed(() => props.column),\n  element,\n  handle,\n  accept: 'item',\n  type: 'item',\n  feedback: 'clone',\n  data: computed(() => ({group: props.column})),\n});\n</script>\n\n<template>\n  <li\n    ref=\"element\"\n    class=\"item\"\n    :data-shadow=\"isDragging ? 'true' : undefined\"\n    :data-accent-color=\"column\"\n    :style=\"{'--accent-color': accentColor}\"\n  >\n    {{ id }}\n    <button ref=\"handle\" class=\"handle\" />\n  </li>\n</template>\n"
  },
  {
    "path": "apps/stories-vue/stories/Sortable/SortableApp.vue",
    "content": "<script setup lang=\"ts\">\nimport {ref, computed} from 'vue';\nimport {DragDropProvider} from '@dnd-kit/vue';\nimport {useSortable} from '@dnd-kit/vue/sortable';\nimport {move} from '@dnd-kit/helpers';\n\nconst items = ref(Array.from({length: 100}, (_, i) => i + 1));\n\nfunction onDragEnd(event: any) {\n  items.value = move(items.value, event);\n}\n</script>\n\n<script lang=\"ts\">\nimport {defineComponent} from 'vue';\n\nconst SortableItem = defineComponent({\n  props: {\n    id: {type: Number, required: true},\n    index: {type: Number, required: true},\n  },\n  setup(props) {\n    const element = ref<HTMLElement | null>(null);\n    const {isDragging} = useSortable({\n      id: computed(() => props.id),\n      index: computed(() => props.index),\n      element,\n    });\n    return {element, isDragging};\n  },\n  template: `\n    <li ref=\"element\" class=\"item\" :data-shadow=\"isDragging || undefined\">\n      {{ id }}\n    </li>\n  `,\n});\n\nexport default defineComponent({components: {SortableItem}});\n</script>\n\n<template>\n  <DragDropProvider @dragEnd=\"onDragEnd\">\n    <ul class=\"list\">\n      <SortableItem\n        v-for=\"(id, index) in items\"\n        :key=\"id\"\n        :id=\"id\"\n        :index=\"index\"\n      />\n    </ul>\n  </DragDropProvider>\n</template>\n"
  },
  {
    "path": "apps/stories-vue/stories/Sortable/SortableDragHandleApp.vue",
    "content": "<script setup lang=\"ts\">\nimport {ref, computed} from 'vue';\nimport {DragDropProvider} from '@dnd-kit/vue';\nimport {useSortable} from '@dnd-kit/vue/sortable';\nimport {move} from '@dnd-kit/helpers';\n\nconst items = ref(Array.from({length: 100}, (_, i) => i + 1));\n\nfunction onDragEnd(event: any) {\n  items.value = move(items.value, event);\n}\n</script>\n\n<script lang=\"ts\">\nimport {defineComponent} from 'vue';\n\nconst SortableItem = defineComponent({\n  props: {\n    id: {type: Number, required: true},\n    index: {type: Number, required: true},\n  },\n  setup(props) {\n    const element = ref<HTMLElement | null>(null);\n    const handle = ref<HTMLElement | null>(null);\n    const {isDragging} = useSortable({\n      id: computed(() => props.id),\n      index: computed(() => props.index),\n      element,\n      handle,\n    });\n    return {element, handle, isDragging};\n  },\n  template: `\n    <li ref=\"element\" class=\"item\" :data-shadow=\"isDragging || undefined\">\n      {{ id }}\n      <button ref=\"handle\" class=\"handle\" />\n    </li>\n  `,\n});\n\nexport default defineComponent({components: {SortableItem}});\n</script>\n\n<template>\n  <DragDropProvider @dragEnd=\"onDragEnd\">\n    <ul class=\"list\">\n      <SortableItem\n        v-for=\"(id, index) in items\"\n        :key=\"id\"\n        :id=\"id\"\n        :index=\"index\"\n      />\n    </ul>\n  </DragDropProvider>\n</template>\n"
  },
  {
    "path": "apps/stories-vue/stories/Sortable/Vertical/Vertical.stories.ts",
    "content": "import type {Meta, StoryObj} from '@storybook/vue3-vite';\n\nimport SortableApp from '../SortableApp.vue';\nimport sortableSource from '../SortableApp.vue?raw';\nimport SortableDragHandleApp from '../SortableDragHandleApp.vue';\nimport sortableDragHandleSource from '../SortableDragHandleApp.vue?raw';\nimport {\n  baseStyles,\n  handleStyles,\n  sortableStyles,\n} from '@dnd-kit/stories-shared/styles/sandbox';\n\nconst meta: Meta = {\n  title: 'Sortable/Vertical list',\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const BasicSetup: Story = {\n  name: 'Basic setup',\n  render: () => ({components: {SortableApp}, template: '<SortableApp />'}),\n  parameters: {\n    codesandbox: {\n      files: {\n        'src/App.vue': sortableSource,\n        'src/styles.css': [baseStyles, sortableStyles].join('\\n\\n'),\n      },\n    },\n  },\n};\n\nexport const WithDragHandle: Story = {\n  name: 'Drag handle',\n  render: () => ({components: {SortableDragHandleApp}, template: '<SortableDragHandleApp />'}),\n  parameters: {\n    codesandbox: {\n      files: {\n        'src/App.vue': sortableDragHandleSource,\n        'src/styles.css': [baseStyles, sortableStyles, handleStyles].join('\\n\\n'),\n      },\n    },\n  },\n};\n"
  },
  {
    "path": "apps/stories-vue/tests/draggable.spec.ts",
    "content": "import {draggableTests} from '../../stories-shared/tests/draggable.tests.ts';\n\ndraggableTests({\n  example: 'draggable-basic-setup--example',\n  dragHandle: 'draggable-drag-handles--example',\n});\n"
  },
  {
    "path": "apps/stories-vue/tests/droppable.spec.ts",
    "content": "import {droppableTests} from '../../stories-shared/tests/droppable.tests.ts';\n\ndroppableTests({\n  example: 'droppable-basic-setup--example',\n  multipleDropTargets: 'droppable-multiple-drop-targets--example',\n});\n"
  },
  {
    "path": "apps/stories-vue/tests/sortable-vertical.spec.ts",
    "content": "import {sortableVerticalTests} from '../../stories-shared/tests/sortable-vertical.tests.ts';\n\nsortableVerticalTests({\n  basicSetup: 'sortable-vertical-list--basic-setup',\n  withDragHandle: 'sortable-vertical-list--with-drag-handle',\n});\n"
  },
  {
    "path": "config/typescript/base.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/tsconfig\",\n  \"display\": \"Default\",\n  \"compilerOptions\": {\n    \"composite\": false,\n    \"declaration\": true,\n    \"declarationMap\": true,\n    \"esModuleInterop\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"inlineSources\": false,\n    \"isolatedModules\": true,\n    \"noUnusedLocals\": false,\n    \"noUnusedParameters\": false,\n    \"preserveWatchOutput\": true,\n    \"skipLibCheck\": true,\n    \"strict\": true,\n    \"allowImportingTsExtensions\": true,\n    \"emitDeclarationOnly\": true\n  },\n  \"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "config/typescript/react.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/tsconfig\",\n  \"display\": \"React\",\n  \"extends\": \"./base.json\",\n  \"compilerOptions\": {\n    \"jsx\": \"react-jsx\",\n    \"lib\": [\"dom\", \"ES2015\"],\n    \"target\": \"es6\",\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"importHelpers\": true\n  }\n}\n"
  },
  {
    "path": "config/typescript/solid.json",
    "content": "{\n  \"$schema\": \"https://json-schema.org/tsconfig\",\n  \"display\": \"Solid\",\n  \"extends\": \"./base.json\",\n  \"compilerOptions\": {\n    \"lib\": [\"dom\", \"ES2022\"],\n    \"target\": \"es6\",\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"jsx\": \"preserve\",\n    \"jsxImportSource\": \"solid-js\",\n    \"importHelpers\": true,\n    \"sourceMap\": true\n  }\n}\n"
  },
  {
    "path": "config/typescript/svelte.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/tsconfig\",\n  \"display\": \"Svelte\",\n  \"extends\": \"./base.json\",\n  \"compilerOptions\": {\n    \"lib\": [\"dom\", \"ES2022\"],\n    \"target\": \"es6\",\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"importHelpers\": true,\n    \"sourceMap\": true,\n    \"verbatimModuleSyntax\": true\n  }\n}\n"
  },
  {
    "path": "config/typescript/vanilla.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/tsconfig\",\n  \"display\": \"Vanilla\",\n  \"extends\": \"./base.json\",\n  \"compilerOptions\": {\n    \"lib\": [\"dom\", \"ES2015\"],\n    \"target\": \"es6\",\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"importHelpers\": true,\n    \"sourceMap\": true\n  }\n}\n"
  },
  {
    "path": "config/typescript/vue.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/tsconfig\",\n  \"display\": \"Vue\",\n  \"extends\": \"./base.json\",\n  \"compilerOptions\": {\n    \"lib\": [\"dom\", \"ES2022\"],\n    \"target\": \"es6\",\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"importHelpers\": true,\n    \"sourceMap\": true\n  }\n}\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"private\": true,\n  \"scripts\": {\n    \"build\": \"turbo run build\",\n    \"dev\": \"turbo run dev --concurrency 20\",\n    \"test\": \"turbo run test\",\n    \"test:e2e\": \"turbo run test:e2e\",\n    \"lint\": \"turbo run lint\",\n    \"clean\": \"turbo run clean && rm -rf node_modules\",\n    \"format\": \"prettier --write \\\"**/*.{ts,tsx,md}\\\"\",\n    \"changeset\": \"changeset\",\n    \"version-packages\": \"changeset version\",\n    \"release\": \"changeset publish\",\n    \"version-packages:beta\": \"changeset version --snapshot beta\",\n    \"release:beta\": \"changeset publish --snapshot --tag beta\"\n  },\n  \"devDependencies\": {\n    \"@changesets/changelog-github\": \"^0.5.1\",\n    \"@changesets/cli\": \"^2.29.2\",\n    \"prettier\": \"^3.1.1\",\n    \"turbo\": \"^2.5.2\"\n  },\n  \"packageManager\": \"bun@1.1.12\",\n  \"workspaces\": [\n    \"packages/*\",\n    \"apps/*\"\n  ],\n  \"name\": \"dnd-kit-experimental\"\n}\n"
  },
  {
    "path": "packages/abstract/CHANGELOG.md",
    "content": "# @dnd-kit/abstract\n\n## 0.3.2\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/geometry@0.3.2\n  - @dnd-kit/state@0.3.2\n\n## 0.3.1\n\n### Patch Changes\n\n- [#1899](https://github.com/clauderic/dnd-kit/pull/1899) [`4341114`](https://github.com/clauderic/dnd-kit/commit/43411143063349caeded4f778923473624ce25cf) Thanks [@hanneskuettner](https://github.com/hanneskuettner)! - Fix modifiers passed to `DragDropProvider` being silently destroyed before they could take effect. An array reference comparison in the modifier lifecycle effect always evaluated to true, causing manager-level modifier instances to be destroyed and reassigned in a broken state on every drag start.\n\n- Updated dependencies []:\n  - @dnd-kit/geometry@0.3.1\n  - @dnd-kit/state@0.3.1\n\n## 0.3.0\n\n### Minor Changes\n\n- [`6a59647`](https://github.com/clauderic/dnd-kit/commit/6a59647ebba2114b2e423f282ab25bf2ea40318d) Thanks [@clauderic](https://github.com/clauderic)! - Allow `plugins`, `sensors`, and `modifiers` to accept a function that receives the defaults, making it easy to extend or configure them without replacing the entire array.\n\n  ```ts\n  // Add a plugin alongside the defaults\n  const manager = new DragDropManager({\n    plugins: (defaults) => [...defaults, MyPlugin],\n  });\n  ```\n\n  ```tsx\n  // Configure a default plugin in React\n  <DragDropProvider\n    plugins={(defaults) => [\n      ...defaults,\n      Feedback.configure({dropAnimation: null}),\n    ]}\n  />\n  ```\n\n  Previously, passing `plugins`, `sensors`, or `modifiers` would replace the defaults entirely, requiring consumers to import and spread `defaultPreset`. The function form receives the default values as an argument, so consumers can add, remove, or configure individual entries without needing to know or maintain the full default list.\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/geometry@0.3.0\n  - @dnd-kit/state@0.3.0\n\n## 0.2.4\n\n### Patch Changes\n\n- [#1874](https://github.com/clauderic/dnd-kit/pull/1874) [`de27fbc`](https://github.com/clauderic/dnd-kit/commit/de27fbca9df12eece3cd53ccbbac34e0eaf113e1) Thanks [@clauderic](https://github.com/clauderic)! - Expose ergonomic type aliases for drag and drop event handlers: `CollisionEvent`, `BeforeDragStartEvent`, `DragStartEvent`, `DragMoveEvent`, `DragOverEvent`, and `DragEndEvent`. These types are re-exported from `@dnd-kit/dom` and `@dnd-kit/react` for convenience.\n\n- [#1866](https://github.com/clauderic/dnd-kit/pull/1866) [`be7cfe3`](https://github.com/clauderic/dnd-kit/commit/be7cfe3b6cf6a989aefd3e39fd145fe271942b3a) Thanks [@github-actions](https://github.com/apps/github-actions)! - Fix TypeScript type incompatibility when using abstract modifiers (`RestrictToVerticalAxis`, `RestrictToHorizontalAxis`, `SnapModifier`) with DOM or React `DragDropManager`. The `AxisModifier` and `SnapModifier` classes no longer over-constrain their generic manager type parameter.\n\n- Updated dependencies []:\n  - @dnd-kit/geometry@0.2.4\n  - @dnd-kit/state@0.2.4\n\n## 0.2.3\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/geometry@0.2.3\n  - @dnd-kit/state@0.2.3\n\n## 0.2.2\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/geometry@0.2.2\n  - @dnd-kit/state@0.2.2\n\n## 0.2.1\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/geometry@0.2.1\n  - @dnd-kit/state@0.2.1\n\n## 0.2.0\n\n### Minor Changes\n\n- [#1821](https://github.com/clauderic/dnd-kit/pull/1821) [`e95a9c8`](https://github.com/clauderic/dnd-kit/commit/e95a9c8f448d6b339e0b6fd37546ac7cfdf18edb) Thanks [@clauderic](https://github.com/clauderic)! - - Added `ActivationController` and `ActivationConstraint` primitives for input activation orchestration.\n  - Exported `ActivationConstraints<E extends Event>` type for composing multiple constraints.\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/geometry@0.2.0\n  - @dnd-kit/state@0.2.0\n\n## 0.1.21\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/geometry@0.1.21\n  - @dnd-kit/state@0.1.21\n\n## 0.1.20\n\n### Patch Changes\n\n- Updated dependencies [[`98d4cd4`](https://github.com/clauderic/dnd-kit/commit/98d4cd4047c56589cdf21067526426717bba01c4), [`32448ff`](https://github.com/clauderic/dnd-kit/commit/32448ff11eb3e86a28fc8f6ef7a8a3761e092412)]:\n  - @dnd-kit/state@0.1.20\n  - @dnd-kit/geometry@0.1.20\n\n## 0.1.19\n\n### Patch Changes\n\n- Updated dependencies [[`d848327`](https://github.com/clauderic/dnd-kit/commit/d848327b242c6714b36207071ad30e6b4183e865)]:\n  - @dnd-kit/state@0.1.19\n  - @dnd-kit/geometry@0.1.19\n\n## 0.1.18\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/geometry@0.1.18\n  - @dnd-kit/state@0.1.18\n\n## 0.1.17\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/geometry@0.1.17\n  - @dnd-kit/state@0.1.17\n\n## 0.1.16\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/geometry@0.1.16\n  - @dnd-kit/state@0.1.16\n\n## 0.1.15\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/geometry@0.1.15\n  - @dnd-kit/state@0.1.15\n\n## 0.1.14\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/geometry@0.1.14\n  - @dnd-kit/state@0.1.14\n\n## 0.1.13\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/geometry@0.1.13\n  - @dnd-kit/state@0.1.13\n\n## 0.1.12\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/geometry@0.1.12\n  - @dnd-kit/state@0.1.12\n\n## 0.1.11\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/geometry@0.1.11\n  - @dnd-kit/state@0.1.11\n\n## 0.1.10\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/geometry@0.1.10\n  - @dnd-kit/state@0.1.10\n\n## 0.1.9\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/geometry@0.1.9\n  - @dnd-kit/state@0.1.9\n\n## 0.1.8\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/geometry@0.1.8\n  - @dnd-kit/state@0.1.8\n\n## 0.1.7\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/geometry@0.1.7\n  - @dnd-kit/state@0.1.7\n\n## 0.1.6\n\n### Patch Changes\n\n- [#1671](https://github.com/clauderic/dnd-kit/pull/1671) [`7ceb799`](https://github.com/clauderic/dnd-kit/commit/7ceb799c7d214bc8223ec845357a0040c28ae40e) Thanks [@github-actions](https://github.com/apps/github-actions)! - Fix shape snapshotting in DragOperation\n\n  - Ensure shape is properly snapshotted when creating operation state snapshot\n\n- Updated dependencies [[`299389b`](https://github.com/clauderic/dnd-kit/commit/299389befcc747fe8d79231ba32f73afae88615e)]:\n  - @dnd-kit/state@0.1.6\n  - @dnd-kit/geometry@0.1.6\n\n## 0.1.5\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/geometry@0.1.5\n  - @dnd-kit/state@0.1.5\n\n## 0.1.4\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/geometry@0.1.4\n  - @dnd-kit/state@0.1.4\n\n## 0.1.3\n\n### Patch Changes\n\n- [#1663](https://github.com/clauderic/dnd-kit/pull/1663) [`6c9a9ea`](https://github.com/clauderic/dnd-kit/commit/6c9a9ea060095884c90c72cd5d6b73820467ec29) Thanks [@github-actions](https://github.com/apps/github-actions)! - Prevent race conditions in `dragOperation` when `actions.stop()` is invoked before `actions.start()` has completed.\n\n- [#1663](https://github.com/clauderic/dnd-kit/pull/1663) [`1bef872`](https://github.com/clauderic/dnd-kit/commit/1bef8722d515079f998dc0608084e1d853e74d3a) Thanks [@github-actions](https://github.com/apps/github-actions)! - Improve drag operation control by:\n\n  - Introducing `AbortController` for better operation lifecycle management\n  - Remove `requestAnimationFram()` from `start()` action\n  - Replacing boolean returns with proper abort control\n  - Ensure proper cleanup of drag operations\n  - Improving status handling and initialization checks\n  - Making feedback plugin respect operation initialization state\n\n- Updated dependencies [[`8f91d91`](https://github.com/clauderic/dnd-kit/commit/8f91d9112608d2077c3b6c8fc939aa052606148c), [`2522836`](https://github.com/clauderic/dnd-kit/commit/2522836fdb80520913ea35d94c6558bf7784afc9), [`9a0edf6`](https://github.com/clauderic/dnd-kit/commit/9a0edf64cbde1bd761f3650e043b6612e61a5fab), [`a9db4c7`](https://github.com/clauderic/dnd-kit/commit/a9db4c73467d9eda9f95fe5b582948c9fc735f57)]:\n  - @dnd-kit/state@0.1.3\n  - @dnd-kit/geometry@0.1.3\n\n## 0.1.2\n\n### Patch Changes\n\n- [#1658](https://github.com/clauderic/dnd-kit/pull/1658) [`4682570`](https://github.com/clauderic/dnd-kit/commit/4682570a6b80868af0e51b1bbbf902430117df43) Thanks [@github-actions](https://github.com/apps/github-actions)! - Fix handling of aborted drag operations across sensors. The `start` method now returns a boolean to indicate whether the operation was aborted, allowing sensors to properly clean up when a drag operation is prevented. This affects the Keyboard and Pointer sensors, ensuring they properly handle cases where `beforeDragStart` events are prevented.\n\n- [#1658](https://github.com/clauderic/dnd-kit/pull/1658) [`f8d69b0`](https://github.com/clauderic/dnd-kit/commit/f8d69b01f4cf53fc368ef1fca9188c313192928d) Thanks [@github-actions](https://github.com/apps/github-actions)! - Allow `actions.start()` to optionally receive a `source` as input.\n\n- [#1658](https://github.com/clauderic/dnd-kit/pull/1658) [`d04e9a2`](https://github.com/clauderic/dnd-kit/commit/d04e9a2879fb00f092c3f8280c8081a48eebf193) Thanks [@github-actions](https://github.com/apps/github-actions)! - Prevent starting a new drag operation while another one is active by adding a status check in the drag operation manager. This change throws an error if an attempt is made to start a drag operation while another one is in progress.\n\n- [#1658](https://github.com/clauderic/dnd-kit/pull/1658) [`ee55f58`](https://github.com/clauderic/dnd-kit/commit/ee55f582f92dc42cc6eea9ad7492fc782ca6455a) Thanks [@github-actions](https://github.com/apps/github-actions)! - Refactor the drag operation system to improve code organization and maintainability:\n\n  - Split `dragOperation.ts` into multiple focused files:\n    - `operation.ts` - Core drag operation logic\n    - `status.ts` - Status management\n    - `actions.ts` - Drag actions\n  - Update imports and exports to reflect new file structure\n  - Improve type definitions and exports\n\n- Updated dependencies [[`ee55f58`](https://github.com/clauderic/dnd-kit/commit/ee55f582f92dc42cc6eea9ad7492fc782ca6455a)]:\n  - @dnd-kit/state@0.1.2\n  - @dnd-kit/geometry@0.1.2\n\n## 0.1.1\n\n### Patch Changes\n\n- [#1656](https://github.com/clauderic/dnd-kit/pull/1656) [`f13cbc9`](https://github.com/clauderic/dnd-kit/commit/f13cbc978229844770d3c8aa03135e4352ee2532) Thanks [@github-actions](https://github.com/apps/github-actions)! - Add a new `initialization-pending` status to the drag operation lifecycle. This status is set after a dragOperation is initiated but before the `beforedragstart` event fires, which allows consumers to prevent a drag operation from being initialized. This provides better control over the drag operation lifecycle and enables cancellation of drag operations before they are initialized.\n\n- Updated dependencies []:\n  - @dnd-kit/geometry@0.1.1\n  - @dnd-kit/state@0.1.1\n\n## 0.1.0\n\n### Minor Changes\n\n- [#1650](https://github.com/clauderic/dnd-kit/pull/1650) [`00a33c9`](https://github.com/clauderic/dnd-kit/commit/00a33c99e777ab205a45309a4efc8b3560bafdaf) Thanks [@MateusJabour](https://github.com/MateusJabour)! - Adds new `data` property to `Collision` type\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/geometry@0.1.0\n  - @dnd-kit/state@0.1.0\n\n## 0.0.10\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/geometry@0.0.10\n  - @dnd-kit/state@0.0.10\n\n## 0.0.9\n\n### Patch Changes\n\n- [#1600](https://github.com/clauderic/dnd-kit/pull/1600) [`e36d954`](https://github.com/clauderic/dnd-kit/commit/e36d95420148659ba78bdbefd3a0a24ec5d02b8f) Thanks [@github-actions](https://github.com/apps/github-actions)! - Added `nativeEvent` property to `dragstart`, `dragmove` and `dragend` events. This can be used to distinguish user triggered events from sensor triggered events, as user or plugin triggered events will typically not have an associated `event` attached.\n\n- [#1600](https://github.com/clauderic/dnd-kit/pull/1600) [`b7f1cf8`](https://github.com/clauderic/dnd-kit/commit/b7f1cf8f9e15a285c45f896e092f61001335cdff) Thanks [@github-actions](https://github.com/apps/github-actions)! - Fixed a bug in the `CollisionObserver` where the initial set of collisions when a drag operation is initiated were not being set and notified.\n\n- [#1600](https://github.com/clauderic/dnd-kit/pull/1600) [`3e629cc`](https://github.com/clauderic/dnd-kit/commit/3e629cc81dbaf9d112c4f1d2c10c75eb6779cf4e) Thanks [@github-actions](https://github.com/apps/github-actions)! - Added the option to trigger `move` actions that are not propagated to `dragmove` listeners. This can be useful when firing a `dragmove` action in response to another `dragmove` event to avoid an infinite loop.\n\n- [#1600](https://github.com/clauderic/dnd-kit/pull/1600) [`ce31da7`](https://github.com/clauderic/dnd-kit/commit/ce31da736ec5d4f48bab45430be7b57223d60ee7) Thanks [@github-actions](https://github.com/apps/github-actions)! - Added `dragOperation.shape.initial` to the list of dependencies that cause the `transform` and `modifiers` to be re-calculated.\n\n- Updated dependencies [[`60e7297`](https://github.com/clauderic/dnd-kit/commit/60e72979850bfe4cbb8e2b2e2b8e84bce9edc9f5), [`8ae7014`](https://github.com/clauderic/dnd-kit/commit/8ae70143bc404bff7678fa8e8390a640c16f2579)]:\n  - @dnd-kit/geometry@0.0.9\n  - @dnd-kit/state@0.0.9\n\n## 0.0.8\n\n### Patch Changes\n\n- [#1598](https://github.com/clauderic/dnd-kit/pull/1598) [`c9716cf`](https://github.com/clauderic/dnd-kit/commit/c9716cf7b8b846faab451bd2f60c53c77d2d24ba) Thanks [@github-actions](https://github.com/apps/github-actions)! - Added `isDragging` and `isDropping` properties to `draggable` and `sortable` instances.\n\n- [#1598](https://github.com/clauderic/dnd-kit/pull/1598) [`3ea0d31`](https://github.com/clauderic/dnd-kit/commit/3ea0d314649b186bfe0524d50145625da13a8787) Thanks [@github-actions](https://github.com/apps/github-actions)! - Added optional `register` argument to instances of `Entity` to disable automatic registration of instances that have a manager supplied on initialization.\n\n- [#1597](https://github.com/clauderic/dnd-kit/pull/1597) [`3cf4db1`](https://github.com/clauderic/dnd-kit/commit/3cf4db126813ebe6ddfc025df5e42e9bfcfa9c38) Thanks [@clauderic](https://github.com/clauderic)! - Added the `registerEffect` method that can be invoked by sub-classes that extend the base `Plugin` class to register effects and automatically dispose of them when the plugin instance is destroyed.\n\n- Updated dependencies []:\n  - @dnd-kit/geometry@0.0.8\n  - @dnd-kit/state@0.0.8\n\n## 0.0.7\n\n### Patch Changes\n\n- [#1592](https://github.com/clauderic/dnd-kit/pull/1592) [`c1dadef`](https://github.com/clauderic/dnd-kit/commit/c1dadef118f8f5f096d36dac314bfe317ea950ce) Thanks [@github-actions](https://github.com/apps/github-actions)! - Fire a cancelled `dragend` event when a drag operation is interrupted by the `DragDropManager` being destroyed during an operation.\n\n- [#1592](https://github.com/clauderic/dnd-kit/pull/1592) [`cef9b46`](https://github.com/clauderic/dnd-kit/commit/cef9b46c5ed017e6a601b1d0ee9d0f05b7bbd19f) Thanks [@github-actions](https://github.com/apps/github-actions)! - Fix global modifiers set on `DragDropManager` / `<DragDropProvider>` being destroyed after the first drag operation.\n\n- Updated dependencies []:\n  - @dnd-kit/geometry@0.0.7\n  - @dnd-kit/state@0.0.7\n\n## 0.0.6\n\n### Patch Changes\n\n- [#1553](https://github.com/clauderic/dnd-kit/pull/1553) [`984b5ab`](https://github.com/clauderic/dnd-kit/commit/984b5ab7bec3145dedb9c9b3b560ffbf7e54b919) Thanks [@chrisvxd](https://github.com/chrisvxd)! - Reconfigure the manager when the input changes.\n\n- [#1567](https://github.com/clauderic/dnd-kit/pull/1567) [`081b7f2`](https://github.com/clauderic/dnd-kit/commit/081b7f2a11da2aad8ce3da7f0579974415d1fdf0) Thanks [@chrisvxd](https://github.com/chrisvxd)! - Add source maps to output.\n\n- [#1454](https://github.com/clauderic/dnd-kit/pull/1454) [`a04d3f8`](https://github.com/clauderic/dnd-kit/commit/a04d3f88d380853b97585ab3b608561f7b02ce69) Thanks [@github-actions](https://github.com/apps/github-actions)! - Rework how collisions are detected and how the position of elements is observed using a new `PositionObserver`.\n\n- [#1454](https://github.com/clauderic/dnd-kit/pull/1454) [`a8542de`](https://github.com/clauderic/dnd-kit/commit/a8542de56d39c3cd3b6ef981172a0782454295b2) Thanks [@github-actions](https://github.com/apps/github-actions)! - Fix issues with `collisionPriority` not being respected.\n\n- [#1454](https://github.com/clauderic/dnd-kit/pull/1454) [`f7458d9`](https://github.com/clauderic/dnd-kit/commit/f7458d9dc32824dbea3a6d5dfb29236f19a2c073) Thanks [@github-actions](https://github.com/apps/github-actions)! - Fixed a bug where the `accept` function of `Droppable` was never invoked if the `draggable` did not have a `type` set.\n\n- [#1454](https://github.com/clauderic/dnd-kit/pull/1454) [`e70b29a`](https://github.com/clauderic/dnd-kit/commit/e70b29ae64837e424f7279c95112fb6e420c4dcc) Thanks [@github-actions](https://github.com/apps/github-actions)! - Make sure the generic for `DragDropManager` is passed through to `Entity` so that the `manager` reference on classes extending `Entity` is strongly typed.\n\n- [#1454](https://github.com/clauderic/dnd-kit/pull/1454) [`4d1a030`](https://github.com/clauderic/dnd-kit/commit/4d1a0306c920ae064eb5b30c4c02961f50460c84) Thanks [@github-actions](https://github.com/apps/github-actions)! - Make sure the cleanup function of effects is invoked when registering a new instance with the same `id` before the old instance has been unregistered.\n\n- [#1454](https://github.com/clauderic/dnd-kit/pull/1454) [`a5933d8`](https://github.com/clauderic/dnd-kit/commit/a5933d8607e63ed08818ffab43e858863cb35d47) Thanks [@github-actions](https://github.com/apps/github-actions)! - Move responsibility from `CollisionObserver` to `CollisionNotifier` to check if the previous collisions are equal to the next collisions.\n\n- [#1454](https://github.com/clauderic/dnd-kit/pull/1454) [`a5a556a`](https://github.com/clauderic/dnd-kit/commit/a5a556abfeec1d78effb3e047f529555e444c020) Thanks [@github-actions](https://github.com/apps/github-actions)! - Fixed React lifecycle regressions related to StrictMode.\n\n- [#1448](https://github.com/clauderic/dnd-kit/pull/1448) [`96f28ef`](https://github.com/clauderic/dnd-kit/commit/96f28ef86adf95e77540732d39033c7f3fb0fd04) Thanks [@lfades](https://github.com/lfades)! - Allow entities to receive a new id during the lifecycle of the entity\n\n- Updated dependencies [[`081b7f2`](https://github.com/clauderic/dnd-kit/commit/081b7f2a11da2aad8ce3da7f0579974415d1fdf0), [`b750c05`](https://github.com/clauderic/dnd-kit/commit/b750c05b4b14f5d9817dc07d974d40b74470e904), [`71dc39f`](https://github.com/clauderic/dnd-kit/commit/71dc39fb2ec21b9a680238a91be419c71ecabe86)]:\n  - @dnd-kit/geometry@0.0.6\n  - @dnd-kit/state@0.0.6\n\n## 0.0.5\n\n### Patch Changes\n\n- [`e9be505`](https://github.com/clauderic/dnd-kit/commit/e9be5051b5c99e522fb6efd028d425220b171890) Thanks [@clauderic](https://github.com/clauderic)! - Fix lifecycle of local modifiers now that it's possible to initialize a Draggable instance without a manager instance.\n\n- Updated dependencies []:\n  - @dnd-kit/geometry@0.0.5\n  - @dnd-kit/state@0.0.5\n\n## 0.0.4\n\n### Patch Changes\n\n- [#1443](https://github.com/clauderic/dnd-kit/pull/1443) [`2ccc27c`](https://github.com/clauderic/dnd-kit/commit/2ccc27c566b13d6de46719d0ad5978d655261177) Thanks [@clauderic](https://github.com/clauderic)! - Added `status` property to draggable instances to know the current status of a draggable instance. Useful to know if an instance is being dropped.\n\n- [#1443](https://github.com/clauderic/dnd-kit/pull/1443) [`e0d80f5`](https://github.com/clauderic/dnd-kit/commit/e0d80f59c733b3adcf1fc89d29aa80257e7edd98) Thanks [@clauderic](https://github.com/clauderic)! - Refactor the lifecycle to allow `manager` to be optional and provided later during the lifecycle of `draggable` / `droppable` / `sortable` instances.\n\n- [#1443](https://github.com/clauderic/dnd-kit/pull/1443) [`794cf2f`](https://github.com/clauderic/dnd-kit/commit/794cf2f4bdeeb57a197effb1df654c7c44cf34a3) Thanks [@clauderic](https://github.com/clauderic)! - Removed `options` and `options.register` from `Entity` base class. Passing an `undefined` manager when instantiating `Draggable` and `Droppable` now has the same effect.\n\n- Updated dependencies [[`a4d9150`](https://github.com/clauderic/dnd-kit/commit/a4d91500124698abf58355592913f84d438faa3d)]:\n  - @dnd-kit/state@0.0.4\n  - @dnd-kit/geometry@0.0.4\n\n## 0.0.3\n\n### Patch Changes\n\n- [#1440](https://github.com/clauderic/dnd-kit/pull/1440) [`5ccd5e6`](https://github.com/clauderic/dnd-kit/commit/5ccd5e668fb8d736ec3c195116559cb5c5684e80) Thanks [@clauderic](https://github.com/clauderic)! - Add the ability for modifiers to be set dynamically on the `Draggable` instances\n\n- [#1440](https://github.com/clauderic/dnd-kit/pull/1440) [`886de33`](https://github.com/clauderic/dnd-kit/commit/886de33d0df851ebdcb3fcf2915f9623069b06d1) Thanks [@clauderic](https://github.com/clauderic)! - Introduced `SnapModifier` to snap to grid\n\n- Updated dependencies []:\n  - @dnd-kit/geometry@0.0.3\n  - @dnd-kit/state@0.0.3\n\n## 0.0.2\n\n### Patch Changes\n\n- Updated dependencies [[`6c84308`](https://github.com/clauderic/dnd-kit/commit/6c84308b45c55ca1324a5c752b0ec117235da9e2)]:\n  - @dnd-kit/state@0.0.2\n  - @dnd-kit/geometry@0.0.2\n"
  },
  {
    "path": "packages/abstract/README.md",
    "content": "# @dnd-kit/abstract\n\n[![Stable release](https://img.shields.io/npm/v/@dnd-kit/abstract.svg)](https://npm.im/@dnd-kit/abstract)\n\nAbstract implementation of @dnd-kit, which can be extended by concrete implementation layers, such as @dnd-kit/dom.\n\n## Overview\n\nThis package provides the core abstractions and utilities for implementing drag and drop functionality. It serves as the foundation for building concrete implementation layers on top of @dnd-kit, such as the [DOM implementation layer](../dom).\n\n> [!NOTE]\n> This package is not meant to be used by most consumers, unless you are planning on building a concrete implementation layer on top of @dnd-kit.\n\n## Core Concepts\n\n### Entities\n\nThe library defines two main entity types:\n\n- **Draggable**: Represents elements that can be dragged\n- **Droppable**: Represents elements that can receive dragged items\n\n### Sensors\n\nSensors are responsible for detecting and initiating drag operations. They handle user interactions and translate them into drag operations. The library provides:\n\n- Abstract `Sensor` base class\n- Support for multiple sensor types\n- Custom sensor configuration\n- Configurable sensor options\n\n### Collision Detection\n\nThe collision system provides:\n\n- Multiple collision detection strategies\n- Priority-based collision resolution\n- Custom collision detectors\n- Collision observation and management\n\n### Plugins\n\nThe plugin system allows extending core functionality:\n\n- Plugin-based architecture\n- Plugin configuration and descriptors\n- Plugin lifecycle management\n\n### Modifiers\n\nModifiers provide a way to transform or modify drag operations:\n\n- Abstract `Modifier` base class\n- Ability to modify coordinates and operations\n- Chainable modifier system\n- Configurable modifier options\n\n## API\n\n### Core Types\n\n- `DragDropManager`: Manages drag and drop state and operations\n- `Draggable`: Interface for draggable elements\n- `Droppable`: Interface for droppable elements\n- `Plugin`: Base class for plugins\n- `Sensor`: Abstract base class for sensors\n- `Modifier`: Abstract base class to modify drag operations\n\n## Contributing\n\nThis package is part of the dnd-kit monorepo. Please refer to the main repository's [contributing guidelines](/CONTRIBUTING.md) for details on our code of conduct and the process for submitting pull requests.\n\n## License\n\nThis package is licensed under the MIT License - see the [LICENSE](/LICENSE) file for details.\n"
  },
  {
    "path": "packages/abstract/package.json",
    "content": "{\n  \"name\": \"@dnd-kit/abstract\",\n  \"version\": \"0.3.2\",\n  \"type\": \"module\",\n  \"main\": \"./index.cjs\",\n  \"module\": \"./index.js\",\n  \"types\": \"./index.d.ts\",\n  \"sideEffects\": false,\n  \"license\": \"MIT\",\n  \"files\": [\n    \"LICENSE\",\n    \"README.md\",\n    \"index.js\",\n    \"index.js.map\",\n    \"index.d.ts\",\n    \"index.d.cts\",\n    \"index.cjs\",\n    \"index.cjs.map\",\n    \"modifiers.js\",\n    \"modifiers.js.map\",\n    \"modifiers.d.ts\",\n    \"modifiers.d.cts\",\n    \"modifiers.cjs\",\n    \"modifiers.cjs.map\"\n  ],\n  \"exports\": {\n    \".\": {\n      \"types\": \"./index.d.ts\",\n      \"import\": \"./index.js\",\n      \"require\": \"./index.cjs\"\n    },\n    \"./modifiers\": {\n      \"types\": \"./modifiers.d.ts\",\n      \"import\": \"./modifiers.js\",\n      \"require\": \"./modifiers.cjs\"\n    }\n  },\n  \"scripts\": {\n    \"build\": \"bun build:core && bun build:modifiers\",\n    \"build:core\": \"tsup src/core/index.ts\",\n    \"build:modifiers\": \"tsup --entry.modifiers src/modifiers/index.ts\",\n    \"dev\": \"bun build:core --watch & bun build:modifiers --watch\",\n    \"test\": \"bun test\",\n    \"lint\": \"TIMING=1 eslint src/**/*.ts* --fix\",\n    \"clean\": \"rm -rf .turbo && rm -rf node_modules && rm -rf dist\"\n  },\n  \"dependencies\": {\n    \"@dnd-kit/geometry\": \"^0.3.2\",\n    \"@dnd-kit/state\": \"^0.3.2\",\n    \"tslib\": \"^2.6.2\"\n  },\n  \"devDependencies\": {\n    \"@dnd-kit/eslint-config\": \"*\",\n    \"eslint\": \"^8.38.0\",\n    \"tsup\": \"8.3.0\",\n    \"typescript\": \"^5.5.2\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/clauderic/dnd-kit\"\n  }\n}\n"
  },
  {
    "path": "packages/abstract/src/core/collision/index.ts",
    "content": "export {CollisionObserver} from './observer.ts';\nexport {CollisionNotifier} from './notifier.ts';\nexport {sortCollisions} from './utilities.ts';\nexport * from './types.ts';\n"
  },
  {
    "path": "packages/abstract/src/core/collision/notifier.ts",
    "content": "import {effects, untracked} from '@dnd-kit/state';\n\nimport {Entity} from '../entities/index.ts';\nimport {DragDropManager} from '../manager/index.ts';\nimport {CorePlugin} from '../plugins/index.ts';\nimport {defaultPreventable} from '../manager/events.ts';\n\nimport type {Collision} from './types.ts';\n\nexport class CollisionNotifier extends CorePlugin {\n  constructor(manager: DragDropManager<any, any>) {\n    super(manager);\n\n    const isEqual = (a: Collision[], b: Collision[]) =>\n      a.map(({id}) => id).join('') === b.map(({id}) => id).join('');\n\n    let previousCollisions: Collision[] = [];\n\n    this.destroy = effects(\n      () => {\n        const {dragOperation, collisionObserver} = manager;\n\n        if (dragOperation.status.initializing) {\n          previousCollisions = [];\n          collisionObserver.enable();\n        }\n      },\n      () => {\n        const {collisionObserver, monitor} = manager;\n        const {collisions} = collisionObserver;\n\n        if (collisionObserver.isDisabled()) {\n          return;\n        }\n\n        if (Entity.pendingIdChanges) {\n          return;\n        }\n\n        const event = defaultPreventable({\n          collisions,\n        });\n\n        monitor.dispatch('collision', event);\n\n        if (event.defaultPrevented) {\n          return;\n        }\n\n        if (isEqual(collisions, previousCollisions)) {\n          return;\n        } else {\n          previousCollisions = collisions;\n        }\n\n        const [firstCollision] = collisions;\n\n        untracked(() => {\n          if (firstCollision?.id !== manager.dragOperation.target?.id) {\n            collisionObserver.disable();\n\n            manager.actions.setDropTarget(firstCollision?.id).then(() => {\n              collisionObserver.enable();\n            });\n          }\n        });\n      }\n    );\n  }\n}\n"
  },
  {
    "path": "packages/abstract/src/core/collision/observer.ts",
    "content": "import {signal, untracked, type Signal, effects} from '@dnd-kit/state';\nimport type {Coordinates} from '@dnd-kit/geometry';\n\nimport type {DragDropManager} from '../manager/index.ts';\nimport type {Draggable, Droppable} from '../entities/index.ts';\nimport {Plugin} from '../plugins/index.ts';\nimport type {Collision, CollisionDetector, Collisions} from './types.ts';\nimport {sortCollisions} from './utilities.ts';\n\nconst DEFAULT_VALUE: Collisions = [];\n\n/**\n * Observes and manages collision detection between draggable and droppable elements.\n *\n * @template T - The type of draggable entities\n * @template U - The type of droppable entities\n * @template V - The type of drag drop manager\n *\n * @remarks\n * The CollisionObserver is responsible for:\n * - Computing collisions between draggable and droppable elements\n * - Maintaining a signal of current collisions\n * - Updating collision state based on drag operation changes\n */\nexport class CollisionObserver<\n  T extends Draggable = Draggable,\n  U extends Droppable = Droppable,\n  V extends DragDropManager<T, U> = DragDropManager<T, U>,\n> extends Plugin<V> {\n  /**\n   * Creates a new CollisionObserver instance.\n   *\n   * @param manager - The drag drop manager instance\n   */\n  constructor(manager: V) {\n    super(manager);\n\n    this.computeCollisions = this.computeCollisions.bind(this);\n    this.#collisions = signal(DEFAULT_VALUE);\n\n    this.destroy = effects(\n      () => {\n        const collisions = this.computeCollisions();\n        const coordinates = untracked(\n          () => this.manager.dragOperation.position.current\n        );\n\n        if (collisions !== DEFAULT_VALUE) {\n          const previousCoordinates = this.#previousCoordinates;\n          this.#previousCoordinates = coordinates;\n\n          if (\n            previousCoordinates &&\n            coordinates.x == previousCoordinates.x &&\n            coordinates.y == previousCoordinates.y\n          ) {\n            return;\n          }\n        } else {\n          this.#previousCoordinates = undefined;\n        }\n\n        this.#collisions.value = collisions;\n      },\n      () => {\n        const {dragOperation} = this.manager;\n\n        if (dragOperation.status.initialized) {\n          this.forceUpdate();\n        }\n      }\n    );\n  }\n\n  #previousCoordinates: Coordinates | undefined;\n\n  /**\n   * Forces an immediate update of collision detection.\n   *\n   * @param immediate - If true, updates collisions immediately. If false, resets previous coordinates.\n   */\n  public forceUpdate(immediate = true) {\n    untracked(() => {\n      if (immediate) {\n        this.#collisions.value = this.computeCollisions();\n      } else {\n        this.#previousCoordinates = undefined;\n      }\n    });\n  }\n\n  /**\n   * Computes collisions between draggable and droppable elements.\n   *\n   * @param entries - Optional array of droppable elements to check. If not provided, uses all registered droppables.\n   * @param collisionDetector - Optional custom collision detector function\n   * @returns Array of detected collisions, sorted by priority\n   */\n  public computeCollisions(\n    entries?: Droppable[],\n    collisionDetector?: CollisionDetector\n  ) {\n    const {registry, dragOperation} = this.manager;\n    const {source, shape, status} = dragOperation;\n\n    if (!status.initialized || !shape) {\n      return DEFAULT_VALUE;\n    }\n\n    const collisions: Collision[] = [];\n    const potentialTargets = [];\n\n    for (const entry of entries ?? registry.droppables) {\n      if (entry.disabled) {\n        continue;\n      }\n\n      if (source && !entry.accepts(source)) {\n        continue;\n      }\n\n      const detectCollision = collisionDetector ?? entry.collisionDetector;\n\n      if (!detectCollision) {\n        continue;\n      }\n\n      potentialTargets.push(entry);\n\n      // Force collisions to be recomputed when the shape changes\n      void entry.shape;\n\n      const collision = untracked(() =>\n        detectCollision({\n          droppable: entry,\n          dragOperation,\n        })\n      );\n\n      if (collision) {\n        if (entry.collisionPriority != null) {\n          collision.priority = entry.collisionPriority;\n        }\n\n        collisions.push(collision);\n      }\n    }\n\n    if (potentialTargets.length === 0) {\n      return DEFAULT_VALUE;\n    }\n\n    collisions.sort(sortCollisions);\n\n    return collisions;\n  }\n\n  /**\n   * Gets the current collisions signal value.\n   */\n  public get collisions() {\n    return this.#collisions.value;\n  }\n\n  #collisions: Signal<Collisions>;\n}\n"
  },
  {
    "path": "packages/abstract/src/core/collision/types.ts",
    "content": "import type {DragOperation} from '../manager/index.ts';\nimport type {\n  Draggable,\n  Droppable,\n  UniqueIdentifier,\n} from '../entities/index.ts';\n\n/**\n * Priority levels for collision detection.\n *\n * @remarks\n * Higher priority collisions take precedence over lower priority ones.\n * Custom numeric priorities can also be used for fine-grained control.\n */\nexport enum CollisionPriority {\n  /** Lowest priority level */\n  Lowest,\n  /** Low priority level */\n  Low,\n  /** Normal priority level */\n  Normal,\n  /** High priority level */\n  High,\n  /** Highest priority level */\n  Highest,\n}\n\n/**\n * Types of collision detection.\n *\n * @remarks\n * Different collision types can be used to implement various\n * drag and drop behaviors and visual feedback.\n */\nexport enum CollisionType {\n  /** Basic collision detection */\n  Collision,\n  /** Shape-based intersection detection */\n  ShapeIntersection,\n  /** Pointer-based intersection detection */\n  PointerIntersection,\n}\n\n/**\n * Represents a detected collision between a draggable and droppable.\n *\n * @remarks\n * Contains information about the collision type, priority, and\n * additional data that can be used for custom behaviors.\n */\nexport interface Collision {\n  /** Unique identifier of the droppable involved in the collision */\n  id: UniqueIdentifier;\n  /** Priority of the collision */\n  priority: CollisionPriority | number;\n  /** Type of collision detected */\n  type: CollisionType;\n  /** Numeric value representing the collision strength or overlap */\n  value: number;\n  /** Additional data associated with the collision */\n  data?: Record<string, any>;\n}\n\n/** Array of detected collisions */\nexport type Collisions = Collision[];\n\n/**\n * Input for collision detection functions.\n *\n * @template T - The type of draggable entities\n * @template U - The type of droppable entities\n */\nexport interface CollisionDetectorInput<\n  T extends Draggable = Draggable,\n  U extends Droppable = Droppable,\n> {\n  /** The droppable to check for collisions */\n  droppable: U;\n  /** The current drag operation state */\n  dragOperation: DragOperation<T, U>;\n}\n\n/**\n * Function type for detecting collisions between draggables and droppables.\n *\n * @template T - The type of draggable entities\n * @template U - The type of droppable entities\n * @param input - The collision detection input\n * @returns A collision object if detected, null otherwise\n */\nexport type CollisionDetector = <\n  T extends Draggable = Draggable,\n  U extends Droppable = Droppable,\n>(\n  input: CollisionDetectorInput<T, U>\n) => Collision | null;\n"
  },
  {
    "path": "packages/abstract/src/core/collision/utilities.ts",
    "content": "import {Collision} from './types.ts';\n\n/**\n * Sort collisions from greatest to smallest priority\n * Collisions of equal priority are sorted from greatest to smallest value\n */\nexport function sortCollisions(a: Collision, b: Collision) {\n  if (a.priority === b.priority) {\n    if (a.type === b.type) {\n      return b.value - a.value;\n    }\n\n    return b.type - a.type;\n  }\n\n  return b.priority - a.priority;\n}\n"
  },
  {
    "path": "packages/abstract/src/core/entities/draggable/draggable.ts",
    "content": "import {derived, reactive} from '@dnd-kit/state';\nimport type {Alignment} from '@dnd-kit/geometry';\n\nimport {Entity} from '../entity/index.ts';\nimport type {EntityInput, Data, Type} from '../entity/index.ts';\nimport type {Modifiers} from '../../modifiers/index.ts';\nimport type {DragDropManager} from '../../manager/index.ts';\nimport type {Sensors} from '../../sensors/sensor.ts';\nimport type {\n  Plugins,\n  PluginConstructor,\n  PluginDescriptor,\n} from '../../plugins/index.ts';\nimport {descriptor as toDescriptor} from '../../plugins/index.ts';\n\n/**\n * Input configuration for creating a draggable entity.\n *\n * @template T - The type of data associated with the draggable\n *\n * @remarks\n * Extends the base entity input with draggable-specific configuration:\n * - Type for categorization\n * - Sensors for handling drag interactions\n * - Modifiers for transforming drag behavior\n * - Alignment for positioning\n */\nexport interface Input<T extends Data = Data> extends EntityInput<T> {\n  type?: Type;\n  sensors?: Sensors;\n  modifiers?: Modifiers;\n  alignment?: Alignment;\n  plugins?: Plugins;\n}\n\n/**\n * Possible status values for a draggable entity.\n *\n * @remarks\n * - idle: Not being dragged\n * - dragging: Currently being dragged\n * - dropping: Currently being dropped\n */\nexport type DraggableStatus = 'idle' | 'dragging' | 'dropping';\n\n/**\n * Represents an entity that can be dragged in a drag and drop operation.\n *\n * @template T - The type of data associated with the draggable\n * @template U - The type of drag and drop manager\n *\n * @remarks\n * This class extends the base Entity class with draggable-specific functionality:\n * - Type-based categorization\n * - Sensor-based interaction handling\n * - Modifier-based behavior transformation\n * - Status tracking during drag operations\n */\nexport class Draggable<\n  T extends Data = Data,\n  U extends DragDropManager<any, any> = DragDropManager<any, any>,\n> extends Entity<T, U> {\n  constructor(\n    {modifiers, type, sensors, plugins, effects, ...input}: Input<T>,\n    manager: U | undefined\n  ) {\n    super(\n      {\n        ...input,\n        effects: () => [\n          ...(effects?.() ?? []),\n          () => {\n            const {manager, plugins} = this;\n            if (!manager || !plugins) return;\n\n            for (const entry of plugins) {\n              const {plugin} = toDescriptor(entry);\n              manager.registry.plugins.register(plugin);\n            }\n          },\n        ],\n      },\n      manager\n    );\n\n    this.type = type;\n    this.sensors = sensors;\n    this.modifiers = modifiers;\n    this.alignment = input.alignment;\n    this.plugins = plugins;\n  }\n\n  /** The type of the draggable entity */\n  @reactive\n  public accessor type: Type | undefined;\n\n  /** The sensors associated with the draggable entity */\n  public sensors: Sensors | undefined;\n\n  /** The modifiers associated with the draggable entity */\n  @reactive\n  public accessor modifiers: Modifiers | undefined;\n\n  /** The alignment of the draggable entity */\n  public alignment: Alignment | undefined;\n\n  /** Per-entity plugin configuration descriptors */\n  public plugins: Plugins | undefined;\n\n  /**\n   * Look up per-entity options for a given plugin constructor.\n   */\n  public pluginConfig<P extends PluginConstructor>(\n    plugin: P\n  ): PluginDescriptor<any, any, P>['options'] | undefined {\n    if (!this.plugins) return undefined;\n\n    for (const entry of this.plugins) {\n      const desc = toDescriptor(entry);\n      if (desc.plugin === plugin) return desc.options;\n    }\n\n    return undefined;\n  }\n\n  /** The current status of the draggable entity */\n  @reactive\n  public accessor status: DraggableStatus = this.isDragSource\n    ? 'dragging'\n    : 'idle';\n\n  /**\n   * Checks if the draggable entity is currently being dropped.\n   *\n   * @returns true if the entity is being dropped and is the drag source\n   */\n  @derived\n  public get isDropping() {\n    return this.status === 'dropping' && this.isDragSource;\n  }\n\n  /**\n   * Checks if the draggable entity is currently being dragged.\n   *\n   * @returns true if the entity is being dragged and is the drag source\n   */\n  @derived\n  public get isDragging() {\n    return this.status === 'dragging' && this.isDragSource;\n  }\n\n  /**\n   * Checks if the draggable entity is the source of the current drag operation.\n   *\n   * @returns true if the entity's ID matches the current drag operation's source ID\n   */\n  @derived\n  public get isDragSource() {\n    return this.manager?.dragOperation.source?.id === this.id;\n  }\n}\n"
  },
  {
    "path": "packages/abstract/src/core/entities/draggable/index.ts",
    "content": "export {Draggable} from './draggable.ts';\nexport type {Input as DraggableInput} from './draggable.ts';\n"
  },
  {
    "path": "packages/abstract/src/core/entities/droppable/droppable.ts",
    "content": "import {derived, effects, reactive, type Effect} from '@dnd-kit/state';\nimport type {Shape} from '@dnd-kit/geometry';\n\nimport {Entity} from '../entity/index.ts';\nimport type {EntityInput, Data, Type} from '../entity/index.ts';\nimport {\n  CollisionPriority,\n  type CollisionDetector,\n} from '../../collision/index.ts';\nimport type {DragDropManager} from '../../manager/index.ts';\nimport {Draggable} from '../draggable/draggable.ts';\n\n/**\n * Input configuration for creating a droppable entity.\n *\n * @template T - The type of data associated with the droppable\n *\n * @remarks\n * Extends the base entity input with droppable-specific configuration:\n * - Accept rules for determining compatible draggables\n * - Collision detection configuration\n * - Type for categorization\n */\nexport interface Input<T extends Data = Data> extends EntityInput<T> {\n  /** Types of draggables that can be dropped here, or a function to determine compatibility */\n  accept?: Type | Type[] | ((source: Draggable) => boolean);\n  /** Priority for collision detection */\n  collisionPriority?: CollisionPriority | number;\n  /** Detector for determining collisions with draggables */\n  collisionDetector: CollisionDetector;\n  /** Type for categorization */\n  type?: Type;\n}\n\n/**\n * Represents an entity that can receive draggable items in a drag and drop operation.\n *\n * @template T - The type of data associated with the droppable\n * @template U - The type of drag and drop manager\n *\n * @remarks\n * This class extends the base Entity class with droppable-specific functionality:\n * - Type-based acceptance rules\n * - Collision detection\n * - Shape tracking\n * - Target status tracking\n */\nexport class Droppable<\n  T extends Data = Data,\n  U extends DragDropManager<any, any> = DragDropManager<any, any>,\n> extends Entity<T, U> {\n  constructor(\n    {accept, collisionDetector, collisionPriority, type, ...input}: Input<T>,\n    manager: U | undefined\n  ) {\n    super(input, manager);\n\n    this.accept = accept;\n    this.collisionDetector = collisionDetector;\n    this.collisionPriority = collisionPriority;\n    this.type = type;\n  }\n\n  /**\n   * Types of draggables that can be dropped here, or a function to determine compatibility.\n   *\n   * @remarks\n   * If undefined, all draggables are accepted.\n   * If a function, it determines compatibility based on the draggable.\n   * If a type or array of types, only draggables of matching types are accepted.\n   */\n  @reactive\n  public accessor accept:\n    | Type\n    | Type[]\n    | ((draggable: Draggable) => boolean)\n    | undefined;\n\n  /** The type of the droppable entity */\n  @reactive\n  public accessor type: Type | undefined;\n\n  /**\n   * Checks whether or not the droppable accepts a given draggable.\n   *\n   * @param draggable - The draggable to check\n   * @returns true if the draggable can be dropped here\n   */\n  public accepts(draggable: Draggable): boolean {\n    const {accept} = this;\n\n    if (!accept) {\n      return true;\n    }\n\n    if (typeof accept === 'function') {\n      return accept(draggable);\n    }\n\n    if (!draggable.type) {\n      return false;\n    }\n\n    if (Array.isArray(accept)) {\n      return accept.includes(draggable.type);\n    }\n\n    return draggable.type === accept;\n  }\n\n  /** The collision detector for this droppable */\n  @reactive\n  public accessor collisionDetector: CollisionDetector;\n\n  /** The collision priority for this droppable */\n  @reactive\n  public accessor collisionPriority: CollisionPriority | number | undefined;\n\n  /** The current shape of this droppable */\n  @reactive\n  public accessor shape: Shape | undefined;\n\n  /**\n   * Checks if this droppable is the current drop target.\n   *\n   * @returns true if this droppable's ID matches the current drag operation's target ID\n   */\n  @derived\n  public get isDropTarget() {\n    return this.manager?.dragOperation.target?.id === this.id;\n  }\n}\n"
  },
  {
    "path": "packages/abstract/src/core/entities/droppable/index.ts",
    "content": "export {Droppable} from './droppable.ts';\nexport type {Input as DroppableInput} from './droppable.ts';\n"
  },
  {
    "path": "packages/abstract/src/core/entities/entity/entity.ts",
    "content": "import {\n  batch,\n  CleanupFunction,\n  reactive,\n  signal,\n  type Signal,\n  type Effect,\n} from '@dnd-kit/state';\n\nimport {DragDropManager} from '../../manager/index.ts';\nimport type {Data, UniqueIdentifier} from './types.ts';\n\nexport interface Input<T extends Data = Data> {\n  /**\n   * The unique identifier of the entity.\n   */\n  id: UniqueIdentifier;\n  /**\n   * Optional data associated with the entity.\n   */\n  data?: T;\n  /**\n   * Whether the entity should initially be disabled.\n   * @default false\n   */\n  disabled?: boolean;\n  /**\n   * Whether the entity should be automatically registered with the manager when it is created.\n   * @default true\n   */\n  register?: boolean;\n  /**\n   * An array of effects that are set up when the entity is registered and cleaned up when it is unregistered.\n   */\n  effects?(): Effect[];\n}\n\n/**\n * The `Entity` class is an abstract representation of a distinct unit in the drag and drop system.\n * It is a base class that other concrete classes like `Draggable` and `Droppable` can extend.\n *\n * @template T - The type of data associated with the entity.\n */\nexport class Entity<\n  T extends Data = Data,\n  U extends DragDropManager<any, any> = DragDropManager<any, any>,\n> {\n  static pendingIdChanges: Map<Entity, UniqueIdentifier> | null = null;\n\n  static #flushIdChanges() {\n    const changes = Entity.pendingIdChanges;\n    Entity.pendingIdChanges = null;\n\n    if (changes) {\n      batch(() => {\n        for (const [entity, id] of changes) {\n          entity.#idSignal.value = id;\n        }\n      });\n    }\n  }\n\n  /**\n   * Creates a new instance of the `Entity` class.\n   *\n   * @param input - An object containing the initial properties of the entity.\n   * @param manager - The manager that controls the drag and drop operations.\n   */\n  constructor(input: Input<T>, manager: U | undefined) {\n    const {effects, id, data = {} as T, disabled = false, register = true} = input;\n\n    let previousId = id;\n\n    this.#idSignal = signal(id);\n    this.manager = manager;\n    this.data = data;\n    this.disabled = disabled;\n    this.effects = () => [\n      () => {\n        const {id, manager} = this;\n\n        if (id === previousId) {\n          return;\n        }\n\n        previousId = id;\n        manager?.registry.register(this);\n\n        return () => manager?.registry.unregister(this);\n      },\n      ...(effects?.() ?? []),\n    ];\n\n    this.register = this.register.bind(this);\n    this.unregister = this.unregister.bind(this);\n    this.destroy = this.destroy.bind(this);\n\n    if (manager && register) {\n      queueMicrotask(this.register);\n    }\n  }\n\n  /**\n   * The manager that controls the drag and drop operations.\n   */\n  @reactive\n  public accessor manager: U | undefined;\n\n  /**\n   * The unique identifier of the entity.\n   *\n   * Setting this property defers the signal update to a microtask,\n   * batching multiple id changes together atomically. This ensures\n   * that when entities swap ids (e.g. during sorting with virtualization),\n   * all registry updates happen in a single transaction.\n   */\n  #idSignal: Signal<UniqueIdentifier>;\n\n  public get id(): UniqueIdentifier {\n    const signalValue = this.#idSignal.value;\n    return Entity.pendingIdChanges?.get(this) ?? signalValue;\n  }\n\n  public set id(value: UniqueIdentifier) {\n    const current = Entity.pendingIdChanges?.get(this) ?? this.#idSignal.peek();\n    if (value === current) return;\n\n    if (!Entity.pendingIdChanges) {\n      Entity.pendingIdChanges = new Map();\n      queueMicrotask(() => Entity.#flushIdChanges());\n    }\n\n    Entity.pendingIdChanges.set(this, value);\n  }\n\n  /**\n   * The data associated with the entity.\n   */\n  @reactive\n  public accessor data: T;\n\n  /**\n   * A boolean indicating whether the entity is disabled.\n   */\n  @reactive\n  public accessor disabled: boolean;\n\n  /**\n   * An array of effects that are applied to the entity.\n   */\n  public effects: () => Effect[];\n\n  /**\n   * A method that registers the entity with the manager.\n   * @returns CleanupFunction | void\n   */\n  public register(): CleanupFunction | void {\n    return this.manager?.registry.register(this);\n  }\n\n  /**\n   * A method that unregisters the entity from the manager.\n   * @returns void\n   */\n  public unregister(): void {\n    this.manager?.registry.unregister(this);\n  }\n\n  /**\n   * A method that cleans up the entity when it is no longer needed.\n   * @returns void\n   */\n  public destroy(): void {\n    this.manager?.registry.unregister(this);\n  }\n}\n"
  },
  {
    "path": "packages/abstract/src/core/entities/entity/index.ts",
    "content": "export {Entity} from './entity.ts';\nexport type {Input as EntityInput} from './entity.ts';\n\nexport type {Data, Type, UniqueIdentifier} from './types.ts';\n\nexport {EntityRegistry} from './registry.ts';\n"
  },
  {
    "path": "packages/abstract/src/core/entities/entity/registry.ts",
    "content": "import {effects, signal} from '@dnd-kit/state';\n\nimport type {Entity} from './entity.ts';\nimport type {UniqueIdentifier} from './types.ts';\n\n/**\n * Reactive class representing a registry for entities.\n * @template T - The type of entries that the registry manages,\n * for example, `Draggable` or `Droppable` entities.\n */\nexport class EntityRegistry<T extends Entity> {\n  private map = signal<Map<UniqueIdentifier, T>>(new Map());\n  private cleanupFunctions = new WeakMap<T, () => void>();\n\n  /**\n   * Iterator for the EntityRegistry class.\n   * @returns An iterator for the values in the map.\n   */\n  public [Symbol.iterator]() {\n    return this.map.peek().values();\n  }\n\n  public get value() {\n    return this.map.value.values();\n  }\n\n  /**\n   * Checks if a entity with the given identifier exists in the registry.\n   * @param identifier - The unique identifier of the entity.\n   * @returns True if the entity exists, false otherwise.\n   */\n  public has(identifier: UniqueIdentifier): boolean {\n    return this.map.value.has(identifier);\n  }\n\n  /**\n   * Retrieves a entity from the registry using its identifier.\n   * @param identifier - The unique identifier of the entity.\n   * @returns The entity if it exists, undefined otherwise.\n   */\n  public get(identifier: UniqueIdentifier): T | undefined {\n    return this.map.value.get(identifier);\n  }\n\n  /**\n   * Registers a entity in the registry.\n   * @param key - The unique identifier of the entity.\n   * @param value - The entity to register.\n   * @returns A function that unregisters the entity.\n   */\n  public register = (key: UniqueIdentifier, value: T) => {\n    const current = this.map.peek();\n    const currentValue = current.get(key);\n    const unregister = () => this.unregister(key, value);\n\n    if (currentValue === value) return unregister;\n\n    if (currentValue) {\n      if (currentValue.id === key) {\n        const cleanup = this.cleanupFunctions.get(currentValue);\n        cleanup?.();\n        this.cleanupFunctions.delete(currentValue);\n      }\n    }\n\n    const updatedMap = new Map(current);\n\n    // Remove ghost registrations: if this entity exists at a different key\n    // (stale entry from before its id changed), clean it up\n    for (const [existingKey, existingValue] of current) {\n      if (existingValue === value && existingKey !== key) {\n        updatedMap.delete(existingKey);\n        break;\n      }\n    }\n\n    updatedMap.set(key, value);\n\n    this.map.value = updatedMap;\n\n    const cleanup = effects(...value.effects());\n    this.cleanupFunctions.set(value, cleanup);\n\n    return unregister;\n  };\n\n  /**\n   * Unregisters an entity from the registry.\n   * @param key - The unique identifier of the entity.\n   * @param value - The entity instance to unregister.\n   */\n  public unregister = (key: UniqueIdentifier, value: T) => {\n    const current = this.map.peek();\n\n    if (current.get(key) !== value) {\n      return;\n    }\n\n    const cleanup = this.cleanupFunctions.get(value);\n    cleanup?.();\n    this.cleanupFunctions.delete(value);\n\n    const updatedMap = new Map(current);\n    updatedMap.delete(key);\n\n    this.map.value = updatedMap;\n  };\n\n  /**\n   * Destroys all entries in the registry and clears the registry.\n   */\n  public destroy() {\n    for (const entry of this) {\n      const cleanup = this.cleanupFunctions.get(entry);\n      cleanup?.();\n      entry.destroy();\n    }\n\n    this.map.value = new Map();\n  }\n}\n"
  },
  {
    "path": "packages/abstract/src/core/entities/entity/types.ts",
    "content": "/**\n * Type representing arbitrary data associated with an entity.\n *\n * @remarks\n * This type is used to store additional information about entities\n * that can be accessed during drag and drop operations.\n */\nexport type Data = Record<string, any>;\n\n/**\n * Type representing a unique identifier for an entity.\n *\n * @remarks\n * This type is used to uniquely identify draggable and droppable entities\n * within the drag and drop system.\n */\nexport type UniqueIdentifier = string | number;\n\n/**\n * Type representing the type of an entity.\n *\n * @remarks\n * This type is used to categorize entities and can be used to\n * implement type-based filtering or matching.\n */\nexport type Type = Symbol | string | number;\n"
  },
  {
    "path": "packages/abstract/src/core/entities/index.ts",
    "content": "export * from './entity/index.ts';\nexport * from './draggable/index.ts';\nexport * from './droppable/index.ts';\n"
  },
  {
    "path": "packages/abstract/src/core/index.ts",
    "content": "export {\n  DragDropManager,\n  DragOperationStatus,\n  resolveCustomizable,\n} from './manager/index.ts';\nexport type {\n  DragDropManagerInput,\n  Customizable,\n  DragActions,\n  DragDropEventMap,\n  DragDropEventHandlers,\n  CollisionEvent,\n  BeforeDragStartEvent,\n  DragStartEvent,\n  DragMoveEvent,\n  DragOverEvent,\n  DragEndEvent,\n  DragOperation,\n  Renderer,\n} from './manager/index.ts';\n\nexport {\n  CollisionPriority,\n  CollisionType,\n  sortCollisions,\n} from './collision/index.ts';\nexport type {Collision, CollisionDetector} from './collision/index.ts';\n\nexport {Modifier} from './modifiers/index.ts';\nexport type {Modifiers, ModifierConstructor} from './modifiers/index.ts';\n\nexport {Draggable, Droppable} from './entities/index.ts';\nexport type {\n  Data,\n  DraggableInput,\n  DroppableInput,\n  Entity,\n  Type,\n  UniqueIdentifier,\n} from './entities/index.ts';\n\nexport {\n  Plugin,\n  PluginRegistry,\n  CorePlugin,\n  configure,\n  configurator,\n  descriptor,\n} from './plugins/index.ts';\nexport type {\n  Plugins,\n  PluginConstructor,\n  PluginDescriptor,\n  PluginOptions,\n} from './plugins/index.ts';\n\nexport {\n  ActivationConstraint,\n  ActivationController,\n  Sensor,\n} from './sensors/index.ts';\nexport type {\n  ActivationConstraints,\n  Sensors,\n  SensorConstructor,\n  SensorDescriptor,\n  SensorOptions,\n} from './sensors/index.ts';\n"
  },
  {
    "path": "packages/abstract/src/core/manager/actions.ts",
    "content": "import type {Coordinates} from '@dnd-kit/geometry';\nimport {batch, effect, untracked} from '@dnd-kit/state';\n\nimport type {\n  Draggable,\n  Droppable,\n  UniqueIdentifier,\n} from '../entities/index.ts';\n\nimport type {DragDropManager} from './manager.ts';\nimport {defaultPreventable} from './events.ts';\nimport {StatusValue} from './status.ts';\n\n/**\n * Provides actions for controlling drag and drop operations.\n *\n * @template T - The type of draggable entities\n * @template U - The type of droppable entities\n * @template V - The type of drag and drop manager\n */\nexport class DragActions<\n  T extends Draggable,\n  U extends Droppable,\n  V extends DragDropManager<T, U>,\n> {\n  /**\n   * Creates a new instance of drag actions.\n   *\n   * @param manager - The drag and drop manager instance\n   */\n  constructor(private readonly manager: V) {}\n\n  /**\n   * Sets the source of the drag operation.\n   *\n   * @param source - The draggable entity or its unique identifier\n   */\n  setDragSource(source: T | UniqueIdentifier) {\n    const {dragOperation} = this.manager;\n    dragOperation.sourceIdentifier =\n      typeof source === 'string' || typeof source === 'number'\n        ? source\n        : source.id;\n  }\n\n  /**\n   * Sets the target of the drop operation.\n   *\n   * @param identifier - The unique identifier of the droppable entity or null/undefined\n   * @returns A promise that resolves to true if the drop was prevented\n   */\n  setDropTarget(\n    identifier: UniqueIdentifier | null | undefined\n  ): Promise<boolean> {\n    return untracked(() => {\n      const {dragOperation} = this.manager;\n      const id = identifier ?? null;\n\n      if (dragOperation.targetIdentifier === id) {\n        return Promise.resolve(false);\n      }\n\n      dragOperation.targetIdentifier = id;\n\n      const event = defaultPreventable({\n        operation: dragOperation.snapshot(),\n      });\n\n      if (dragOperation.status.dragging) {\n        this.manager.monitor.dispatch('dragover', event);\n      }\n\n      return this.manager.renderer.rendering.then(() => event.defaultPrevented);\n    });\n  }\n\n  /**\n   * Starts a new drag operation.\n   *\n   * @param args - Configuration for the drag operation\n   * @param args.event - The event that initiated the drag\n   * @param args.source - The source draggable entity or its identifier\n   * @param args.coordinates - The initial coordinates of the drag\n   * @returns true if the drag operation started successfully\n   * @throws {Error} If there is no drag source or another operation is active\n   */\n  start(args: {\n    /** The event that initiated the drag. */\n    event?: Event;\n    /** The source draggable entity or its identifier. */\n    source?: T | UniqueIdentifier;\n    /** The initial coordinates of the drag. */\n    coordinates: Coordinates;\n  }): AbortController {\n    return untracked(() => {\n      const {dragOperation} = this.manager;\n\n      if (args.source != null) {\n        this.setDragSource(args.source);\n      }\n\n      const sourceInstance = dragOperation.source;\n\n      if (!sourceInstance) {\n        throw new Error('Cannot start a drag operation without a drag source');\n      }\n\n      if (!dragOperation.status.idle) {\n        throw new Error(\n          'Cannot start a drag operation while another is active'\n        );\n      }\n\n      const controller = new AbortController();\n\n      const {event: nativeEvent, coordinates} = args;\n\n      batch(() => {\n        dragOperation.status.set(StatusValue.InitializationPending);\n        dragOperation.shape = null;\n        dragOperation.canceled = false;\n        dragOperation.activatorEvent = nativeEvent ?? null;\n        dragOperation.position.reset(coordinates);\n      });\n\n      const beforeStartEvent = defaultPreventable({\n        operation: dragOperation.snapshot(),\n      });\n\n      this.manager.monitor.dispatch('beforedragstart', beforeStartEvent);\n\n      if (beforeStartEvent.defaultPrevented) {\n        dragOperation.reset();\n        controller.abort();\n        return controller;\n      }\n\n      dragOperation.status.set(StatusValue.Initializing);\n      dragOperation.controller = controller;\n\n      this.manager.renderer.rendering.then(() => {\n        if (controller.signal.aborted) return;\n\n        const {status} = dragOperation;\n        if (status.current !== StatusValue.Initializing) return;\n\n        dragOperation.status.set(StatusValue.Dragging);\n\n        this.manager.monitor.dispatch('dragstart', {\n          nativeEvent,\n          operation: dragOperation.snapshot(),\n          cancelable: false,\n        });\n      });\n\n      return controller;\n    });\n  }\n\n  /**\n   * Moves the dragged entity to a new position.\n   *\n   * @param args - Configuration for the move operation\n   * @param args.by - Relative coordinates to move by\n   * @param args.to - Absolute coordinates to move to\n   * @param args.event - The event that triggered the move\n   * @param args.cancelable - Whether the move can be canceled\n   * @param args.propagate - Whether to dispatch dragmove events\n   */\n  move(args: {\n    /** The relative coordinates to move by. */\n    by?: Coordinates;\n    /** The absolute coordinates to move to. */\n    to?: Coordinates;\n    /** The event that triggered the move. */\n    event?: Event;\n    /** Whether the move can be canceled. */\n    cancelable?: boolean;\n    /** Whether to propagate the dragmove event to the manager. */\n    propagate?: boolean;\n  }): void {\n    return untracked(() => {\n      const {dragOperation} = this.manager;\n      const {status, controller} = dragOperation;\n\n      if (!status.dragging || !controller || controller.signal.aborted) {\n        return;\n      }\n\n      const event = defaultPreventable(\n        {\n          nativeEvent: args.event,\n          operation: dragOperation.snapshot(),\n          by: args.by,\n          to: args.to,\n        },\n        args.cancelable ?? true\n      );\n\n      if (args.propagate ?? true) {\n        this.manager.monitor.dispatch('dragmove', event);\n      }\n\n      queueMicrotask(() => {\n        if (event.defaultPrevented) {\n          return;\n        }\n\n        const coordinates = args.to ?? {\n          x: dragOperation.position.current.x + (args.by?.x ?? 0),\n          y: dragOperation.position.current.y + (args.by?.y ?? 0),\n        };\n\n        dragOperation.position.current = coordinates;\n      });\n    });\n  }\n\n  /**\n   * Stops the current drag operation.\n   *\n   * @param args - Configuration for stopping the operation\n   * @param args.event - The event that triggered the stop\n   * @param args.canceled - Whether the operation was canceled\n   * @remarks\n   * This method:\n   * - Dispatches a dragend event\n   * - Allows suspension of the operation\n   * - Handles cleanup of the operation state\n   */\n  stop(\n    args: {\n      /**\n       * The event that triggered the stop.\n       */\n      event?: Event;\n      /**\n       * Whether the operation was canceled.\n       *\n       * @default false\n       */\n      canceled?: boolean;\n    } = {}\n  ): void {\n    return untracked(() => {\n      const {dragOperation} = this.manager;\n      const {controller} = dragOperation;\n\n      if (!controller || controller.signal.aborted) return;\n\n      let promise: Promise<void> | undefined;\n      const suspend = () => {\n        const output = {\n          resume: () => {},\n          abort: () => {},\n        };\n\n        promise = new Promise<void>((resolve, reject) => {\n          output.resume = resolve;\n          output.abort = reject;\n        });\n\n        return output;\n      };\n\n      controller.abort();\n\n      const end = () => {\n        this.manager.renderer.rendering.then(() => {\n          dragOperation.status.set(StatusValue.Dropped);\n\n          const dropping = untracked(\n            () => dragOperation.source?.status === 'dropping'\n          );\n\n          const cleanup = () => {\n            if (dragOperation.controller === controller) {\n              dragOperation.controller = undefined;\n            }\n            dragOperation.reset();\n          };\n\n          if (dropping) {\n            const {source} = dragOperation;\n\n            // Wait until the source has finished dropping before resetting the operation\n            const dispose = effect(() => {\n              if (source?.status === 'idle') {\n                dispose();\n                cleanup();\n              }\n            });\n          } else {\n            this.manager.renderer.rendering.then(cleanup);\n          }\n        });\n      };\n\n      dragOperation.canceled = args.canceled ?? false;\n\n      this.manager.monitor.dispatch('dragend', {\n        nativeEvent: args.event,\n        operation: dragOperation.snapshot(),\n        canceled: args.canceled ?? false,\n        suspend,\n      });\n\n      if (promise) {\n        promise.then(end).catch(() => dragOperation.reset());\n      } else {\n        end();\n      }\n    });\n  }\n}\n"
  },
  {
    "path": "packages/abstract/src/core/manager/events.ts",
    "content": "import type {Coordinates} from '@dnd-kit/geometry';\n\nimport type {Draggable, Droppable} from '../entities/index.ts';\nimport type {Collisions} from '../collision/index.ts';\nimport type {DragDropManager} from './manager.ts';\nimport type {DragOperationSnapshot} from './operation.ts';\n\n/** Base type for event handler functions */\nexport type Events = Record<string, (...args: any[]) => void>;\n\n/**\n * Extends an event type with preventable functionality.\n *\n * @template T - The base event type\n */\nexport type Preventable<T> = T & {\n  /** Whether the event can be canceled */\n  cancelable: boolean;\n  /** Whether the default action was prevented */\n  defaultPrevented: boolean;\n  /** Prevents the default action of the event */\n  preventDefault(): void;\n};\n\n/**\n * Base class for event monitoring and dispatching.\n *\n * @template T - The type of events to monitor\n */\nclass Monitor<T extends Events> {\n  private registry = new Map<keyof T, Set<T[keyof T]>>();\n\n  /**\n   * Adds an event listener for the specified event type.\n   *\n   * @param name - The name of the event to listen for\n   * @param handler - The function to call when the event occurs\n   * @returns A function to remove the event listener\n   */\n  public addEventListener<U extends keyof T>(name: U, handler: T[U]) {\n    const {registry} = this;\n    const listeners = new Set(registry.get(name));\n\n    listeners.add(handler);\n    registry.set(name, listeners);\n\n    return () => this.removeEventListener(name, handler);\n  }\n\n  /**\n   * Removes an event listener for the specified event type.\n   *\n   * @param name - The name of the event\n   * @param handler - The function to remove\n   */\n  public removeEventListener(name: keyof T, handler: T[keyof T]) {\n    const {registry} = this;\n    const listeners = new Set(registry.get(name));\n\n    listeners.delete(handler);\n    registry.set(name, listeners);\n  }\n\n  /**\n   * Dispatches an event to all registered listeners.\n   *\n   * @param name - The name of the event to dispatch\n   * @param args - Arguments to pass to the event handlers\n   */\n  protected dispatch<U extends keyof T>(name: U, ...args: any[]) {\n    const {registry} = this;\n    const listeners = registry.get(name);\n\n    if (!listeners) {\n      return;\n    }\n\n    for (const listener of listeners) {\n      listener(...args);\n    }\n  }\n}\n\n/**\n * Map of drag and drop event objects, keyed by event name.\n * Follows the same pattern as the DOM's `WindowEventMap`.\n *\n * @template T - The type of draggable entities\n * @template U - The type of droppable entities\n * @template V - The type of drag and drop manager\n */\nexport type DragDropEventMap<\n  T extends Draggable,\n  U extends Droppable,\n  V extends DragDropManager<T, U>,\n> = {\n  /** Event fired when collisions are detected */\n  collision: Preventable<{\n    collisions: Collisions;\n  }>;\n  /** Event fired before a drag operation starts */\n  beforedragstart: Preventable<{\n    operation: DragOperationSnapshot<T, U>;\n    nativeEvent?: Event;\n  }>;\n  /** Event fired when a drag operation starts */\n  dragstart: {\n    cancelable: false;\n    operation: DragOperationSnapshot<T, U>;\n    nativeEvent?: Event;\n  };\n  /** Event fired when a drag operation moves */\n  dragmove: Preventable<{\n    operation: DragOperationSnapshot<T, U>;\n    to?: Coordinates;\n    by?: Coordinates;\n    nativeEvent?: Event;\n  }>;\n  /** Event fired when a drag operation hovers over a droppable */\n  dragover: Preventable<{\n    operation: DragOperationSnapshot<T, U>;\n  }>;\n  /** Event fired when a drag operation ends */\n  dragend: {\n    operation: DragOperationSnapshot<T, U>;\n    nativeEvent?: Event;\n    canceled: boolean;\n    suspend(): {resume(): void; abort(): void};\n  };\n};\n\n/**\n * Map of drag and drop event handler signatures, keyed by event name.\n * Each handler receives the event object and the manager instance.\n * Derived from `DragDropEventMap`.\n *\n * @template T - The type of draggable entities\n * @template U - The type of droppable entities\n * @template V - The type of drag and drop manager\n */\nexport type DragDropEventHandlers<\n  T extends Draggable,\n  U extends Droppable,\n  V extends DragDropManager<T, U>,\n> = {\n  [K in keyof DragDropEventMap<T, U, V>]: (\n    event: DragDropEventMap<T, U, V>[K],\n    manager: V\n  ) => void;\n};\n\nexport type CollisionEvent<\n  T extends Draggable = Draggable,\n  U extends Droppable = Droppable,\n  V extends DragDropManager<T, U> = DragDropManager<T, U>,\n> = DragDropEventMap<T, U, V>['collision'];\n\nexport type BeforeDragStartEvent<\n  T extends Draggable = Draggable,\n  U extends Droppable = Droppable,\n  V extends DragDropManager<T, U> = DragDropManager<T, U>,\n> = DragDropEventMap<T, U, V>['beforedragstart'];\n\nexport type DragStartEvent<\n  T extends Draggable = Draggable,\n  U extends Droppable = Droppable,\n  V extends DragDropManager<T, U> = DragDropManager<T, U>,\n> = DragDropEventMap<T, U, V>['dragstart'];\n\nexport type DragMoveEvent<\n  T extends Draggable = Draggable,\n  U extends Droppable = Droppable,\n  V extends DragDropManager<T, U> = DragDropManager<T, U>,\n> = DragDropEventMap<T, U, V>['dragmove'];\n\nexport type DragOverEvent<\n  T extends Draggable = Draggable,\n  U extends Droppable = Droppable,\n  V extends DragDropManager<T, U> = DragDropManager<T, U>,\n> = DragDropEventMap<T, U, V>['dragover'];\n\nexport type DragEndEvent<\n  T extends Draggable = Draggable,\n  U extends Droppable = Droppable,\n  V extends DragDropManager<T, U> = DragDropManager<T, U>,\n> = DragDropEventMap<T, U, V>['dragend'];\n\n/**\n * Monitors and dispatches drag and drop events.\n *\n * @template T - The type of draggable entities\n * @template U - The type of droppable entities\n * @template V - The type of drag and drop manager\n */\nexport class DragDropMonitor<\n  T extends Draggable,\n  U extends Droppable,\n  V extends DragDropManager<T, U>,\n> extends Monitor<DragDropEventHandlers<T, U, V>> {\n  /**\n   * Creates a new drag and drop monitor.\n   *\n   * @param manager - The drag and drop manager to monitor\n   */\n  constructor(private manager: V) {\n    super();\n  }\n\n  /**\n   * Dispatches a drag and drop event.\n   *\n   * @param type - The type of event to dispatch\n   * @param event - The event data to dispatch\n   */\n  public dispatch<Key extends keyof DragDropEventMap<T, U, V>>(\n    type: Key,\n    event: DragDropEventMap<T, U, V>[Key]\n  ) {\n    const args = [event, this.manager] as any;\n\n    super.dispatch(type, ...args);\n  }\n}\n\n/**\n * Creates a preventable event object.\n *\n * @param event - The base event object\n * @param cancelable - Whether the event can be canceled\n * @returns A preventable event object\n */\nexport function defaultPreventable<T>(\n  event: T,\n  cancelable = true\n): Preventable<T> {\n  let defaultPrevented = false;\n\n  return {\n    ...event,\n    cancelable,\n    get defaultPrevented() {\n      return defaultPrevented;\n    },\n    preventDefault() {\n      if (!cancelable) {\n        return;\n      }\n\n      defaultPrevented = true;\n    },\n  };\n}\n"
  },
  {
    "path": "packages/abstract/src/core/manager/index.ts",
    "content": "export {DragDropManager, resolveCustomizable} from './manager.ts';\nexport type {DragDropManagerInput, Customizable} from './manager.ts';\nexport type {DragActions} from './actions.ts';\nexport type {\n  DragDropEventMap,\n  DragDropEventHandlers,\n  CollisionEvent,\n  BeforeDragStartEvent,\n  DragStartEvent,\n  DragMoveEvent,\n  DragOverEvent,\n  DragEndEvent,\n} from './events.ts';\nexport {Status as DragOperationStatus} from './status.ts';\nexport type {DragOperationSnapshot as DragOperation} from './operation.ts';\nexport type {DragDropRegistry} from './registry.ts';\nexport type {InferDraggable, InferDroppable} from './types.ts';\nexport type {Renderer} from './renderer.ts';\n"
  },
  {
    "path": "packages/abstract/src/core/manager/manager.ts",
    "content": "import {effects, untracked} from '@dnd-kit/state';\n\nimport type {Draggable, Droppable} from '../entities/index.ts';\nimport {CollisionObserver, CollisionNotifier} from '../collision/index.ts';\nimport type {Plugins, Plugin} from '../plugins/index.ts';\nimport type {Sensor, Sensors} from '../sensors/index.ts';\nimport type {Modifier, Modifiers} from '../modifiers/index.ts';\nimport {descriptor} from '../plugins/utilities.ts';\n\nimport {DragActions} from './actions.ts';\nimport {DragDropRegistry} from './registry.ts';\nimport {DragOperation} from './operation.ts';\nimport {DragDropMonitor} from './events.ts';\nimport {defaultRenderer, type Renderer} from './renderer.ts';\n\n/**\n * A value that can be provided as-is or as a function that receives defaults.\n *\n * @example\n * // As a plain array (replaces defaults)\n * plugins: [MyPlugin]\n *\n * // As a function (receives defaults)\n * plugins: (defaults) => [...defaults, MyPlugin]\n */\nexport type Customizable<T> = T | ((defaults: T) => T);\n\n/**\n * Resolves a customizable value by applying it to defaults.\n *\n * @param value - A value or function that receives defaults\n * @param defaults - The default value to use when undefined, or to pass to a function\n * @returns The resolved value\n */\nexport function resolveCustomizable<T>(\n  value: Customizable<T> | undefined,\n  defaults: T\n): T {\n  if (typeof value === 'function') {\n    return (value as (defaults: T) => T)(defaults);\n  }\n\n  return value ?? defaults;\n}\n\nexport type DragDropManagerInput<T extends DragDropManager<any, any>> = {\n  plugins?: Customizable<Plugins<T>>;\n  sensors?: Customizable<Sensors<T>>;\n  modifiers?: Customizable<Modifiers<T>>;\n  renderer?: Renderer;\n};\n\n/**\n * Central manager class that orchestrates drag and drop operations.\n *\n * @template T - The type of draggable entities\n * @template U - The type of droppable entities\n */\nexport class DragDropManager<T extends Draggable, U extends Droppable> {\n  /** Actions that can be performed during drag operations */\n  public actions: DragActions<T, U, DragDropManager<T, U>>;\n\n  /** Observes and manages collision detection between draggable and droppable entities */\n  public collisionObserver: CollisionObserver<T, U>;\n\n  /** Tracks the current drag operation state and metadata */\n  public dragOperation: DragOperation<T, U>;\n\n  /** Monitors and emits drag and drop events */\n  public monitor: DragDropMonitor<T, U, DragDropManager<T, U>>;\n\n  /** Registry that manages draggable and droppable entities */\n  public registry: DragDropRegistry<T, U, DragDropManager<T, U>>;\n\n  /** Handles rendering of drag and drop visual feedback */\n  public renderer: Renderer;\n\n  /**\n   * Creates a new drag and drop manager instance.\n   *\n   * @param config - Optional configuration for plugins, sensors, modifiers, and renderer\n   */\n  constructor(config?: DragDropManagerInput<any>) {\n    type V = DragDropManager<T, U>;\n\n    const raw = config ?? {};\n    const plugins = resolveCustomizable(raw.plugins, []);\n    const sensors = resolveCustomizable(raw.sensors, []);\n    const modifiers = resolveCustomizable(raw.modifiers, []);\n    const renderer = raw.renderer ?? defaultRenderer;\n    const monitor = new DragDropMonitor<T, U, V>(this);\n    const registry = new DragDropRegistry<T, U, V>(this);\n\n    this.registry = registry;\n    this.monitor = monitor;\n    this.renderer = renderer;\n\n    this.actions = new DragActions<T, U, V>(this);\n    this.dragOperation = new DragOperation<T, U>(this);\n    this.collisionObserver = new CollisionObserver<T, U, V>(this);\n    this.plugins = [CollisionNotifier, ...plugins];\n    this.modifiers = modifiers;\n    this.sensors = sensors;\n\n    const {destroy} = this;\n\n    const cleanup = effects(() => {\n      const currentModifiers = untracked(() => this.dragOperation.modifiers);\n      const managerModifiers = this.modifiers;\n\n      for (const modifier of currentModifiers) {\n        if (!managerModifiers.includes(modifier)) {\n          modifier.destroy();\n        }\n      }\n\n      this.dragOperation.modifiers =\n        this.dragOperation.source?.modifiers?.map((modifier) => {\n          const {plugin, options} = descriptor(modifier);\n          return new plugin(this, options);\n        }) ?? managerModifiers;\n    });\n\n    this.destroy = () => {\n      cleanup();\n      destroy();\n    };\n  }\n\n  /**\n   * Gets the list of active plugins.\n   *\n   * @returns Array of active plugin instances\n   */\n  get plugins(): Plugin<any>[] {\n    return this.registry.plugins.values;\n  }\n\n  /**\n   * Sets the list of plugins to be used by the manager.\n   *\n   * @param plugins - Array of plugin constructors or instances\n   */\n  set plugins(plugins: Plugins<any>) {\n    this.registry.plugins.values = plugins;\n  }\n\n  /**\n   * Gets the list of active modifiers.\n   *\n   * @returns Array of active modifier instances\n   */\n  get modifiers(): Modifier<any>[] {\n    return this.registry.modifiers.values;\n  }\n\n  /**\n   * Sets the list of modifiers to be used by the manager.\n   *\n   * @param modifiers - Array of modifier constructors or instances\n   */\n  set modifiers(modifiers: Modifiers<any>) {\n    this.registry.modifiers.values = modifiers;\n  }\n\n  /**\n   * Gets the list of active sensors.\n   *\n   * @returns Array of active sensor instances\n   */\n  get sensors(): Sensor<any>[] {\n    return this.registry.sensors.values;\n  }\n\n  /**\n   * Sets the list of sensors to be used by the manager.\n   *\n   * @param sensors - Array of sensor constructors or instances\n   */\n  set sensors(sensors: Sensors<any>) {\n    this.registry.sensors.values = sensors;\n  }\n\n  /**\n   * Cleans up resources and stops any active drag operations.\n   */\n  public destroy = () => {\n    if (!this.dragOperation.status.idle) {\n      this.actions.stop({canceled: true});\n    }\n\n    this.dragOperation.modifiers.forEach((modifier) => modifier.destroy());\n\n    this.registry.destroy();\n    this.collisionObserver.destroy();\n  };\n}\n"
  },
  {
    "path": "packages/abstract/src/core/manager/operation.ts",
    "content": "import {Position, type Shape} from '@dnd-kit/geometry';\nimport type {Coordinates} from '@dnd-kit/geometry';\nimport {\n  batch,\n  derived,\n  reactive,\n  snapshot,\n  untracked,\n  ValueHistory,\n  type WithHistory,\n} from '@dnd-kit/state';\n\nimport type {\n  Draggable,\n  Droppable,\n  UniqueIdentifier,\n} from '../entities/index.ts';\nimport type {Modifier} from '../modifiers/index.ts';\n\nimport type {DragDropManager} from './manager.ts';\nimport {Status, StatusValue} from './status.ts';\n\nexport interface DragOperationSnapshot<\n  T extends Draggable = Draggable,\n  U extends Droppable = Droppable,\n> {\n  readonly activatorEvent: Event | null;\n  readonly canceled: boolean;\n  readonly position: Position;\n  readonly transform: Coordinates;\n  readonly status: Status;\n  get shape(): WithHistory<Shape> | null;\n  set shape(value: Shape | null);\n  readonly source: T | null;\n  readonly target: U | null;\n}\n\n/**\n * Represents the current state of a drag operation.\n *\n * @template T - The type of draggable entities\n * @template U - The type of droppable entities\n */\nexport class DragOperation<T extends Draggable, U extends Droppable>\n  implements DragOperationSnapshot<T, U>\n{\n  /**\n   * Creates a new drag operation instance.\n   *\n   * @param manager - The drag and drop manager that owns this operation\n   */\n  constructor(manager: DragDropManager<T, U>) {\n    this.#manager = manager;\n  }\n\n  #manager: DragDropManager<T, U>;\n\n  #previousSource?: T;\n\n  #shape = new ValueHistory<Shape | undefined>(undefined, (a, b) =>\n    a && b ? a.equals(b) : a === b\n  );\n\n  /** Current status of the drag operation */\n  public readonly status = new Status();\n\n  /** The controller for the currentdrag operation */\n  public controller: AbortController | undefined;\n\n  /**\n   * Gets the current shape of the dragged entity with history.\n   *\n   * @returns The shape history or null if no shape is set\n   */\n  @derived\n  public get shape(): WithHistory<Shape> | null {\n    const {current, initial, previous} = this.#shape;\n\n    if (!current || !initial) {\n      return null;\n    }\n\n    return {current, initial, previous};\n  }\n\n  /**\n   * Sets the shape of the dragged entity.\n   *\n   * @param value - The new shape or null to reset\n   */\n  public set shape(value: Shape | null) {\n    if (!value) {\n      this.#shape.reset();\n    } else {\n      this.#shape.current = value;\n    }\n  }\n\n  /** Whether the drag operation was canceled */\n  @reactive\n  public accessor canceled = false;\n\n  /** The event that initiated the drag operation */\n  @reactive\n  public accessor activatorEvent: Event | null = null;\n\n  /** Unique identifier of the source draggable entity */\n  @reactive\n  public accessor sourceIdentifier: UniqueIdentifier | null = null;\n\n  /** Unique identifier of the target droppable entity */\n  @reactive\n  public accessor targetIdentifier: UniqueIdentifier | null = null;\n\n  /** List of modifiers applied to the drag operation */\n  @reactive\n  public accessor modifiers: Modifier[] = [];\n\n  /** Current position of the dragged entity */\n  public position = new Position({x: 0, y: 0});\n\n  /**\n   * Gets the source draggable entity.\n   *\n   * @returns The current draggable entity, falling back to the previous\n   * instance to bridge the gap when React unmounts and remounts a sortable\n   * during reparenting (e.g. moving an item between columns).\n   */\n  @derived\n  public get source(): T | null {\n    const identifier = this.sourceIdentifier;\n    if (identifier == null) return null;\n\n    const value = this.#manager.registry.draggables.get(identifier);\n\n    if (value) {\n      this.#previousSource = value;\n    }\n\n    return value ?? this.#previousSource ?? null;\n  }\n\n  /**\n   * Gets the target droppable entity.\n   *\n   * @returns The current droppable entity or null if not found\n   */\n  @derived\n  public get target(): U | null {\n    const identifier = this.targetIdentifier;\n    return identifier != null\n      ? (this.#manager.registry.droppables.get(identifier) ?? null)\n      : null;\n  }\n\n  #transform = {x: 0, y: 0};\n\n  /**\n   * Gets the current transform after applying all modifiers.\n   *\n   * @returns The transformed coordinates\n   */\n  @derived\n  public get transform() {\n    const {x, y} = this.position.delta;\n    let transform = {x, y};\n\n    for (const modifier of this.modifiers) {\n      transform = modifier.apply({\n        ...this.snapshot(),\n        transform,\n      });\n    }\n\n    this.#transform = transform;\n\n    return transform;\n  }\n\n  /**\n   * Creates a snapshot of the current drag operation state.\n   *\n   * @returns An immutable snapshot of the current operation state\n   */\n  public snapshot(): DragOperationSnapshot<T, U> {\n    return untracked(() => ({\n      source: this.source,\n      target: this.target,\n      activatorEvent: this.activatorEvent,\n      transform: this.#transform,\n      shape: this.shape ? snapshot(this.shape) : null,\n      position: snapshot(this.position),\n      status: snapshot(this.status),\n      canceled: this.canceled,\n    }));\n  }\n\n  /**\n   * Resets the drag operation to its initial state.\n   *\n   * @remarks\n   * This method:\n   * - Sets status to idle\n   * - Clears source and target identifiers\n   * - Resets shape history\n   * - Resets position and transform\n   * - Clears modifiers\n   */\n  public reset() {\n    batch(() => {\n      this.status.set(StatusValue.Idle);\n      this.sourceIdentifier = null;\n      this.targetIdentifier = null;\n      this.#shape.reset();\n      this.position.reset({x: 0, y: 0});\n      this.#transform = {x: 0, y: 0};\n      this.modifiers = [];\n    });\n  }\n}\n"
  },
  {
    "path": "packages/abstract/src/core/manager/registry.ts",
    "content": "import type {CleanupFunction} from '@dnd-kit/state';\n\nimport {\n  Draggable,\n  Droppable,\n  Entity,\n  EntityRegistry,\n} from '../entities/index.ts';\nimport {\n  PluginRegistry,\n  Plugin,\n  type PluginConstructor,\n  PluginOptions,\n} from '../plugins/index.ts';\nimport {\n  Sensor,\n  SensorOptions,\n  type SensorConstructor,\n} from '../sensors/index.ts';\nimport {Modifier, type ModifierConstructor} from '../modifiers/index.ts';\nimport type {DragDropManager} from './manager.ts';\n\n/**\n * Manages the registration and lifecycle of draggable and droppable entities,\n * as well as plugins, sensors, and modifiers.\n *\n * @template T - The type of draggable entities\n * @template U - The type of droppable entities\n * @template V - The type of drag and drop manager\n */\nexport class DragDropRegistry<\n  T extends Draggable,\n  U extends Droppable,\n  V extends DragDropManager<T, U>,\n> {\n  /**\n   * Creates a new registry instance.\n   *\n   * @param manager - The drag and drop manager that owns this registry\n   */\n  constructor(manager: V) {\n    this.plugins = new PluginRegistry<V, PluginConstructor<V>>(manager);\n    this.sensors = new PluginRegistry<V, SensorConstructor<V>>(manager);\n    this.modifiers = new PluginRegistry<V, ModifierConstructor<V>>(manager);\n  }\n\n  /** Registry for draggable entities */\n  public draggables = new EntityRegistry<T>();\n\n  /** Registry for droppable entities */\n  public droppables = new EntityRegistry<U>();\n\n  /** Registry for plugins */\n  public plugins: PluginRegistry<V, PluginConstructor<V>>;\n\n  /** Registry for sensors */\n  public sensors: PluginRegistry<V, SensorConstructor<V>>;\n\n  /** Registry for modifiers */\n  public modifiers: PluginRegistry<V, ModifierConstructor<V>>;\n\n  /**\n   * Registers a new entity, plugin, sensor, or modifier.\n   *\n   * @param input - The entity, plugin constructor, sensor constructor, or modifier constructor to register\n   * @param options - Optional configuration for plugins and sensors\n   * @returns A cleanup function or the registered instance\n   * @throws {Error} If the input type is invalid\n   */\n  public register(input: Entity): () => void;\n  public register(input: Draggable): () => void;\n  public register(input: Droppable): () => void;\n  public register(input: SensorConstructor, options?: SensorOptions): Sensor;\n  public register(input: ModifierConstructor): Modifier;\n  public register(input: PluginConstructor, options?: PluginOptions): Plugin;\n  public register(input: any, options?: Record<string, any>) {\n    if (input instanceof Draggable) {\n      return this.draggables.register(input.id, input as T);\n    }\n\n    if (input instanceof Droppable) {\n      return this.droppables.register(input.id, input as U);\n    }\n\n    if (input.prototype instanceof Modifier) {\n      return this.modifiers.register(input, options);\n    }\n\n    if (input.prototype instanceof Sensor) {\n      return this.sensors.register(input, options);\n    }\n\n    if (input.prototype instanceof Plugin) {\n      return this.plugins.register(input, options);\n    }\n\n    throw new Error('Invalid instance type');\n  }\n\n  /**\n   * Unregisters an entity, plugin, sensor, or modifier.\n   *\n   * @param input - The entity, plugin constructor, sensor constructor, or modifier constructor to unregister\n   * @returns A cleanup function\n   * @throws {Error} If the input type is invalid\n   */\n  public unregister(input: Entity): CleanupFunction;\n  public unregister(input: Draggable): CleanupFunction;\n  public unregister(input: Droppable): CleanupFunction;\n  public unregister(input: SensorConstructor): CleanupFunction;\n  public unregister(input: ModifierConstructor): CleanupFunction;\n  public unregister(input: PluginConstructor): CleanupFunction;\n  public unregister(input: any) {\n    if (input instanceof Entity) {\n      if (input instanceof Draggable) {\n        return this.draggables.unregister(input.id, input as T);\n      }\n\n      if (input instanceof Droppable) {\n        return this.droppables.unregister(input.id, input as U);\n      }\n\n      // no-op\n      return () => {};\n    }\n\n    if (input.prototype instanceof Modifier) {\n      return this.modifiers.unregister(input);\n    }\n\n    if (input.prototype instanceof Sensor) {\n      return this.sensors.unregister(input);\n    }\n\n    if (input.prototype instanceof Plugin) {\n      return this.plugins.unregister(input);\n    }\n\n    throw new Error('Invalid instance type');\n  }\n\n  /**\n   * Destroys all registered entities and cleans up resources.\n   *\n   * @remarks\n   * This method:\n   * - Destroys all draggable and droppable entities\n   * - Destroys all plugins, sensors, and modifiers\n   * - Cleans up any associated resources\n   */\n  destroy() {\n    this.draggables.destroy();\n    this.droppables.destroy();\n    this.plugins.destroy();\n    this.sensors.destroy();\n    this.modifiers.destroy();\n  }\n}\n"
  },
  {
    "path": "packages/abstract/src/core/manager/renderer.ts",
    "content": "/**\n * Interface for handling visual feedback during drag operations.\n *\n * @remarks\n * Implementations of this interface are responsible for managing\n * the visual state of dragged elements and ensuring smooth animations.\n */\nexport interface Renderer {\n  /**\n   * Gets a promise that resolves when the current rendering operation is complete.\n   *\n   * @returns A promise that resolves when rendering is finished\n   */\n  get rendering(): Promise<void>;\n}\n\n/**\n * Default renderer implementation.\n *\n * @remarks\n * This implementation immediately resolves rendering promises,\n * making it suitable for environments where custom rendering\n * is not required or handled externally.\n */\nexport const defaultRenderer: Renderer = {\n  get rendering() {\n    return Promise.resolve();\n  },\n};\n"
  },
  {
    "path": "packages/abstract/src/core/manager/status.ts",
    "content": "import {derived, reactive} from '@dnd-kit/state';\n\n/**\n * Enum representing the possible states of a drag operation.\n */\nexport enum StatusValue {\n  /** No drag operation is in progress */\n  Idle = 'idle',\n  /** A drag operation is about to start */\n  InitializationPending = 'initialization-pending',\n  /** A drag operation is being initialized */\n  Initializing = 'initializing',\n  /** A drag operation is in progress */\n  Dragging = 'dragging',\n  /** A drag operation has completed */\n  Dropped = 'dropped',\n}\n\n/**\n * Manages the status of a drag operation.\n *\n * @remarks\n * This class provides reactive accessors for checking the current state\n * of a drag operation and methods for updating it.\n */\nexport class Status {\n  /** The current status value */\n  @reactive\n  private accessor value: StatusValue = StatusValue.Idle;\n\n  /**\n   * Gets the current status value.\n   *\n   * @returns The current status value\n   */\n  @derived\n  public get current(): StatusValue {\n    return this.value;\n  }\n\n  /**\n   * Checks if the status is idle.\n   *\n   * @returns true if no drag operation is in progress\n   */\n  @derived\n  public get idle(): boolean {\n    return this.value === StatusValue.Idle;\n  }\n\n  /**\n   * Checks if the status is initializing.\n   *\n   * @returns true if a drag operation is being initialized\n   */\n  @derived\n  public get initializing(): boolean {\n    return this.value === StatusValue.Initializing;\n  }\n\n  /**\n   * Checks if the status is initialized.\n   *\n   * @returns true if a drag operation has started initialization\n   */\n  @derived\n  public get initialized(): boolean {\n    const {value} = this;\n\n    return (\n      value !== StatusValue.Idle && value !== StatusValue.InitializationPending\n    );\n  }\n\n  /**\n   * Checks if the status is dragging.\n   *\n   * @returns true if a drag operation is in progress\n   */\n  @derived\n  public get dragging(): boolean {\n    return this.value === StatusValue.Dragging;\n  }\n\n  /**\n   * Checks if the status is dropped.\n   *\n   * @returns true if a drag operation has completed\n   */\n  @derived\n  public get dropped(): boolean {\n    return this.value === StatusValue.Dropped;\n  }\n\n  /**\n   * Sets the current status value.\n   *\n   * @param value - The new status value\n   */\n  public set(value: StatusValue) {\n    this.value = value;\n  }\n}\n"
  },
  {
    "path": "packages/abstract/src/core/manager/types.ts",
    "content": "import type {DragDropManager} from './manager.ts';\n\n/**\n * Infers the draggable type from a drag and drop manager type.\n *\n * @template P - The drag and drop manager type\n * @returns The inferred draggable type\n *\n * @example\n * ```typescript\n * type MyDraggable = InferDraggable<DragDropManager<HTMLDivElement, HTMLDivElement>>;\n * // MyDraggable is HTMLDivElement\n * ```\n */\nexport type InferDraggable<P> =\n  P extends DragDropManager<infer T, any> ? T : never;\n\n/**\n * Infers the droppable type from a drag and drop manager type.\n *\n * @template P - The drag and drop manager type\n * @returns The inferred droppable type\n *\n * @example\n * ```typescript\n * type MyDroppable = InferDroppable<DragDropManager<HTMLDivElement, HTMLDivElement>>;\n * // MyDroppable is HTMLDivElement\n * ```\n */\nexport type InferDroppable<P> =\n  P extends DragDropManager<any, infer T> ? T : never;\n"
  },
  {
    "path": "packages/abstract/src/core/modifiers/index.ts",
    "content": "export {Modifier} from './modifier.ts';\n\nexport type {\n  Modifiers,\n  ModifierConstructor,\n  ModifierDescriptor,\n  ModifierOptions,\n} from './modifier.ts';\n"
  },
  {
    "path": "packages/abstract/src/core/modifiers/modifier.ts",
    "content": "import type {Coordinates} from '@dnd-kit/geometry';\n\nimport {\n  Plugin,\n  type PluginOptions,\n  type PluginConstructor,\n  type PluginDescriptor,\n} from '../plugins/index.ts';\nimport type {DragDropManager} from '../manager/manager.ts';\nimport type {DragOperationSnapshot} from '../manager/operation.ts';\n\n/** Options that can be passed to a modifier */\nexport type ModifierOptions = PluginOptions;\n\n/**\n * Base class for drag operation modifiers.\n *\n * @template T - The type of drag and drop manager\n * @template U - The type of modifier options\n *\n * @remarks\n * Modifiers can transform the coordinates of a drag operation,\n * enabling features like snapping, constraints, and custom behaviors.\n */\nexport class Modifier<\n  T extends DragDropManager<any, any> = DragDropManager<any, any>,\n  U extends ModifierOptions = ModifierOptions,\n> extends Plugin<T, U> {\n  /**\n   * Creates a new modifier instance.\n   *\n   * @param manager - The drag and drop manager that owns this modifier\n   * @param options - Optional configuration for the modifier\n   */\n  constructor(\n    public manager: T,\n    public options?: U\n  ) {\n    super(manager, options);\n  }\n\n  /**\n   * Applies the modifier to the current drag operation.\n   *\n   * @param operation - The current state of the drag operation\n   * @returns The transformed coordinates\n   *\n   * @remarks\n   * Override this method to implement custom transformation logic.\n   * The default implementation returns the original transform unchanged.\n   */\n  public apply(operation: DragOperationSnapshot<any, any>): Coordinates {\n    return operation.transform;\n  }\n}\n\n/**\n * Constructor type for modifiers.\n *\n * @template T - The type of drag and drop manager\n */\nexport type ModifierConstructor<\n  T extends DragDropManager<any, any> = DragDropManager<any, any>,\n> = PluginConstructor<T, Modifier<T, any>>;\n\n/**\n * Descriptor type for modifiers.\n *\n * @template T - The type of drag and drop manager\n */\nexport type ModifierDescriptor<\n  T extends DragDropManager<any, any> = DragDropManager<any, any>,\n> = PluginDescriptor<T, Modifier<T, any>, ModifierConstructor<T>>;\n\n/**\n * Array type for modifier constructors or descriptors.\n *\n * @template T - The type of drag and drop manager\n */\nexport type Modifiers<\n  T extends DragDropManager<any, any> = DragDropManager<any, any>,\n> = (ModifierConstructor<T> | ModifierDescriptor<T>)[];\n"
  },
  {
    "path": "packages/abstract/src/core/plugins/index.ts",
    "content": "export {Plugin, CorePlugin} from './plugin.ts';\nexport {PluginRegistry} from './registry.ts';\nexport type {\n  Plugins,\n  PluginConstructor,\n  PluginDescriptor,\n  PluginOptions,\n} from './types.ts';\nexport {configure, configurator, descriptor} from './utilities.ts';\n"
  },
  {
    "path": "packages/abstract/src/core/plugins/plugin.ts",
    "content": "import {\n  type CleanupFunction,\n  effect,\n  reactive,\n  untracked,\n} from '@dnd-kit/state';\n\nimport type {DragDropManager} from '../manager/index.ts';\nimport type {PluginOptions} from './types.ts';\nimport {configure} from './utilities.ts';\n\n/**\n * Base class for plugins that extend drag and drop functionality.\n *\n * @template T - The type of drag and drop manager\n * @template U - The type of plugin options\n *\n * @remarks\n * Plugins can add new features and behaviors to the drag and drop system\n * by extending this class and implementing custom functionality.\n */\nexport abstract class Plugin<\n  T extends DragDropManager<any, any> = DragDropManager<any, any>,\n  U extends PluginOptions = PluginOptions,\n> {\n  /**\n   * Creates a new plugin instance.\n   *\n   * @param manager - The drag and drop manager that owns this plugin\n   * @param options - Optional configuration for the plugin\n   */\n  constructor(\n    public manager: T,\n    public options?: U\n  ) {}\n\n  /**\n   * Whether the plugin instance is disabled.\n   *\n   * @remarks\n   * This property is reactive and triggers effects when accessed.\n   */\n  @reactive\n  public accessor disabled: boolean = false;\n\n  /**\n   * Enables a disabled plugin instance.\n   *\n   * @remarks\n   * This method triggers effects when called.\n   */\n  public enable() {\n    this.disabled = false;\n  }\n\n  /**\n   * Disables an enabled plugin instance.\n   *\n   * @remarks\n   * This method triggers effects when called.\n   */\n  public disable() {\n    this.disabled = true;\n  }\n\n  /**\n   * Checks if the plugin instance is disabled.\n   *\n   * @returns true if the plugin is disabled\n   * @remarks\n   * This method does not trigger effects when accessed.\n   */\n  public isDisabled() {\n    return untracked(() => {\n      return this.disabled;\n    });\n  }\n\n  /**\n   * Configures a plugin instance with new options.\n   *\n   * @param options - The new options to apply\n   */\n  public configure(options?: U) {\n    this.options = options;\n  }\n\n  #cleanupFunctions = new Set<CleanupFunction>();\n\n  /**\n   * Registers an effect that will be cleaned up when the plugin is destroyed.\n   *\n   * @param callback - The effect callback to register\n   * @returns A function to dispose of the effect\n   */\n  protected registerEffect(callback: () => void) {\n    const dispose = effect(callback.bind(this));\n\n    this.#cleanupFunctions.add(dispose);\n\n    return dispose;\n  }\n\n  /**\n   * Destroys a plugin instance and cleans up its resources.\n   *\n   * @remarks\n   * This method:\n   * - Calls all registered cleanup functions\n   * - Should be overridden by subclasses to clean up additional resources\n   */\n  public destroy() {\n    this.#cleanupFunctions.forEach((cleanup) => cleanup());\n  }\n\n  /**\n   * Configures a plugin constructor with options.\n   *\n   * @param options - The options to configure the constructor with\n   * @returns The configured plugin constructor\n   *\n   * @remarks\n   * This method is used to configure the options that the\n   * plugin constructor will use to create plugin instances.\n   */\n  static configure(options: PluginOptions) {\n    return configure(this as any, options);\n  }\n}\n\n/**\n * Base class for core plugins that ship with the library.\n *\n * @template T - The type of drag and drop manager\n * @template U - The type of plugin options\n */\nexport class CorePlugin<\n  T extends DragDropManager<any, any> = DragDropManager<any, any>,\n  U extends PluginOptions = PluginOptions,\n> extends Plugin<T, U> {}\n"
  },
  {
    "path": "packages/abstract/src/core/plugins/registry.ts",
    "content": "import {DragDropManager} from '../manager/index.ts';\nimport {CorePlugin, type Plugin} from './plugin.ts';\nimport type {\n  InferPluginOptions,\n  PluginDescriptor,\n  PluginConstructor,\n  Plugins,\n} from './types.ts';\nimport {descriptor} from './utilities.ts';\n\n/**\n * Manages the registration and lifecycle of plugin instances.\n *\n * @template T - The type of drag and drop manager\n * @template W - The type of plugin constructor\n * @template U - The type of plugin instance\n */\nexport class PluginRegistry<\n  T extends DragDropManager<any, any>,\n  W extends PluginConstructor<T> = PluginConstructor<T>,\n  U extends Plugin<T> = InstanceType<W>,\n> {\n  private instances: Map<W, U> = new Map();\n\n  /**\n   * Creates a new plugin registry.\n   *\n   * @param manager - The drag and drop manager that owns this registry\n   */\n  constructor(private manager: T) {}\n\n  /**\n   * Gets all registered plugin instances.\n   *\n   * @returns An array of all active plugin instances\n   */\n  public get values(): U[] {\n    return Array.from(this.instances.values());\n  }\n\n  #previousValues: PluginConstructor<T>[] = [];\n\n  /**\n   * Sets the list of plugins to be used by the registry.\n   *\n   * @param entries - Array of plugin constructors or descriptors\n   * @remarks\n   * This method:\n   * - Filters out duplicate plugins\n   * - Unregisters plugins that are no longer in use\n   * - Registers new plugins with their options\n   */\n  public set values(entries: Plugins<T>) {\n    const descriptors = entries\n      .map(descriptor)\n      .reduce<PluginDescriptor<T>[]>((acc, descriptor) => {\n        const existing = acc.find(({plugin}) => plugin === descriptor.plugin);\n\n        if (existing) {\n          // Keep the first occurrence's position, apply latest options\n          existing.options = descriptor.options;\n          return acc;\n        }\n\n        return [...acc, descriptor];\n      }, []);\n    const constructors = descriptors.map(({plugin}) => plugin);\n\n    for (const plugin of this.#previousValues) {\n      if (!constructors.includes(plugin)) {\n        if (plugin.prototype instanceof CorePlugin) {\n          continue;\n        }\n\n        this.unregister(plugin as W);\n      }\n    }\n\n    for (const {plugin, options} of descriptors) {\n      this.register(plugin as W, options as InferPluginOptions<W>);\n    }\n\n    this.#previousValues = constructors;\n  }\n\n  /**\n   * Gets a plugin instance by its constructor.\n   *\n   * @param plugin - The plugin constructor to look up\n   * @returns The plugin instance or undefined if not found\n   */\n  public get<X extends W>(plugin: X): InstanceType<X> | undefined {\n    const instance = this.instances.get(plugin);\n\n    return instance as any;\n  }\n\n  /**\n   * Registers a new plugin instance.\n   *\n   * @param plugin - The plugin constructor to register\n   * @param options - Optional configuration for the plugin\n   * @returns The registered plugin instance\n   * @remarks\n   * If the plugin is already registered, its options will be updated\n   * and the existing instance will be returned.\n   */\n  public register<X extends W>(\n    plugin: X,\n    options?: InferPluginOptions<X>\n  ): InstanceType<X> {\n    const existingInstance = this.instances.get(plugin);\n\n    if (existingInstance) {\n      if (existingInstance.options !== options) {\n        existingInstance.options = options;\n      }\n\n      return existingInstance as InstanceType<X>;\n    }\n\n    const instance = new plugin(this.manager, options) as U;\n\n    this.instances.set(plugin, instance);\n\n    return instance as InstanceType<X>;\n  }\n\n  /**\n   * Unregisters a plugin instance.\n   *\n   * @param plugin - The plugin constructor to unregister\n   * @remarks\n   * This method:\n   * - Destroys the plugin instance\n   * - Removes it from the registry\n   */\n  public unregister<X extends W>(plugin: X) {\n    const instance = this.instances.get(plugin);\n\n    if (instance) {\n      instance.destroy();\n      this.instances.delete(plugin);\n    }\n  }\n\n  /**\n   * Destroys all registered plugin instances.\n   *\n   * @remarks\n   * This method:\n   * - Calls destroy() on all plugin instances\n   * - Clears the registry\n   */\n  public destroy() {\n    for (const plugin of this.instances.values()) {\n      plugin.destroy();\n    }\n\n    this.instances.clear();\n  }\n}\n"
  },
  {
    "path": "packages/abstract/src/core/plugins/types.ts",
    "content": "import type {DragDropManager} from '../manager/index.ts';\nimport type {Plugin} from './plugin.ts';\n\n/** Base type for plugin options */\nexport type PluginOptions = Record<string, any>;\n\n/**\n * Constructor type for plugins.\n *\n * @template T - The type of drag and drop manager\n * @template U - The type of plugin instance\n * @template V - The type of plugin options\n */\nexport interface PluginConstructor<\n  T extends DragDropManager<any, any> = DragDropManager<any, any>,\n  U extends Plugin<T> = Plugin<T>,\n  V extends PluginOptions = InferPluginOptions<U>,\n> {\n  /** Creates a new plugin instance */\n  new (manager: T, options?: V): U;\n}\n\n/**\n * Descriptor type for plugins.\n *\n * @template T - The type of drag and drop manager\n * @template U - The type of plugin instance\n * @template V - The type of plugin constructor\n */\nexport type PluginDescriptor<\n  T extends DragDropManager<any, any> = DragDropManager<any, any>,\n  U extends Plugin<T> = Plugin<T>,\n  V extends PluginConstructor<T, U> = PluginConstructor<T, U>,\n> = {\n  /** The plugin constructor */\n  plugin: V;\n  /** Optional configuration for the plugin */\n  options?: InferPluginOptions<U>;\n};\n\n/**\n * Array type for plugin constructors or descriptors.\n *\n * @template T - The type of drag and drop manager\n */\nexport type Plugins<\n  T extends DragDropManager<any, any> = DragDropManager<any, any>,\n> = (PluginConstructor<T> | PluginDescriptor<T>)[];\n\n/**\n * Infers the options type from a plugin constructor or instance.\n *\n * @template P - The plugin constructor or instance type\n */\nexport type InferPluginOptions<P> =\n  P extends PluginConstructor<any, any, infer T>\n    ? T\n    : P extends Plugin<any, infer T>\n      ? T\n      : never;\n\n/**\n * Infers the manager type from a plugin instance.\n *\n * @template P - The plugin instance type\n */\nexport type InferManager<P> =\n  P extends Plugin<infer T extends DragDropManager<any, any>> ? T : never;\n"
  },
  {
    "path": "packages/abstract/src/core/plugins/utilities.ts",
    "content": "import type {\n  PluginConstructor,\n  PluginOptions,\n  PluginDescriptor,\n  InferPluginOptions,\n} from './types.ts';\n\n/**\n * Creates a plugin descriptor with the given plugin constructor and options.\n *\n * @template T - The plugin constructor type\n * @template V - The plugin options type\n * @param plugin - The plugin constructor\n * @param options - The plugin configuration options\n * @returns A plugin descriptor containing the constructor and options\n */\nexport function configure<\n  T extends PluginConstructor<any, any, any>,\n  V extends PluginOptions = InferPluginOptions<T>,\n>(plugin: T, options: V): PluginDescriptor<any, any, T> {\n  return {\n    plugin,\n    options,\n  };\n}\n\n/**\n * Creates a configurator function for a specific plugin constructor.\n *\n * @template T - The plugin constructor type\n * @param plugin - The plugin constructor to configure\n * @returns A function that takes options and returns a plugin descriptor\n */\nexport function configurator<T extends PluginConstructor<any, any, any>>(\n  plugin: T\n) {\n  return (options: InferPluginOptions<T>): PluginDescriptor<any, any, T> => {\n    return configure(plugin, options);\n  };\n}\n\n/**\n * Normalizes a plugin constructor or descriptor into a descriptor.\n *\n * @template T - The plugin constructor type\n * @param plugin - Either a plugin constructor or a plugin descriptor\n * @returns A plugin descriptor\n */\nexport function descriptor<T extends PluginConstructor<any, any, any>>(\n  plugin: T | PluginDescriptor<any, any, T>\n): PluginDescriptor<any, any, T> {\n  if (typeof plugin === 'function') {\n    return {\n      plugin,\n      options: undefined,\n    };\n  }\n\n  return plugin;\n}\n"
  },
  {
    "path": "packages/abstract/src/core/sensors/activation.ts",
    "content": "export class ActivationController<E extends Event> extends AbortController {\n  public activated = false;\n\n  constructor(\n    private constraints: ActivationConstraints<E> | undefined,\n    private onActivate: (event: E) => void\n  ) {\n    super();\n\n    for (const constraint of constraints ?? []) {\n      constraint.controller = this;\n    }\n  }\n\n  onEvent(event: E) {\n    if (this.activated) return;\n\n    if (this.constraints?.length) {\n      for (const constraint of this.constraints) {\n        constraint.onEvent(event);\n      }\n    } else {\n      this.activate(event);\n    }\n  }\n\n  activate(event: E) {\n    if (this.activated) return;\n    this.activated = true;\n    this.onActivate(event);\n  }\n\n  abort(event?: E) {\n    this.activated = false;\n\n    super.abort(event);\n  }\n}\n\nexport interface ActivationConstraintOptions {}\n\nexport abstract class ActivationConstraint<\n  E extends Event = Event,\n  O extends ActivationConstraintOptions = ActivationConstraintOptions,\n> {\n  #controller: ActivationController<E> | undefined;\n\n  set controller(controller: ActivationController<E>) {\n    this.#controller = controller;\n\n    controller.signal.addEventListener('abort', () => this.abort());\n  }\n\n  constructor(protected options: O) {}\n\n  /**\n   * Called when the activation is triggered.\n   */\n  public activate(event: E): void {\n    this.#controller?.activate(event);\n  }\n\n  /**\n   * Called when the activation is aborted.\n   */\n  public abstract abort(event?: E): void;\n\n  /**\n   * Called when an input event is received by the sensor.\n   * Returns `true` if this event triggers activation immediately.\n   */\n  public abstract onEvent(event: E): void;\n}\n\nexport type ActivationConstraints<E extends Event> = ActivationConstraint<E>[];\n"
  },
  {
    "path": "packages/abstract/src/core/sensors/index.ts",
    "content": "export {Sensor} from './sensor.ts';\nexport type {\n  Sensors,\n  SensorConstructor,\n  SensorDescriptor,\n  SensorOptions,\n} from './sensor.ts';\n\nexport {\n  ActivationConstraint,\n  type ActivationConstraints,\n} from './activation.ts';\nexport {ActivationController} from './activation.ts';\n"
  },
  {
    "path": "packages/abstract/src/core/sensors/sensor.ts",
    "content": "import {CleanupFunction} from '@dnd-kit/state';\n\nimport type {DragDropManager} from '../manager/index.ts';\nimport type {Draggable, Droppable} from '../entities/index.ts';\nimport {\n  Plugin,\n  type PluginConstructor,\n  type PluginDescriptor,\n  type PluginOptions,\n} from '../plugins/index.ts';\n\n/**\n * Options that can be passed to a sensor.\n * Extends the base PluginOptions type.\n */\nexport type SensorOptions = PluginOptions;\n\n/**\n * Abstract base class for all sensor implementations.\n *\n * @template T - The type of drag drop manager\n * @template U - The type of sensor options\n *\n * @remarks\n * Sensors are responsible for detecting and initiating drag operations.\n * They handle the actual user interaction (mouse, touch, keyboard, etc.)\n * and translate those interactions into drag operations.\n */\nexport abstract class Sensor<\n  T extends DragDropManager<any, any> = DragDropManager<Draggable, Droppable>,\n  U extends SensorOptions = SensorOptions,\n> extends Plugin<T, U> {\n  /**\n   * Creates a new sensor instance.\n   *\n   * @param manager - The drag drop manager instance\n   * @param options - Optional sensor configuration\n   */\n  constructor(\n    public manager: T,\n    public options?: U\n  ) {\n    super(manager, options);\n  }\n\n  /**\n   * Binds the sensor to a draggable source.\n   *\n   * @param source - The draggable element to bind to\n   * @param options - Optional sensor options specific to this draggable\n   * @returns A cleanup function to unbind the sensor\n   */\n  public abstract bind(source: Draggable, options?: U): CleanupFunction;\n}\n\n/**\n * Constructor type for creating sensor instances.\n *\n * @template T - The type of drag drop manager\n */\nexport type SensorConstructor<\n  T extends DragDropManager<any, any> = DragDropManager<any, any>,\n> = PluginConstructor<T, Sensor<T>>;\n\n/**\n * Descriptor type for configuring sensors.\n *\n * @template T - The type of drag drop manager\n */\nexport type SensorDescriptor<\n  T extends DragDropManager<any, any> = DragDropManager<any, any>,\n> = PluginDescriptor<T, Sensor<T>, SensorConstructor<T>>;\n\n/**\n * Array type for multiple sensor configurations.\n *\n * @template T - The type of drag drop manager\n */\nexport type Sensors<\n  T extends DragDropManager<any, any> = DragDropManager<any, any>,\n> = (SensorConstructor<T> | SensorDescriptor<T>)[];\n"
  },
  {
    "path": "packages/abstract/src/modifiers/axis.ts",
    "content": "import {\n  configurator,\n  Modifier,\n  type DragDropManager,\n  type DragOperation,\n} from '@dnd-kit/abstract';\n\n/**\n * Options for configuring an axis modifier.\n *\n * @property axis - The axis to restrict movement to ('x' or 'y')\n * @property value - The fixed value to set for the specified axis\n */\ninterface Options {\n  axis: 'x' | 'y';\n  value: number;\n}\n\n/**\n * A modifier that restricts drag movement to a specific axis and value.\n *\n * @remarks\n * This modifier can be used to:\n * - Restrict movement to a specific axis\n * - Set a fixed value for the specified axis\n * - Create horizontal or vertical movement constraints\n */\nexport class AxisModifier extends Modifier<DragDropManager<any, any>, Options> {\n  /**\n   * Applies the axis restriction to the drag operation.\n   *\n   * @param operation - The current drag operation\n   * @returns The modified transform with the axis restriction applied\n   */\n  apply({transform}: DragOperation) {\n    if (!this.options) {\n      return transform;\n    }\n\n    const {axis, value} = this.options;\n\n    return {\n      ...transform,\n      [axis]: value,\n    };\n  }\n\n  /**\n   * Creates a configured instance of the AxisModifier.\n   *\n   * @param options - The axis restriction options\n   * @returns A configured AxisModifier instance\n   */\n  static configure = configurator(AxisModifier);\n}\n\n/**\n * A pre-configured modifier that restricts movement to the vertical axis.\n *\n * @remarks\n * This modifier fixes the x-axis value to 0, allowing only vertical movement.\n */\nexport const RestrictToVerticalAxis = AxisModifier.configure({\n  axis: 'x',\n  value: 0,\n});\n\n/**\n * A pre-configured modifier that restricts movement to the horizontal axis.\n *\n * @remarks\n * This modifier fixes the y-axis value to 0, allowing only horizontal movement.\n */\nexport const RestrictToHorizontalAxis = AxisModifier.configure({\n  axis: 'y',\n  value: 0,\n});\n"
  },
  {
    "path": "packages/abstract/src/modifiers/boundingRectangle.ts",
    "content": "import type {BoundingRectangle, Coordinates, Shape} from '@dnd-kit/geometry';\n\n/**\n * Restricts a shape's movement to stay within a bounding rectangle.\n *\n * @param shape - The shape to restrict\n * @param transform - The current transform coordinates\n * @param boundingRect - The bounding rectangle to restrict movement within\n * @returns The modified transform coordinates that keep the shape within bounds\n *\n * @remarks\n * This function:\n * - Prevents the shape from moving outside the bounding rectangle\n * - Adjusts the transform coordinates to keep the shape's edges within bounds\n * - Maintains the shape's position relative to the bounding rectangle\n *\n * @example\n * ```typescript\n * const shape = { boundingRectangle: { top: 0, left: 0, right: 100, bottom: 100 } };\n * const transform = { x: 50, y: 50 };\n * const bounds = { top: 0, left: 0, width: 200, height: 200 };\n *\n * const restricted = restrictShapeToBoundingRectangle(shape, transform, bounds);\n * ```\n */\nexport function restrictShapeToBoundingRectangle(\n  shape: Shape,\n  transform: Coordinates,\n  boundingRect: BoundingRectangle\n) {\n  const value = {\n    ...transform,\n  };\n\n  if (shape.boundingRectangle.top + transform.y <= boundingRect.top) {\n    value.y = boundingRect.top - shape.boundingRectangle.top;\n  } else if (\n    shape.boundingRectangle.bottom + transform.y >=\n    boundingRect.top + boundingRect.height\n  ) {\n    value.y =\n      boundingRect.top + boundingRect.height - shape.boundingRectangle.bottom;\n  }\n\n  if (shape.boundingRectangle.left + transform.x <= boundingRect.left) {\n    value.x = boundingRect.left - shape.boundingRectangle.left;\n  } else if (\n    shape.boundingRectangle.right + transform.x >=\n    boundingRect.left + boundingRect.width\n  ) {\n    value.x =\n      boundingRect.left + boundingRect.width - shape.boundingRectangle.right;\n  }\n\n  return value;\n}\n"
  },
  {
    "path": "packages/abstract/src/modifiers/index.ts",
    "content": "export {\n  AxisModifier,\n  RestrictToHorizontalAxis,\n  RestrictToVerticalAxis,\n} from './axis.ts';\n\nexport {restrictShapeToBoundingRectangle} from './boundingRectangle.ts';\n\nexport {SnapModifier} from './snap.ts';\n"
  },
  {
    "path": "packages/abstract/src/modifiers/snap.ts",
    "content": "import {\n  configurator,\n  Modifier,\n  type DragDropManager,\n  type DragOperation,\n} from '@dnd-kit/abstract';\n\n/**\n * Options for configuring a snap modifier.\n *\n * @property size - The grid size to snap to, either a single number for both axes\n *                 or separate x and y values\n */\ninterface Options {\n  size: number | {x: number; y: number};\n}\n\n/**\n * A modifier that snaps drag movement to a grid.\n *\n * @remarks\n * This modifier:\n * - Snaps drag coordinates to the nearest grid point\n * - Supports different grid sizes for x and y axes\n * - Uses ceiling rounding to ensure consistent snapping behavior\n *\n * @example\n * ```typescript\n * // Snap to a 20x20 grid\n * const modifier = SnapModifier.configure({ size: 20 });\n *\n * // Snap to a 10x20 grid\n * const modifier = SnapModifier.configure({ size: { x: 10, y: 20 } });\n * ```\n */\nexport class SnapModifier extends Modifier<DragDropManager<any, any>, Options> {\n  /**\n   * Applies the snap grid to the drag operation.\n   *\n   * @param operation - The current drag operation\n   * @returns The modified transform with coordinates snapped to the grid\n   */\n  apply({transform}: DragOperation) {\n    const {size = 20} = this.options ?? {};\n    const x = typeof size === 'number' ? size : size.x;\n    const y = typeof size === 'number' ? size : size.y;\n\n    return {\n      ...transform,\n      x: Math.ceil(transform.x / x) * x,\n      y: Math.ceil(transform.y / y) * y,\n    };\n  }\n\n  /**\n   * Creates a configured instance of the SnapModifier.\n   *\n   * @param options - The snap grid options\n   * @returns A configured SnapModifier instance\n   */\n  static configure = configurator(SnapModifier);\n}\n"
  },
  {
    "path": "packages/abstract/tests/manager-modifiers.test.ts",
    "content": "import {describe, expect, it} from 'bun:test';\nimport {batch} from '@dnd-kit/state';\nimport {\n  DragDropManager,\n  Modifier,\n  Draggable,\n  configure,\n} from '@dnd-kit/abstract';\n\nclass ClampXModifier extends Modifier {\n  public apply(operation: Parameters<Modifier['apply']>[0]) {\n    return {x: 0, y: operation.transform.y};\n  }\n}\n\nclass ClampYModifier extends Modifier {\n  public apply(operation: Parameters<Modifier['apply']>[0]) {\n    return {x: operation.transform.x, y: 0};\n  }\n}\n\n/** Flush microtasks so async stop/reset logic completes */\nfunction flush() {\n  return new Promise((resolve) => setTimeout(resolve, 10));\n}\n\ndescribe('Manager-level modifiers', () => {\n  it('should apply manager modifiers when draggable has none', () => {\n    const manager = new DragDropManager({modifiers: [ClampXModifier]});\n    const draggable = new Draggable({id: 'd1', register: false}, manager);\n    draggable.register();\n\n    manager.actions.start({source: draggable, coordinates: {x: 0, y: 0}});\n    batch(() => {\n      manager.dragOperation.position.current = {x: 100, y: 50};\n    });\n\n    expect(manager.dragOperation.transform).toEqual({x: 0, y: 50});\n\n    draggable.destroy();\n    manager.destroy();\n  });\n\n  it('should apply configured manager modifiers', () => {\n    const manager = new DragDropManager({\n      modifiers: [configure(ClampXModifier, undefined)],\n    });\n    const draggable = new Draggable({id: 'd1', register: false}, manager);\n    draggable.register();\n\n    manager.actions.start({source: draggable, coordinates: {x: 0, y: 0}});\n    batch(() => {\n      manager.dragOperation.position.current = {x: 100, y: 50};\n    });\n\n    expect(manager.dragOperation.transform).toEqual({x: 0, y: 50});\n\n    draggable.destroy();\n    manager.destroy();\n  });\n\n  it('should prefer draggable modifiers over manager modifiers', () => {\n    const manager = new DragDropManager({modifiers: [ClampXModifier]});\n    const draggable = new Draggable(\n      {id: 'd1', modifiers: [ClampYModifier], register: false},\n      manager\n    );\n    draggable.register();\n\n    manager.actions.start({source: draggable, coordinates: {x: 0, y: 0}});\n    batch(() => {\n      manager.dragOperation.position.current = {x: 100, y: 50};\n    });\n\n    expect(manager.dragOperation.transform).toEqual({x: 100, y: 0});\n\n    draggable.destroy();\n    manager.destroy();\n  });\n});\n\ndescribe('Manager modifier lifecycle', () => {\n  it('should not destroy manager modifiers when drag starts', () => {\n    let destroyCount = 0;\n\n    class TrackedModifier extends ClampXModifier {\n      public destroy() {\n        destroyCount++;\n        super.destroy();\n      }\n    }\n\n    const manager = new DragDropManager({modifiers: [TrackedModifier]});\n    const draggable = new Draggable({id: 'd1', register: false}, manager);\n    draggable.register();\n\n    manager.actions.start({source: draggable, coordinates: {x: 0, y: 0}});\n\n    expect(destroyCount).toBe(0);\n\n    draggable.destroy();\n    manager.destroy();\n  });\n\n  it('should not destroy manager modifiers when drag stops', async () => {\n    let destroyCount = 0;\n\n    class TrackedModifier extends ClampXModifier {\n      public destroy() {\n        destroyCount++;\n        super.destroy();\n      }\n    }\n\n    const manager = new DragDropManager({modifiers: [TrackedModifier]});\n    const draggable = new Draggable({id: 'd1', register: false}, manager);\n    draggable.register();\n\n    manager.actions.start({source: draggable, coordinates: {x: 0, y: 0}});\n    manager.actions.stop();\n    await flush();\n\n    expect(destroyCount).toBe(0);\n\n    draggable.destroy();\n    manager.destroy();\n  });\n\n  it('should keep manager modifiers working across multiple drags', async () => {\n    const manager = new DragDropManager({modifiers: [ClampXModifier]});\n    const draggable = new Draggable({id: 'd1', register: false}, manager);\n    draggable.register();\n\n    // First drag\n    manager.actions.start({source: draggable, coordinates: {x: 0, y: 0}});\n    batch(() => {\n      manager.dragOperation.position.current = {x: 100, y: 50};\n    });\n    expect(manager.dragOperation.transform).toEqual({x: 0, y: 50});\n\n    manager.actions.stop();\n    await flush();\n\n    // Second drag — manager modifiers must still be active\n    manager.actions.start({source: draggable, coordinates: {x: 0, y: 0}});\n    batch(() => {\n      manager.dragOperation.position.current = {x: 200, y: 75};\n    });\n    expect(manager.dragOperation.transform).toEqual({x: 0, y: 75});\n\n    draggable.destroy();\n    manager.destroy();\n  });\n\n  it('should destroy per-operation modifiers when draggable modifiers change mid-drag', () => {\n    let destroyCount = 0;\n\n    class TrackedModifier extends ClampXModifier {\n      public destroy() {\n        destroyCount++;\n        super.destroy();\n      }\n    }\n\n    const manager = new DragDropManager({});\n    const draggable = new Draggable(\n      {id: 'd1', modifiers: [TrackedModifier], register: false},\n      manager\n    );\n    draggable.register();\n\n    manager.actions.start({source: draggable, coordinates: {x: 0, y: 0}});\n    expect(destroyCount).toBe(0);\n\n    // Changing the draggable's modifiers mid-drag triggers the effect,\n    // which should destroy the old per-operation instances\n    draggable.modifiers = [ClampYModifier];\n\n    expect(destroyCount).toBe(1);\n\n    draggable.destroy();\n    manager.destroy();\n  });\n\n  it('should destroy per-operation modifiers when switching to manager modifiers mid-drag', () => {\n    let destroyCount = 0;\n\n    class TrackedModifier extends ClampXModifier {\n      public destroy() {\n        destroyCount++;\n        super.destroy();\n      }\n    }\n\n    const manager = new DragDropManager({modifiers: [ClampYModifier]});\n    const draggable = new Draggable(\n      {id: 'd1', modifiers: [TrackedModifier], register: false},\n      manager\n    );\n    draggable.register();\n\n    manager.actions.start({source: draggable, coordinates: {x: 0, y: 0}});\n    expect(destroyCount).toBe(0);\n\n    // Removing draggable modifiers should fall back to manager modifiers\n    // and destroy the per-operation instances\n    draggable.modifiers = undefined;\n\n    expect(destroyCount).toBe(1);\n\n    // Manager modifiers should now be active\n    batch(() => {\n      manager.dragOperation.position.current = {x: 100, y: 50};\n    });\n    expect(manager.dragOperation.transform).toEqual({x: 100, y: 0});\n\n    draggable.destroy();\n    manager.destroy();\n  });\n\n  it('should not destroy manager modifiers when different draggables are used', async () => {\n    let destroyCount = 0;\n\n    class TrackedModifier extends ClampXModifier {\n      public destroy() {\n        destroyCount++;\n        super.destroy();\n      }\n    }\n\n    const manager = new DragDropManager({modifiers: [TrackedModifier]});\n    const draggableA = new Draggable({id: 'a', register: false}, manager);\n    const draggableB = new Draggable({id: 'b', register: false}, manager);\n    draggableA.register();\n    draggableB.register();\n\n    // First drag with draggable A\n    manager.actions.start({source: draggableA, coordinates: {x: 0, y: 0}});\n    manager.actions.stop();\n    await flush();\n\n    expect(destroyCount).toBe(0);\n\n    // Second drag with draggable B\n    manager.actions.start({source: draggableB, coordinates: {x: 0, y: 0}});\n    batch(() => {\n      manager.dragOperation.position.current = {x: 100, y: 50};\n    });\n    expect(manager.dragOperation.transform).toEqual({x: 0, y: 50});\n    expect(destroyCount).toBe(0);\n\n    draggableA.destroy();\n    draggableB.destroy();\n    manager.destroy();\n  });\n});\n"
  },
  {
    "path": "packages/abstract/tests/plugin-registry.test.ts",
    "content": "import {describe, expect, it} from 'bun:test';\nimport {batch} from '@dnd-kit/state';\nimport {\n  DragDropManager,\n  Draggable,\n  Plugin,\n  CorePlugin,\n  configure,\n} from '@dnd-kit/abstract';\n\ninterface TestOptions {\n  value?: string;\n}\n\nclass PluginA extends Plugin {\n  constructor(manager: DragDropManager, public options?: TestOptions) {\n    super(manager, options);\n  }\n}\n\nclass PluginB extends Plugin {\n  constructor(manager: DragDropManager, public options?: TestOptions) {\n    super(manager, options);\n  }\n}\n\nclass PluginC extends CorePlugin {\n  constructor(manager: DragDropManager, public options?: TestOptions) {\n    super(manager, options);\n  }\n}\n\nfunction indexOf(manager: DragDropManager, PluginClass: any): number {\n  return manager.registry.plugins.values.findIndex(\n    (p) => p.constructor === PluginClass\n  );\n}\n\ndescribe('PluginRegistry duplicate handling', () => {\n  it('should keep the first occurrence when duplicates exist', () => {\n    const manager = new DragDropManager({\n      plugins: [PluginA, PluginB, PluginA],\n    });\n\n    const pluginA = manager.registry.plugins.get(PluginA);\n    const pluginB = manager.registry.plugins.get(PluginB);\n\n    expect(pluginA).toBeInstanceOf(PluginA);\n    expect(pluginB).toBeInstanceOf(PluginB);\n    expect(indexOf(manager, PluginA)).toBeLessThan(indexOf(manager, PluginB));\n\n    manager.destroy();\n  });\n\n  it('should apply options from the last occurrence to the first position', () => {\n    const manager = new DragDropManager({\n      plugins: [PluginA, PluginB, configure(PluginA, {value: 'custom'})],\n    });\n\n    const pluginA = manager.registry.plugins.get(PluginA);\n\n    expect(pluginA).toBeDefined();\n    expect(pluginA!.options).toEqual({value: 'custom'});\n    expect(indexOf(manager, PluginA)).toBeLessThan(indexOf(manager, PluginB));\n\n    manager.destroy();\n  });\n\n  it('should preserve registration order so earlier plugins are available to later ones', () => {\n    let resolvedDep: Plugin | undefined;\n\n    class DepPlugin extends Plugin {\n      constructor(manager: DragDropManager) {\n        super(manager);\n      }\n    }\n\n    class ConsumerPlugin extends Plugin {\n      constructor(manager: DragDropManager) {\n        super(manager);\n        resolvedDep = manager.registry.plugins.get(DepPlugin);\n      }\n    }\n\n    const manager = new DragDropManager({\n      plugins: [DepPlugin, ConsumerPlugin, configure(DepPlugin, {value: 'x'})],\n    });\n\n    expect(resolvedDep).toBeInstanceOf(DepPlugin);\n\n    manager.destroy();\n  });\n\n  it('should handle configure with empty options', () => {\n    const manager = new DragDropManager({\n      plugins: [PluginA, PluginB, configure(PluginA, {})],\n    });\n\n    const pluginA = manager.registry.plugins.get(PluginA);\n\n    expect(pluginA).toBeDefined();\n    expect(pluginA!.options).toEqual({});\n    expect(indexOf(manager, PluginA)).toBeLessThan(indexOf(manager, PluginB));\n\n    manager.destroy();\n  });\n\n  it('should not create duplicate instances when the same plugin appears multiple times', () => {\n    let instanceCount = 0;\n\n    class TrackedPlugin extends Plugin {\n      constructor(manager: DragDropManager) {\n        super(manager);\n        instanceCount++;\n      }\n    }\n\n    const manager = new DragDropManager({\n      plugins: [TrackedPlugin, PluginB, configure(TrackedPlugin, {value: 'x'})],\n    });\n\n    expect(instanceCount).toBe(1);\n\n    manager.destroy();\n  });\n\n  it('should apply the rightmost options when a plugin appears more than twice', () => {\n    const manager = new DragDropManager({\n      plugins: [\n        configure(PluginA, {value: 'first'}),\n        PluginB,\n        configure(PluginA, {value: 'second'}),\n        configure(PluginA, {value: 'third'}),\n      ],\n    });\n\n    const pluginA = manager.registry.plugins.get(PluginA);\n\n    expect(pluginA!.options).toEqual({value: 'third'});\n    expect(indexOf(manager, PluginA)).toBeLessThan(indexOf(manager, PluginB));\n\n    manager.destroy();\n  });\n});\n\ndescribe('Per-entity plugin auto-registration', () => {\n  it('should auto-register plugins from entity plugins array', () => {\n    const manager = new DragDropManager({});\n    const draggable = new Draggable(\n      {id: 'd1', plugins: [PluginA], register: false},\n      manager\n    );\n    draggable.register();\n\n    expect(manager.registry.plugins.get(PluginA)).toBeInstanceOf(PluginA);\n\n    draggable.destroy();\n    manager.destroy();\n  });\n\n  it('should auto-register configured plugins without applying entity options globally', () => {\n    const manager = new DragDropManager({});\n    const draggable = new Draggable(\n      {\n        id: 'd1',\n        plugins: [configure(PluginA, {value: 'entity-only'})],\n        register: false,\n      },\n      manager\n    );\n    draggable.register();\n\n    const globalInstance = manager.registry.plugins.get(PluginA);\n    expect(globalInstance).toBeInstanceOf(PluginA);\n    expect(globalInstance!.options).toBeUndefined();\n\n    draggable.destroy();\n    manager.destroy();\n  });\n\n  it('should not duplicate-register already-registered plugins', () => {\n    let instanceCount = 0;\n\n    class TrackedPlugin extends Plugin {\n      constructor(manager: DragDropManager) {\n        super(manager);\n        instanceCount++;\n      }\n    }\n\n    const manager = new DragDropManager({plugins: [TrackedPlugin]});\n    expect(instanceCount).toBe(1);\n\n    const draggable = new Draggable(\n      {id: 'd1', plugins: [TrackedPlugin], register: false},\n      manager\n    );\n    draggable.register();\n\n    expect(instanceCount).toBe(1);\n\n    draggable.destroy();\n    manager.destroy();\n  });\n\n  it('should keep auto-registered plugin alive after source entity is destroyed mid-drag', async () => {\n    const manager = new DragDropManager({});\n    const draggable = new Draggable(\n      {id: 'd1', plugins: [PluginA], register: false},\n      manager\n    );\n    draggable.register();\n\n    manager.actions.start({source: draggable, coordinates: {x: 0, y: 0}});\n\n    expect(manager.registry.plugins.get(PluginA)).toBeInstanceOf(PluginA);\n\n    draggable.destroy();\n\n    expect(manager.registry.plugins.get(PluginA)).toBeInstanceOf(PluginA);\n\n    manager.actions.stop();\n    await new Promise((resolve) => setTimeout(resolve, 10));\n    manager.destroy();\n  });\n});\n\ndescribe('Per-entity plugin config (pluginConfig)', () => {\n  it('should return per-entity options for a configured plugin', () => {\n    const manager = new DragDropManager({});\n    const draggable = new Draggable(\n      {\n        id: 'd1',\n        plugins: [configure(PluginA, {value: 'custom'})],\n        register: false,\n      },\n      manager\n    );\n\n    expect(draggable.pluginConfig(PluginA)).toEqual({value: 'custom'});\n\n    draggable.destroy();\n    manager.destroy();\n  });\n\n  it('should return undefined for unconfigured plugins', () => {\n    const manager = new DragDropManager({});\n    const draggable = new Draggable({id: 'd1', register: false}, manager);\n\n    expect(draggable.pluginConfig(PluginA)).toBeUndefined();\n\n    draggable.destroy();\n    manager.destroy();\n  });\n\n  it('should return undefined when entity has no plugins even if plugin is registered globally', () => {\n    const manager = new DragDropManager({plugins: [PluginA]});\n    const draggable = new Draggable({id: 'd1', register: false}, manager);\n\n    expect(manager.registry.plugins.get(PluginA)).toBeInstanceOf(PluginA);\n    expect(draggable.pluginConfig(PluginA)).toBeUndefined();\n\n    draggable.destroy();\n    manager.destroy();\n  });\n\n  it('should isolate per-entity config between different entities', () => {\n    const manager = new DragDropManager({});\n    const draggableA = new Draggable(\n      {\n        id: 'a',\n        plugins: [configure(PluginA, {value: 'alpha'})],\n        register: false,\n      },\n      manager\n    );\n    const draggableB = new Draggable(\n      {\n        id: 'b',\n        plugins: [configure(PluginA, {value: 'beta'})],\n        register: false,\n      },\n      manager\n    );\n    draggableA.register();\n    draggableB.register();\n\n    expect(draggableA.pluginConfig(PluginA)).toEqual({value: 'alpha'});\n    expect(draggableB.pluginConfig(PluginA)).toEqual({value: 'beta'});\n\n    const globalInstance = manager.registry.plugins.get(PluginA);\n    expect(globalInstance!.options).toBeUndefined();\n\n    draggableA.destroy();\n    draggableB.destroy();\n    manager.destroy();\n  });\n\n  it('should return per-entity options even when plugin is globally configured with different options', () => {\n    const manager = new DragDropManager({\n      plugins: [configure(PluginA, {value: 'global'})],\n    });\n    const draggable = new Draggable(\n      {\n        id: 'd1',\n        plugins: [configure(PluginA, {value: 'entity'})],\n        register: false,\n      },\n      manager\n    );\n\n    expect(draggable.pluginConfig(PluginA)).toEqual({value: 'entity'});\n    expect(manager.registry.plugins.get(PluginA)!.options).toEqual({\n      value: 'global',\n    });\n\n    draggable.destroy();\n    manager.destroy();\n  });\n\n  it('should reflect updated options when plugins property is reassigned', () => {\n    const manager = new DragDropManager({});\n    const draggable = new Draggable(\n      {\n        id: 'd1',\n        plugins: [configure(PluginA, {value: 'first'})],\n        register: false,\n      },\n      manager\n    );\n\n    expect(draggable.pluginConfig(PluginA)).toEqual({value: 'first'});\n\n    draggable.plugins = [configure(PluginA, {value: 'second'})];\n\n    expect(draggable.pluginConfig(PluginA)).toEqual({value: 'second'});\n\n    draggable.destroy();\n    manager.destroy();\n  });\n});\n"
  },
  {
    "path": "packages/abstract/tsconfig.json",
    "content": "{\n  \"extends\": \"../../config/typescript/vanilla.json\",\n  \"include\": [\"src/**/*\"],\n  \"exclude\": [\"dist\", \"build\", \"node_modules\"]\n}\n"
  },
  {
    "path": "packages/abstract/tsup.config.ts",
    "content": "import {defineConfig} from 'tsup';\n\nexport default defineConfig((options) => ({\n  dts: true,\n  outDir: './',\n  external: ['@dnd-kit/abstract'],\n  format: ['esm', 'cjs'],\n  sourcemap: true,\n  treeshake: !options.watch,\n}));\n"
  },
  {
    "path": "packages/collision/CHANGELOG.md",
    "content": "# @dnd-kit/collision\n\n## 0.3.2\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/abstract@0.3.2\n  - @dnd-kit/geometry@0.3.2\n\n## 0.3.1\n\n### Patch Changes\n\n- Updated dependencies [[`4341114`](https://github.com/clauderic/dnd-kit/commit/43411143063349caeded4f778923473624ce25cf)]:\n  - @dnd-kit/abstract@0.3.1\n  - @dnd-kit/geometry@0.3.1\n\n## 0.3.0\n\n### Patch Changes\n\n- Updated dependencies [[`6a59647`](https://github.com/clauderic/dnd-kit/commit/6a59647ebba2114b2e423f282ab25bf2ea40318d)]:\n  - @dnd-kit/abstract@0.3.0\n  - @dnd-kit/geometry@0.3.0\n\n## 0.2.4\n\n### Patch Changes\n\n- [#1866](https://github.com/clauderic/dnd-kit/pull/1866) [`256432d`](https://github.com/clauderic/dnd-kit/commit/256432dec8823342765eebdb78ee791c25fea382) Thanks [@github-actions](https://github.com/apps/github-actions)! - **directionBiased**: Fix inverted logic to bias towards shapes above or below the drag operation shape.\n\n- Updated dependencies [[`de27fbc`](https://github.com/clauderic/dnd-kit/commit/de27fbca9df12eece3cd53ccbbac34e0eaf113e1), [`be7cfe3`](https://github.com/clauderic/dnd-kit/commit/be7cfe3b6cf6a989aefd3e39fd145fe271942b3a)]:\n  - @dnd-kit/abstract@0.2.4\n  - @dnd-kit/geometry@0.2.4\n\n## 0.2.3\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/abstract@0.2.3\n  - @dnd-kit/geometry@0.2.3\n\n## 0.2.2\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/abstract@0.2.2\n  - @dnd-kit/geometry@0.2.2\n\n## 0.2.1\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/abstract@0.2.1\n  - @dnd-kit/geometry@0.2.1\n\n## 0.2.0\n\n### Patch Changes\n\n- Updated dependencies [[`e95a9c8`](https://github.com/clauderic/dnd-kit/commit/e95a9c8f448d6b339e0b6fd37546ac7cfdf18edb)]:\n  - @dnd-kit/abstract@0.2.0\n  - @dnd-kit/geometry@0.2.0\n\n## 0.1.21\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/abstract@0.1.21\n  - @dnd-kit/geometry@0.1.21\n\n## 0.1.20\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/abstract@0.1.20\n  - @dnd-kit/geometry@0.1.20\n\n## 0.1.19\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/abstract@0.1.19\n  - @dnd-kit/geometry@0.1.19\n\n## 0.1.18\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/abstract@0.1.18\n  - @dnd-kit/geometry@0.1.18\n\n## 0.1.17\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/abstract@0.1.17\n  - @dnd-kit/geometry@0.1.17\n\n## 0.1.16\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/abstract@0.1.16\n  - @dnd-kit/geometry@0.1.16\n\n## 0.1.15\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/abstract@0.1.15\n  - @dnd-kit/geometry@0.1.15\n\n## 0.1.14\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/abstract@0.1.14\n  - @dnd-kit/geometry@0.1.14\n\n## 0.1.13\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/abstract@0.1.13\n  - @dnd-kit/geometry@0.1.13\n\n## 0.1.12\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/abstract@0.1.12\n  - @dnd-kit/geometry@0.1.12\n\n## 0.1.11\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/abstract@0.1.11\n  - @dnd-kit/geometry@0.1.11\n\n## 0.1.10\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/abstract@0.1.10\n  - @dnd-kit/geometry@0.1.10\n\n## 0.1.9\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/abstract@0.1.9\n  - @dnd-kit/geometry@0.1.9\n\n## 0.1.8\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/abstract@0.1.8\n  - @dnd-kit/geometry@0.1.8\n\n## 0.1.7\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/abstract@0.1.7\n  - @dnd-kit/geometry@0.1.7\n\n## 0.1.6\n\n### Patch Changes\n\n- Updated dependencies [[`7ceb799`](https://github.com/clauderic/dnd-kit/commit/7ceb799c7d214bc8223ec845357a0040c28ae40e)]:\n  - @dnd-kit/abstract@0.1.6\n  - @dnd-kit/geometry@0.1.6\n\n## 0.1.5\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/abstract@0.1.5\n  - @dnd-kit/geometry@0.1.5\n\n## 0.1.4\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/abstract@0.1.4\n  - @dnd-kit/geometry@0.1.4\n\n## 0.1.3\n\n### Patch Changes\n\n- Updated dependencies [[`6c9a9ea`](https://github.com/clauderic/dnd-kit/commit/6c9a9ea060095884c90c72cd5d6b73820467ec29), [`1bef872`](https://github.com/clauderic/dnd-kit/commit/1bef8722d515079f998dc0608084e1d853e74d3a), [`2522836`](https://github.com/clauderic/dnd-kit/commit/2522836fdb80520913ea35d94c6558bf7784afc9)]:\n  - @dnd-kit/abstract@0.1.3\n  - @dnd-kit/geometry@0.1.3\n\n## 0.1.2\n\n### Patch Changes\n\n- Updated dependencies [[`ee55f58`](https://github.com/clauderic/dnd-kit/commit/ee55f582f92dc42cc6eea9ad7492fc782ca6455a), [`4682570`](https://github.com/clauderic/dnd-kit/commit/4682570a6b80868af0e51b1bbbf902430117df43), [`f8d69b0`](https://github.com/clauderic/dnd-kit/commit/f8d69b01f4cf53fc368ef1fca9188c313192928d), [`d04e9a2`](https://github.com/clauderic/dnd-kit/commit/d04e9a2879fb00f092c3f8280c8081a48eebf193), [`ee55f58`](https://github.com/clauderic/dnd-kit/commit/ee55f582f92dc42cc6eea9ad7492fc782ca6455a)]:\n  - @dnd-kit/geometry@0.1.2\n  - @dnd-kit/abstract@0.1.2\n\n## 0.1.1\n\n### Patch Changes\n\n- Updated dependencies [[`f13cbc9`](https://github.com/clauderic/dnd-kit/commit/f13cbc978229844770d3c8aa03135e4352ee2532)]:\n  - @dnd-kit/abstract@0.1.1\n  - @dnd-kit/geometry@0.1.1\n\n## 0.1.0\n\n### Patch Changes\n\n- Updated dependencies [[`00a33c9`](https://github.com/clauderic/dnd-kit/commit/00a33c99e777ab205a45309a4efc8b3560bafdaf)]:\n  - @dnd-kit/abstract@0.1.0\n  - @dnd-kit/geometry@0.1.0\n\n## 0.0.10\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/abstract@0.0.10\n  - @dnd-kit/geometry@0.0.10\n\n## 0.0.9\n\n### Patch Changes\n\n- [#1600](https://github.com/clauderic/dnd-kit/pull/1600) [`3463da1`](https://github.com/clauderic/dnd-kit/commit/3463da1cac9f26e4b2ab3278ae52206bb99645e4) Thanks [@github-actions](https://github.com/apps/github-actions)! - Changed the `closestCorners` algorithm to use the corners of the drag operation shape instead of the center of the shape.\n\n- [#1600](https://github.com/clauderic/dnd-kit/pull/1600) [`8ae7014`](https://github.com/clauderic/dnd-kit/commit/8ae70143bc404bff7678fa8e8390a640c16f2579) Thanks [@github-actions](https://github.com/apps/github-actions)! - - Added `corners` getter to `Rectangle` instances to retrieve the coordinates of all four corners.\n  - Added `delta` static method to the `Rectangle` constructor which makes it easy to calculate the delta between a given reference point of both shapes.\n- Updated dependencies [[`e36d954`](https://github.com/clauderic/dnd-kit/commit/e36d95420148659ba78bdbefd3a0a24ec5d02b8f), [`60e7297`](https://github.com/clauderic/dnd-kit/commit/60e72979850bfe4cbb8e2b2e2b8e84bce9edc9f5), [`b7f1cf8`](https://github.com/clauderic/dnd-kit/commit/b7f1cf8f9e15a285c45f896e092f61001335cdff), [`3e629cc`](https://github.com/clauderic/dnd-kit/commit/3e629cc81dbaf9d112c4f1d2c10c75eb6779cf4e), [`8ae7014`](https://github.com/clauderic/dnd-kit/commit/8ae70143bc404bff7678fa8e8390a640c16f2579), [`ce31da7`](https://github.com/clauderic/dnd-kit/commit/ce31da736ec5d4f48bab45430be7b57223d60ee7)]:\n  - @dnd-kit/abstract@0.0.9\n  - @dnd-kit/geometry@0.0.9\n\n## 0.0.8\n\n### Patch Changes\n\n- Updated dependencies [[`c9716cf`](https://github.com/clauderic/dnd-kit/commit/c9716cf7b8b846faab451bd2f60c53c77d2d24ba), [`3ea0d31`](https://github.com/clauderic/dnd-kit/commit/3ea0d314649b186bfe0524d50145625da13a8787), [`3cf4db1`](https://github.com/clauderic/dnd-kit/commit/3cf4db126813ebe6ddfc025df5e42e9bfcfa9c38)]:\n  - @dnd-kit/abstract@0.0.8\n  - @dnd-kit/geometry@0.0.8\n\n## 0.0.7\n\n### Patch Changes\n\n- Updated dependencies [[`c1dadef`](https://github.com/clauderic/dnd-kit/commit/c1dadef118f8f5f096d36dac314bfe317ea950ce), [`cef9b46`](https://github.com/clauderic/dnd-kit/commit/cef9b46c5ed017e6a601b1d0ee9d0f05b7bbd19f)]:\n  - @dnd-kit/abstract@0.0.7\n  - @dnd-kit/geometry@0.0.7\n\n## 0.0.6\n\n### Patch Changes\n\n- [#1567](https://github.com/clauderic/dnd-kit/pull/1567) [`081b7f2`](https://github.com/clauderic/dnd-kit/commit/081b7f2a11da2aad8ce3da7f0579974415d1fdf0) Thanks [@chrisvxd](https://github.com/chrisvxd)! - Add source maps to output.\n\n- [#1454](https://github.com/clauderic/dnd-kit/pull/1454) [`69bfad7`](https://github.com/clauderic/dnd-kit/commit/69bfad7d795947987a4281f1a61f81b6a7839fe8) Thanks [@github-actions](https://github.com/apps/github-actions)! - Introduce `closestCorners` collision detection algorithm.\n\n- [#1454](https://github.com/clauderic/dnd-kit/pull/1454) [`a8542de`](https://github.com/clauderic/dnd-kit/commit/a8542de56d39c3cd3b6ef981172a0782454295b2) Thanks [@github-actions](https://github.com/apps/github-actions)! - Fix issues with `collisionPriority` not being respected.\n\n- [#1454](https://github.com/clauderic/dnd-kit/pull/1454) [`a6366f9`](https://github.com/clauderic/dnd-kit/commit/a6366f9e42836b4c5732141bf314489ede9f60cb) Thanks [@github-actions](https://github.com/apps/github-actions)! - Improve accuracy of `shapeIntersection` when there are multiple intersecting shapes.\n\n- Updated dependencies [[`984b5ab`](https://github.com/clauderic/dnd-kit/commit/984b5ab7bec3145dedb9c9b3b560ffbf7e54b919), [`081b7f2`](https://github.com/clauderic/dnd-kit/commit/081b7f2a11da2aad8ce3da7f0579974415d1fdf0), [`a04d3f8`](https://github.com/clauderic/dnd-kit/commit/a04d3f88d380853b97585ab3b608561f7b02ce69), [`a8542de`](https://github.com/clauderic/dnd-kit/commit/a8542de56d39c3cd3b6ef981172a0782454295b2), [`f7458d9`](https://github.com/clauderic/dnd-kit/commit/f7458d9dc32824dbea3a6d5dfb29236f19a2c073), [`e70b29a`](https://github.com/clauderic/dnd-kit/commit/e70b29ae64837e424f7279c95112fb6e420c4dcc), [`4d1a030`](https://github.com/clauderic/dnd-kit/commit/4d1a0306c920ae064eb5b30c4c02961f50460c84), [`a5933d8`](https://github.com/clauderic/dnd-kit/commit/a5933d8607e63ed08818ffab43e858863cb35d47), [`a5a556a`](https://github.com/clauderic/dnd-kit/commit/a5a556abfeec1d78effb3e047f529555e444c020), [`96f28ef`](https://github.com/clauderic/dnd-kit/commit/96f28ef86adf95e77540732d39033c7f3fb0fd04), [`71dc39f`](https://github.com/clauderic/dnd-kit/commit/71dc39fb2ec21b9a680238a91be419c71ecabe86)]:\n  - @dnd-kit/abstract@0.0.6\n  - @dnd-kit/geometry@0.0.6\n\n## 0.0.5\n\n### Patch Changes\n\n- Updated dependencies [[`e9be505`](https://github.com/clauderic/dnd-kit/commit/e9be5051b5c99e522fb6efd028d425220b171890)]:\n  - @dnd-kit/abstract@0.0.5\n  - @dnd-kit/geometry@0.0.5\n\n## 0.0.4\n\n### Patch Changes\n\n- Updated dependencies [[`2ccc27c`](https://github.com/clauderic/dnd-kit/commit/2ccc27c566b13d6de46719d0ad5978d655261177), [`e0d80f5`](https://github.com/clauderic/dnd-kit/commit/e0d80f59c733b3adcf1fc89d29aa80257e7edd98), [`794cf2f`](https://github.com/clauderic/dnd-kit/commit/794cf2f4bdeeb57a197effb1df654c7c44cf34a3)]:\n  - @dnd-kit/abstract@0.0.4\n  - @dnd-kit/geometry@0.0.4\n\n## 0.0.3\n\n### Patch Changes\n\n- Updated dependencies [[`5ccd5e6`](https://github.com/clauderic/dnd-kit/commit/5ccd5e668fb8d736ec3c195116559cb5c5684e80), [`886de33`](https://github.com/clauderic/dnd-kit/commit/886de33d0df851ebdcb3fcf2915f9623069b06d1)]:\n  - @dnd-kit/abstract@0.0.3\n  - @dnd-kit/geometry@0.0.3\n\n## 0.0.2\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/abstract@0.0.2\n  - @dnd-kit/geometry@0.0.2\n"
  },
  {
    "path": "packages/collision/package.json",
    "content": "{\n  \"name\": \"@dnd-kit/collision\",\n  \"type\": \"module\",\n  \"version\": \"0.3.2\",\n  \"main\": \"./dist/index.cjs\",\n  \"module\": \"./dist/index.js\",\n  \"types\": \"./dist/index.d.ts\",\n  \"sideEffects\": false,\n  \"license\": \"MIT\",\n  \"files\": [\n    \"dist/**\"\n  ],\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/index.d.ts\",\n      \"import\": \"./dist/index.js\",\n      \"require\": \"./dist/index.cjs\"\n    }\n  },\n  \"scripts\": {\n    \"build\": \"tsup src/index.ts --format esm,cjs --dts --external react\",\n    \"dev\": \"tsup src/index.ts --format esm,cjs --watch --dts --external react\",\n    \"lint\": \"TIMING=1 eslint src/**/*.ts* --fix\",\n    \"clean\": \"rm -rf .turbo && rm -rf node_modules && rm -rf dist\"\n  },\n  \"dependencies\": {\n    \"@dnd-kit/abstract\": \"^0.3.2\",\n    \"@dnd-kit/geometry\": \"^0.3.2\",\n    \"tslib\": \"^2.6.2\"\n  },\n  \"devDependencies\": {\n    \"@types/react\": \"^18.0.9\",\n    \"@types/react-dom\": \"^18.0.4\",\n    \"eslint\": \"^8.38.0\",\n    \"@dnd-kit/eslint-config\": \"*\",\n    \"tsup\": \"8.3.0\",\n    \"typescript\": \"^5.5.2\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/clauderic/dnd-kit\"\n  }\n}\n"
  },
  {
    "path": "packages/collision/src/algorithms/closestCenter.ts",
    "content": "import {CollisionPriority, CollisionType} from '@dnd-kit/abstract';\nimport type {CollisionDetector} from '@dnd-kit/abstract';\nimport {Point} from '@dnd-kit/geometry';\n\nimport {defaultCollisionDetection} from './default.ts';\n\n/**\n * Returns the distance between the droppable shape and the drag operation shape.\n */\nexport const closestCenter: CollisionDetector = (input) => {\n  const {dragOperation, droppable} = input;\n  const {shape, position} = dragOperation;\n\n  if (!droppable.shape) {\n    return null;\n  }\n\n  const collision = defaultCollisionDetection(input);\n\n  if (collision) {\n    return collision;\n  }\n\n  const distance = Point.distance(\n    droppable.shape.center,\n    shape?.current.center ?? position.current\n  );\n\n  const value = 1 / distance;\n\n  return {\n    id: droppable.id,\n    value,\n    type: CollisionType.Collision,\n    priority: CollisionPriority.Normal,\n  };\n};\n"
  },
  {
    "path": "packages/collision/src/algorithms/closestCorners.ts",
    "content": "import {CollisionPriority, CollisionType} from '@dnd-kit/abstract';\nimport type {CollisionDetector} from '@dnd-kit/abstract';\nimport {Point, Rectangle} from '@dnd-kit/geometry';\n\n/**\n * Returns the distance between the corners of the droppable shape and the drag operation shape.\n */\nexport const closestCorners: CollisionDetector = (input) => {\n  const {dragOperation, droppable} = input;\n  const {shape, position} = dragOperation;\n\n  if (!droppable.shape) {\n    return null;\n  }\n\n  const shapeCorners = shape\n    ? Rectangle.from(shape.current.boundingRectangle).corners\n    : undefined;\n  const distance = Rectangle.from(\n    droppable.shape.boundingRectangle\n  ).corners.reduce(\n    (acc, corner, index) =>\n      acc +\n      Point.distance(\n        Point.from(corner),\n        shapeCorners?.[index] ?? position.current\n      ),\n    0\n  );\n  const value = distance / 4;\n\n  return {\n    id: droppable.id,\n    value: 1 / value,\n    type: CollisionType.Collision,\n    priority: CollisionPriority.Normal,\n  };\n};\n"
  },
  {
    "path": "packages/collision/src/algorithms/default.ts",
    "content": "import type {CollisionDetector} from '@dnd-kit/abstract';\n\nimport {pointerIntersection} from './pointerIntersection.ts';\nimport {shapeIntersection} from './shapeIntersection.ts';\n\n/**\n * Returns the droppable that has the greatest intersection area with the\n * pointer coordinates. If there are no pointer coordinates, or the pointer\n * is not intersecting with any droppable, return the greatest intersection area\n * between the collision shape and other intersecting droppable shapes.\n */\nexport const defaultCollisionDetection: CollisionDetector = (args) => {\n  return pointerIntersection(args) ?? shapeIntersection(args);\n};\n"
  },
  {
    "path": "packages/collision/src/algorithms/directionBiased.ts",
    "content": "import {CollisionPriority, CollisionType} from '@dnd-kit/abstract';\nimport type {CollisionDetector} from '@dnd-kit/abstract';\nimport {Point} from '@dnd-kit/geometry';\n\nimport {defaultCollisionDetection} from './default.ts';\n\nexport const directionBiased: CollisionDetector = ({\n  dragOperation,\n  droppable,\n}) => {\n  if (!droppable.shape) {\n    return null;\n  }\n\n  const {position, shape} = dragOperation;\n  const {direction} = position;\n\n  if (!shape) {\n    return null;\n  }\n\n  if (direction === null) {\n    return defaultCollisionDetection({dragOperation, droppable});\n  }\n\n  const {center} = shape.current;\n  const rect = droppable.shape.boundingRectangle;\n  const isBelow = rect.bottom >= center.y;\n  const isAbove = rect.top <= center.y;\n  const isLeft = rect.left <= center.x;\n  const isRight = rect.right >= center.x;\n\n  if (\n    (direction === 'down' && isBelow) ||\n    (direction === 'up' && isAbove) ||\n    (direction === 'left' && isLeft) ||\n    (direction === 'right' && isRight)\n  ) {\n    const distance = Point.distance(droppable.shape.center, center);\n    const value = distance === 0 ? 1 : 1 / distance;\n\n    return {\n      id: droppable.id,\n      value,\n      type: CollisionType.Collision,\n      priority: CollisionPriority.Normal,\n    };\n  }\n\n  return null;\n};\n"
  },
  {
    "path": "packages/collision/src/algorithms/index.ts",
    "content": "export {defaultCollisionDetection} from './default.ts';\nexport {closestCorners} from './closestCorners.ts';\nexport {closestCenter} from './closestCenter.ts';\nexport {pointerIntersection} from './pointerIntersection.ts';\nexport {shapeIntersection} from './shapeIntersection.ts';\nexport {directionBiased} from './directionBiased.ts';\nexport {pointerDistance} from './pointerDistance.ts';\n"
  },
  {
    "path": "packages/collision/src/algorithms/pointerDistance.ts",
    "content": "import {CollisionPriority, CollisionType} from '@dnd-kit/abstract';\nimport type {CollisionDetector} from '@dnd-kit/abstract';\nimport {Point} from '@dnd-kit/geometry';\n\n/**\n * Returns the distance between the droppable shape and the drag operation coordinates.\n */\nexport const pointerDistance: CollisionDetector = (input) => {\n  const {dragOperation, droppable} = input;\n  const {position} = dragOperation;\n\n  if (!droppable.shape) {\n    return null;\n  }\n\n  const distance = Point.distance(droppable.shape.center, position.current);\n  const value = 1 / distance;\n\n  return {\n    id: droppable.id,\n    value,\n    type: CollisionType.Collision,\n    priority: CollisionPriority.Normal,\n  };\n};\n"
  },
  {
    "path": "packages/collision/src/algorithms/pointerIntersection.ts",
    "content": "import {CollisionPriority, CollisionType} from '@dnd-kit/abstract';\nimport type {CollisionDetector} from '@dnd-kit/abstract';\nimport {Point} from '@dnd-kit/geometry';\n\n/**\n * A high precision collision detection algorithm that detects\n * whether the pointer intersects with a given droppable element.\n *\n * Returns the distance between the pointer coordinates and the center of the\n * droppable element if the pointer is within the droppable element.\n *\n * Returns null if the pointer is outside of the droppable element.\n */\nexport const pointerIntersection: CollisionDetector = ({\n  dragOperation,\n  droppable,\n}) => {\n  const pointerCoordinates = dragOperation.position.current;\n\n  if (!pointerCoordinates) {\n    return null;\n  }\n\n  const {id} = droppable;\n\n  if (!droppable.shape) {\n    return null;\n  }\n\n  if (droppable.shape.containsPoint(pointerCoordinates)) {\n    /* There may be more than a single rectangle intersecting\n     * with the pointer coordinates. In order to sort the\n     * colliding rectangles, we measure the distance between\n     * the pointer and the center of the intersecting rectangle\n     */\n    const distance = Point.distance(droppable.shape.center, pointerCoordinates);\n\n    return {\n      id,\n      value: 1 / distance,\n      type: CollisionType.PointerIntersection,\n      priority: CollisionPriority.High,\n    };\n  }\n\n  return null;\n};\n"
  },
  {
    "path": "packages/collision/src/algorithms/shapeIntersection.ts",
    "content": "import {CollisionPriority, CollisionType} from '@dnd-kit/abstract';\nimport type {CollisionDetector} from '@dnd-kit/abstract';\nimport {Point} from '@dnd-kit/geometry';\n\n/**\n * Returns the droppable with the greatest intersection area with\n * the collision shape.\n */\nexport const shapeIntersection: CollisionDetector = ({\n  dragOperation,\n  droppable,\n}) => {\n  const {shape} = dragOperation;\n\n  if (!droppable.shape || !shape?.current) {\n    return null;\n  }\n\n  const intersectionArea = shape.current.intersectionArea(droppable.shape);\n\n  // Check if the droppable is intersecting with the drag operation shape.\n  if (intersectionArea) {\n    const {position} = dragOperation;\n    /* There could be multiple droppables intersecting with the drag operation shape,\n     * so we need to prioritize the droppable that is the closest to the pointer.\n     * We don't use the intersection area for this because it can lead to cyclic\n     * collisions.\n     */\n    const distance = Point.distance(droppable.shape.center, position.current);\n    const intersectionRatio =\n      intersectionArea /\n      (shape.current.area + droppable.shape.area - intersectionArea);\n\n    const value = intersectionRatio / distance;\n\n    return {\n      id: droppable.id,\n      value,\n      type: CollisionType.ShapeIntersection,\n      priority: CollisionPriority.Normal,\n    };\n  }\n\n  return null;\n};\n"
  },
  {
    "path": "packages/collision/src/index.ts",
    "content": "export type {CollisionDetector} from '@dnd-kit/abstract';\nexport {\n  closestCenter,\n  closestCorners,\n  defaultCollisionDetection,\n  directionBiased,\n  pointerDistance,\n  pointerIntersection,\n  shapeIntersection,\n} from './algorithms/index.ts';\n"
  },
  {
    "path": "packages/collision/tsconfig.json",
    "content": "{\n  \"extends\": \"../../config/typescript/vanilla.json\",\n  \"include\": [\"src/**/*\"],\n  \"exclude\": [\"dist\", \"build\", \"node_modules\"]\n}\n"
  },
  {
    "path": "packages/dom/CHANGELOG.md",
    "content": "# @dnd-kit/dom\n\n## 0.3.2\n\n### Patch Changes\n\n- [#1903](https://github.com/clauderic/dnd-kit/pull/1903) [`7260746`](https://github.com/clauderic/dnd-kit/commit/7260746b0930d51afb3098ef120bffd7d3aaea03) Thanks [@clauderic](https://github.com/clauderic)! - Fixed CSS cascade layer ordering so that the popover-reset styles injected by the Feedback plugin no longer override styles from CSS frameworks that use cascade layers (such as Tailwind CSS v4).\n\n  The `@layer` block is now named `dnd-kit` and injected via a `<style>` element prepended to `<head>` for document roots, ensuring it is declared first in the cascade with the lowest priority. Shadow DOM roots continue to use `adoptedStyleSheets`.\n\n  If needed, consumers can explicitly control the layer ordering:\n\n  ```css\n  @layer dnd-kit, base, components, utilities;\n  ```\n\n- Updated dependencies []:\n  - @dnd-kit/abstract@0.3.2\n  - @dnd-kit/collision@0.3.2\n  - @dnd-kit/geometry@0.3.2\n  - @dnd-kit/state@0.3.2\n\n## 0.3.1\n\n### Patch Changes\n\n- Updated dependencies [[`4341114`](https://github.com/clauderic/dnd-kit/commit/43411143063349caeded4f778923473624ce25cf)]:\n  - @dnd-kit/abstract@0.3.1\n  - @dnd-kit/collision@0.3.1\n  - @dnd-kit/geometry@0.3.1\n  - @dnd-kit/state@0.3.1\n\n## 0.3.0\n\n### Minor Changes\n\n- [`6a59647`](https://github.com/clauderic/dnd-kit/commit/6a59647ebba2114b2e423f282ab25bf2ea40318d) Thanks [@clauderic](https://github.com/clauderic)! - Allow `plugins`, `sensors`, and `modifiers` to accept a function that receives the defaults, making it easy to extend or configure them without replacing the entire array.\n\n  ```ts\n  // Add a plugin alongside the defaults\n  const manager = new DragDropManager({\n    plugins: (defaults) => [...defaults, MyPlugin],\n  });\n  ```\n\n  ```tsx\n  // Configure a default plugin in React\n  <DragDropProvider\n    plugins={(defaults) => [\n      ...defaults,\n      Feedback.configure({dropAnimation: null}),\n    ]}\n  />\n  ```\n\n  Previously, passing `plugins`, `sensors`, or `modifiers` would replace the defaults entirely, requiring consumers to import and spread `defaultPreset`. The function form receives the default values as an argument, so consumers can add, remove, or configure individual entries without needing to know or maintain the full default list.\n\n- [`68e44de`](https://github.com/clauderic/dnd-kit/commit/68e44deb6f824b38a58d9b4b1bd81e2efa9193f9) Thanks [@clauderic](https://github.com/clauderic)! - Add `isSortableOperation` type guard and export `SortableDraggable`/`SortableDroppable` types.\n\n  `isSortableOperation(operation)` narrows a `DragOperationSnapshot` so that `source` is typed as `SortableDraggable` and `target` as `SortableDroppable`, providing typed access to sortable-specific properties like `index`, `initialIndex`, `group`, and `initialGroup`.\n\n  Re-exported from all framework packages (`@dnd-kit/react/sortable`, `@dnd-kit/vue/sortable`, `@dnd-kit/svelte/sortable`, `@dnd-kit/solid/sortable`).\n\n### Patch Changes\n\n- [`5d64078`](https://github.com/clauderic/dnd-kit/commit/5d640782702b74da8be38cbd1e29271d04781854) Thanks [@clauderic](https://github.com/clauderic)! - Add `dropAnimation` prop to the `DragOverlay` component to allow consumers to disable or customize the drop animation that plays when a drag operation ends. Set to `null` to disable, pass `{duration, easing}` to customize timing, or provide a custom animation function for full control.\n\n- [`863ce2b`](https://github.com/clauderic/dnd-kit/commit/863ce2b74ec0f4d630f4b7036c363bc2e3d04f24) Thanks [@clauderic](https://github.com/clauderic)! - Fix auto-scroll trigger zones and boundaries during pinch-to-zoom.\n\n  Updated `getViewportBoundingRectangle`, `getVisibleBoundingRectangle`, and `getScrollPosition` to use the Visual Viewport API, so that scroll detection and element visibility clipping are based on the actual visible area rather than the layout viewport. This fixes auto-scroll not triggering near the visible edges and stopping before reaching the end of scrollable content when the page is zoomed in.\n\n- [`863ce2b`](https://github.com/clauderic/dnd-kit/commit/863ce2b74ec0f4d630f4b7036c363bc2e3d04f24) Thanks [@clauderic](https://github.com/clauderic)! - Fix drag overlay and debug overlay mispositioning in Safari during pinch-to-zoom.\n\n  Safari anchors `position: fixed` elements to the visual viewport rather than the layout viewport during pinch-to-zoom. Added a `getFixedPositionOffset()` utility that compensates for this by adding `visualViewport.offsetLeft/Top` to the CSS `left`/`top` values of fixed-positioned overlays.\n\n- [`e8ae539`](https://github.com/clauderic/dnd-kit/commit/e8ae539abe05a1df41d45078b108167022ac9ef7) Thanks [@clauderic](https://github.com/clauderic)! - Fix the `move` and `swap` helpers to support computed sortable IDs and optimistic sorting reconciliation for grouped records.\n\n  When the ID-based lookup fails (e.g. when using computed IDs like `id={\\`sortable-${item.id}\\`}` that don't match data items), the helpers now fall back to sortable index properties (`initialIndex`, `index`, `group`, `initialGroup`) to determine the correct positions. Additionally, grouped records now support optimistic sorting reconciliation—when `source.id === target.id` after optimistic sorting, the helpers use the sortable indices to determine the intended move.\n\n  Added `initialIndex`, `group`, and `initialGroup` getters to `SortableDraggable`, and `index` and `group` getters to `SortableDroppable`, so these properties are accessible from the operation's `source` and `target` in drag events.\n\n- [`41d7e27`](https://github.com/clauderic/dnd-kit/commit/41d7e27edb30cea9940cd5c46c6fcc81f7b401a6) Thanks [@rjur11](https://github.com/rjur11)! - Fixed PointerSensor crash on Android caused by unhandled pointercancel events.\n\n- Updated dependencies [[`6a59647`](https://github.com/clauderic/dnd-kit/commit/6a59647ebba2114b2e423f282ab25bf2ea40318d)]:\n  - @dnd-kit/abstract@0.3.0\n  - @dnd-kit/collision@0.3.0\n  - @dnd-kit/geometry@0.3.0\n  - @dnd-kit/state@0.3.0\n\n## 0.2.4\n\n### Patch Changes\n\n- [#1874](https://github.com/clauderic/dnd-kit/pull/1874) [`de27fbc`](https://github.com/clauderic/dnd-kit/commit/de27fbca9df12eece3cd53ccbbac34e0eaf113e1) Thanks [@clauderic](https://github.com/clauderic)! - Expose ergonomic type aliases for drag and drop event handlers: `CollisionEvent`, `BeforeDragStartEvent`, `DragStartEvent`, `DragMoveEvent`, `DragOverEvent`, and `DragEndEvent`. These types are re-exported from `@dnd-kit/dom` and `@dnd-kit/react` for convenience.\n\n- [#1854](https://github.com/clauderic/dnd-kit/pull/1854) [`c2097c9`](https://github.com/clauderic/dnd-kit/commit/c2097c92df0af496e973cea6b9824f82d0aba92e) Thanks [@du33169](https://github.com/du33169)! - Fixed Feedback plugin style injection in Shadow DOM (fix #1765)\n\n- [#1875](https://github.com/clauderic/dnd-kit/pull/1875) [`6d80680`](https://github.com/clauderic/dnd-kit/commit/6d80680454001f42ab9ec4bd7ae3c764ca33287a) Thanks [@clauderic](https://github.com/clauderic)! - **Feedback plugin**: Fix table cell width handling during drag operations. Use `getBoundingClientRect().width` instead of `offsetWidth` for sub-pixel precision, and restore original cell widths after dragging ends instead of leaving hardcoded values permanently.\n\n- [#1877](https://github.com/clauderic/dnd-kit/pull/1877) [`0923bc6`](https://github.com/clauderic/dnd-kit/commit/0923bc674273acffd5cf1c35e24f6ff505acc26e) Thanks [@clauderic](https://github.com/clauderic)! - Respect `prefers-reduced-motion` media query across all animations. When the user prefers reduced motion, the following animations are disabled:\n\n  - Keyboard drag move transitions (250ms translate)\n  - Drop animation (250ms slide-back)\n  - Sortable item swap transitions (250ms position shift)\n\n- [#1876](https://github.com/clauderic/dnd-kit/pull/1876) [`5f1b19a`](https://github.com/clauderic/dnd-kit/commit/5f1b19a1f39d845618712bb34314c6133030d557) Thanks [@clauderic](https://github.com/clauderic)! - Refactor the Feedback plugin for improved modularity and extensibility.\n\n  **StyleSheetManager** – Introduced a new generic `CorePlugin` that manages CSS stylesheet injection into document and shadow roots. Plugins can call `register(cssRules)` to declare styles and `addRoot(root)` to track additional roots. The manager reactively injects and cleans up adopted stylesheets as the drag operation's source and target roots change. The Feedback plugin now delegates all stylesheet management to the StyleSheetManager.\n\n  **Configurable drop animation** – The `Feedback` plugin now accepts a `dropAnimation` option:\n\n  - Pass `{ duration, easing }` to customize the built-in animation timing\n  - Pass a function for full custom animation control (receives context, return a promise)\n  - Pass `null` to disable the drop animation entirely\n  - Omit for the default 250ms ease animation\n\n  **Extracted helpers** – Observer setup (`createElementMutationObserver`, `createDocumentMutationObserver`, `createResizeObserver`) and the drop animation logic (`runDropAnimation`) are now in dedicated modules within the feedback plugin directory.\n\n- Updated dependencies [[`de27fbc`](https://github.com/clauderic/dnd-kit/commit/de27fbca9df12eece3cd53ccbbac34e0eaf113e1), [`256432d`](https://github.com/clauderic/dnd-kit/commit/256432dec8823342765eebdb78ee791c25fea382), [`be7cfe3`](https://github.com/clauderic/dnd-kit/commit/be7cfe3b6cf6a989aefd3e39fd145fe271942b3a)]:\n  - @dnd-kit/abstract@0.2.4\n  - @dnd-kit/collision@0.2.4\n  - @dnd-kit/geometry@0.2.4\n  - @dnd-kit/state@0.2.4\n\n## 0.2.3\n\n### Patch Changes\n\n- [#1861](https://github.com/clauderic/dnd-kit/pull/1861) [`f90571d`](https://github.com/clauderic/dnd-kit/commit/f90571db8b8a94d751d3eeb80d91b6cd34716f47) Thanks [@xuxucode](https://github.com/xuxucode)! - Fixed a bug where custom `PointerSensor` options passed to the `bind()` method were not being respected by the `activationConstraints()` method.\n\n- Updated dependencies []:\n  - @dnd-kit/abstract@0.2.3\n  - @dnd-kit/collision@0.2.3\n  - @dnd-kit/geometry@0.2.3\n  - @dnd-kit/state@0.2.3\n\n## 0.2.2\n\n### Patch Changes\n\n- [`5c80bcf`](https://github.com/clauderic/dnd-kit/commit/5c80bcf8affe6accb5b70df3e372f5e864f54b4a) Thanks [@clauderic](https://github.com/clauderic)! - Fixed inverted `preventActivation` default option on `KeyboardSensor`\n\n- Updated dependencies []:\n  - @dnd-kit/abstract@0.2.2\n  - @dnd-kit/collision@0.2.2\n  - @dnd-kit/geometry@0.2.2\n  - @dnd-kit/state@0.2.2\n\n## 0.2.1\n\n### Patch Changes\n\n- [`d7f4130`](https://github.com/clauderic/dnd-kit/commit/d7f413079b028feb826ca33243927e855619c0f2) Thanks [@clauderic](https://github.com/clauderic)! - - Fix a bug with `PointerSensor.defaults.preventActivation` not being applied if there are other sensor options provided.\n\n- Updated dependencies []:\n  - @dnd-kit/abstract@0.2.1\n  - @dnd-kit/collision@0.2.1\n  - @dnd-kit/geometry@0.2.1\n  - @dnd-kit/state@0.2.1\n\n## 0.2.0\n\n### Minor Changes\n\n- [#1821](https://github.com/clauderic/dnd-kit/pull/1821) [`e95a9c8`](https://github.com/clauderic/dnd-kit/commit/e95a9c8f448d6b339e0b6fd37546ac7cfdf18edb) Thanks [@clauderic](https://github.com/clauderic)! - - Refactor `PointerSensor` to use the new activation primitives.\n\n  - Add `PointerActivationConstraints` with composable constraints:\n    - `PointerActivationConstraints.Delay({value, tolerance})`\n    - `PointerActivationConstraints.Distance({value, tolerance?})`\n  - Update `PointerSensor.defaults.activationConstraints(...)`:\n    - Mouse on handle: activates immediately.\n    - Touch: Delay 250ms with 5px tolerance.\n    - Text inputs: Delay 200ms with 0px tolerance.\n    - Other pointer types: Delay 200ms with 10px tolerance + Distance 5px.\n  - New utilities:\n    - `getDocuments()` returns all same-origin documents (enables listening across iframes).\n    - `getEventCoordinates(event)` returns `{x, y}` from a `PointerEvent`.\n  - `PointerSensor` now binds listeners across same-origin documents and improves default prevention during drag.\n  - Internal cleanups: remove internal `sensors/pointer/index.ts` and `utilities/execution-context/index.ts` (no public API impact).\n\n  These changes are additive and should be non-breaking. If you were composing pointer activation constraints, migrate to the new `PointerActivationConstraints` classes if you were importing internal implementations.\n\n- [#1823](https://github.com/clauderic/dnd-kit/pull/1823) [`9849887`](https://github.com/clauderic/dnd-kit/commit/984988774a6ff2f19cae4a27612bbd50cfcfa574) Thanks [@github-actions](https://github.com/apps/github-actions)! - - Add `preventActivation` option to `PointerSensor` and `KeyboardSensor` to conditionally prevent sensor activation.\n  - **PointerSensor**: The default `preventActivation` prevents activation when the pointer target is an interactive element (input, select, textarea, button, link, or contenteditable) that is not the source element or handle.\n  - **KeyboardSensor**: Renamed `shouldActivate` to `preventActivation` with inverted logic—return `true` to prevent activation instead of returning `true` to allow it.\n  - New utility: `isInteractiveElement(element)` checks if an element is an interactive form control or link.\n\n### Patch Changes\n\n- Updated dependencies [[`e95a9c8`](https://github.com/clauderic/dnd-kit/commit/e95a9c8f448d6b339e0b6fd37546ac7cfdf18edb)]:\n  - @dnd-kit/abstract@0.2.0\n  - @dnd-kit/collision@0.2.0\n  - @dnd-kit/geometry@0.2.0\n  - @dnd-kit/state@0.2.0\n\n## 0.1.21\n\n### Patch Changes\n\n- [#1775](https://github.com/clauderic/dnd-kit/pull/1775) [`3d6219d`](https://github.com/clauderic/dnd-kit/commit/3d6219db072551945556fdac2788e738f77b92c7) Thanks [@fpronto](https://github.com/fpronto)! - Added nonce as an option for every plugin that inject styles in html\n\n- Updated dependencies []:\n  - @dnd-kit/abstract@0.1.21\n  - @dnd-kit/collision@0.1.21\n  - @dnd-kit/geometry@0.1.21\n  - @dnd-kit/state@0.1.21\n\n## 0.1.20\n\n### Patch Changes\n\n- [#1737](https://github.com/clauderic/dnd-kit/pull/1737) [`3ba5a90`](https://github.com/clauderic/dnd-kit/commit/3ba5a90854669e034a06146fc0268ed0de813257) Thanks [@github-actions](https://github.com/apps/github-actions)! - **Sortable**: Fix bugs with reverting optimistic updates on canceled `dragend`\n\n- [#1737](https://github.com/clauderic/dnd-kit/pull/1737) [`32448ff`](https://github.com/clauderic/dnd-kit/commit/32448ff11eb3e86a28fc8f6ef7a8a3761e092412) Thanks [@github-actions](https://github.com/apps/github-actions)! - Bump `@preact/signals-core` to `1.10.0`\n\n- Updated dependencies [[`98d4cd4`](https://github.com/clauderic/dnd-kit/commit/98d4cd4047c56589cdf21067526426717bba01c4), [`32448ff`](https://github.com/clauderic/dnd-kit/commit/32448ff11eb3e86a28fc8f6ef7a8a3761e092412)]:\n  - @dnd-kit/state@0.1.20\n  - @dnd-kit/abstract@0.1.20\n  - @dnd-kit/collision@0.1.20\n  - @dnd-kit/geometry@0.1.20\n\n## 0.1.19\n\n### Patch Changes\n\n- [#1735](https://github.com/clauderic/dnd-kit/pull/1735) [`cc7feac`](https://github.com/clauderic/dnd-kit/commit/cc7feacb003b95a744c81e7c75c2aa26d071971f) Thanks [@MateusJabour](https://github.com/MateusJabour)! - Fixes cleanup issue where user would be stuck in dragging mode\n\n- Updated dependencies [[`d848327`](https://github.com/clauderic/dnd-kit/commit/d848327b242c6714b36207071ad30e6b4183e865)]:\n  - @dnd-kit/state@0.1.19\n  - @dnd-kit/abstract@0.1.19\n  - @dnd-kit/collision@0.1.19\n  - @dnd-kit/geometry@0.1.19\n\n## 0.1.18\n\n### Patch Changes\n\n- [#1715](https://github.com/clauderic/dnd-kit/pull/1715) [`e502979`](https://github.com/clauderic/dnd-kit/commit/e502979375b9211fef277b8d657d9411f84be96c) Thanks [@github-actions](https://github.com/apps/github-actions)! - Improved TypeScript generics for better type safety and flexibility\n\n  - Enhanced `DragDropManager` to accept generic type parameters with proper constraints, allowing for more flexible type usage while maintaining type safety\n  - Updated `DragDropProvider` to support custom generic types for draggable and droppable entities\n  - Modified React hooks (`useDragDropManager`, `useDragDropMonitor`, `useDragOperation`) to properly infer and return the correct generic types\n  - Changed from concrete `Draggable` and `Droppable` types to generic parameters constrained by `Data` type\n\n- [`88942be`](https://github.com/clauderic/dnd-kit/commit/88942be007a743673644ba531fd5c6b1a501bf2e) Thanks [@clauderic](https://github.com/clauderic)! - **DOMRectangle**: Fix bugs with projected transforms.\n\n- [#1715](https://github.com/clauderic/dnd-kit/pull/1715) [`9326d43`](https://github.com/clauderic/dnd-kit/commit/9326d43ba0b9b682ee377011b96d4713711571a5) Thanks [@github-actions](https://github.com/apps/github-actions)! - **Feedback**: Re-inject the feedback styles if they get removed from the DOM before the `Feedback` plugin is torn down.\n\n- [#1715](https://github.com/clauderic/dnd-kit/pull/1715) [`7af261f`](https://github.com/clauderic/dnd-kit/commit/7af261f4e3214a9ebef46d26df607221306eb697) Thanks [@github-actions](https://github.com/apps/github-actions)! - **Feedback**: Fix an issue that caused styles to be removed when another instance of the Feedback plugin was torn down even if other instances of the Feedback plugin are still active.\n\n- [#1714](https://github.com/clauderic/dnd-kit/pull/1714) [`b9b182e`](https://github.com/clauderic/dnd-kit/commit/b9b182ef39f7aa8bfe2d331cb20c696b1e9fc15a) Thanks [@clauderic](https://github.com/clauderic)! - **OptimisticSortingPlugin**: Fixed a bug where using `queueMicrotask` in the `dragover` event of to check if `event.defaultPrevented()` was called by consumers was causing the order that we capture to be stale in the event that the consumer updates the order of sortable items before the micortask runs, which can happen in React for consumers using `useOptimistic` to update state optimistically.\n\n- [#1715](https://github.com/clauderic/dnd-kit/pull/1715) [`bb790c9`](https://github.com/clauderic/dnd-kit/commit/bb790c928a9955bd5c7c4312875090e16d891c23) Thanks [@github-actions](https://github.com/apps/github-actions)! - **Feedback**: Fix a regression with the drop animation on Safari.\n\n- Updated dependencies []:\n  - @dnd-kit/abstract@0.1.18\n  - @dnd-kit/collision@0.1.18\n  - @dnd-kit/geometry@0.1.18\n  - @dnd-kit/state@0.1.18\n\n## 0.1.17\n\n### Patch Changes\n\n- [`cfb94d4`](https://github.com/clauderic/dnd-kit/commit/cfb94d4fef372059cb87cf0e63bc3ab87f5c8bd8) Thanks [@clauderic](https://github.com/clauderic)! - Added a `try` / `catch` in `showPopover` and `hidePopover` as the `element.matches(':popover-open')` selector can throw in browsers that don't support the Popover API.\n\n- Updated dependencies []:\n  - @dnd-kit/abstract@0.1.17\n  - @dnd-kit/collision@0.1.17\n  - @dnd-kit/geometry@0.1.17\n  - @dnd-kit/state@0.1.17\n\n## 0.1.16\n\n### Patch Changes\n\n- [#1712](https://github.com/clauderic/dnd-kit/pull/1712) [`93911cc`](https://github.com/clauderic/dnd-kit/commit/93911cca237bea302a12749476d4e18b74ac0fa2) Thanks [@github-actions](https://github.com/apps/github-actions)! - **Debug**: Force the source debug elements to be re-promoted to the top of the top layer.\n\n- [#1712](https://github.com/clauderic/dnd-kit/pull/1712) [`0f68bb6`](https://github.com/clauderic/dnd-kit/commit/0f68bb6c95b1287d5988b1d5d4e94f1462fc36a5) Thanks [@github-actions](https://github.com/apps/github-actions)! - **Feedback**: Account for frame scale when optimistically updating feedback element shape while dragging.\n\n- Updated dependencies []:\n  - @dnd-kit/abstract@0.1.16\n  - @dnd-kit/collision@0.1.16\n  - @dnd-kit/geometry@0.1.16\n  - @dnd-kit/state@0.1.16\n\n## 0.1.15\n\n### Patch Changes\n\n- [`5539a5a`](https://github.com/clauderic/dnd-kit/commit/5539a5a2991ac86b217dba3ef70fc06331bd0260) Thanks [@clauderic](https://github.com/clauderic)! - Mock `ResizeObserver` in SSR environment.\n\n- Updated dependencies []:\n  - @dnd-kit/abstract@0.1.15\n  - @dnd-kit/collision@0.1.15\n  - @dnd-kit/geometry@0.1.15\n  - @dnd-kit/state@0.1.15\n\n## 0.1.14\n\n### Patch Changes\n\n- [#1708](https://github.com/clauderic/dnd-kit/pull/1708) [`4c1e05d`](https://github.com/clauderic/dnd-kit/commit/4c1e05d531a1ffbf32b27d997ebd504532b9616a) Thanks [@GuillaumeSalles](https://github.com/GuillaumeSalles)! - Ensure PositionObserver recompute element rect if IntersectionObserver is scheduled in a different frame\n\n- [#1707](https://github.com/clauderic/dnd-kit/pull/1707) [`a97b10c`](https://github.com/clauderic/dnd-kit/commit/a97b10c9d8467c14ef678d3776ea10a2a1e6e027) Thanks [@github-actions](https://github.com/apps/github-actions)! - **Feedback**:\n\n  - Fixed a bug where the initial `translate` string was incorrectly formed, causing it not to be applied.\n  - Fixed a bug with the placeholder ResizeObserver shape update\n  - Fixed a bug with the initial shape of the Feedback element when the source element unmounts and re-mounts during a drag operation\n  - Fixed a bug with the initial `transition` when setting up the Feedback element\n\n- [#1707](https://github.com/clauderic/dnd-kit/pull/1707) [`caa3273`](https://github.com/clauderic/dnd-kit/commit/caa3273af1fcee9b4e3b5f1e80e5573c84ab69e3) Thanks [@github-actions](https://github.com/apps/github-actions)! - **PositionObserver**: Fixed a bug with observing elements contained within same origin iframes. Due to limitations with `IntersectionObserver`, we need to also attach position observers on the containing iframe to ensure the position of elements nested withing the iframe is updated if the iframe position changes.\n\n- [#1707](https://github.com/clauderic/dnd-kit/pull/1707) [`cb47da3`](https://github.com/clauderic/dnd-kit/commit/cb47da3dad7ec617fabb6e8c3b3432a19b354812) Thanks [@github-actions](https://github.com/apps/github-actions)! - **DOMRectangle**: Fixed a bug with projected transforms where scale was not properly being taken into account.\n\n- [#1707](https://github.com/clauderic/dnd-kit/pull/1707) [`f295344`](https://github.com/clauderic/dnd-kit/commit/f2953444cbdb195e169fc615454d6be3170bf2a6) Thanks [@github-actions](https://github.com/apps/github-actions)! - **KeyboardSensor**: Delegated the responsibility of ending the drag operation when the window resizes to the Feedback plugin, as we only need to end the operation if the feedback element's window resizes, which can be different from the source element window.\n\n- Updated dependencies []:\n  - @dnd-kit/abstract@0.1.14\n  - @dnd-kit/collision@0.1.14\n  - @dnd-kit/geometry@0.1.14\n  - @dnd-kit/state@0.1.14\n\n## 0.1.13\n\n### Patch Changes\n\n- [`c46415a`](https://github.com/clauderic/dnd-kit/commit/c46415a0733f5cbba49cdbd7b6786a0d9add6800) Thanks [@clauderic](https://github.com/clauderic)! - **Feedback**: Removed `box-sizing: border-box` from the default Feedback plugin styles, and account for `box-sizing: content-box` or `box-sizing: border-box` when setting an explicit wdith and height on the feedback element.\n\n- [#1691](https://github.com/clauderic/dnd-kit/pull/1691) [`382f4e2`](https://github.com/clauderic/dnd-kit/commit/382f4e2f0800a3b85487a1a7a2cefef4484bee70) Thanks [@github-actions](https://github.com/apps/github-actions)! - **Accessiblity**: Fixed a bug where accesibility instructions and announcement nodes were re-created on every drag operation.\n\n- [#1691](https://github.com/clauderic/dnd-kit/pull/1691) [`432a0dd`](https://github.com/clauderic/dnd-kit/commit/432a0dd8c67cfdebf0194205979b7249620e73a8) Thanks [@github-actions](https://github.com/apps/github-actions)! - **Feedback**: Fix a bug where options were not properly being set on the plugin instance.\n\n- [#1689](https://github.com/clauderic/dnd-kit/pull/1689) [`a3496c1`](https://github.com/clauderic/dnd-kit/commit/a3496c15c2dc07cc982608b2a4afb1c61b01dbb8) Thanks [@GuillaumeSalles](https://github.com/GuillaumeSalles)! - Ensure showPopover is not called when popover is already visible\n\n- [#1691](https://github.com/clauderic/dnd-kit/pull/1691) [`4a22b39`](https://github.com/clauderic/dnd-kit/commit/4a22b39267f1fa8d17a62b9c29ff8728733c1478) Thanks [@github-actions](https://github.com/apps/github-actions)! - **PointerSensor**: Update default activation constraints to only allow dragging via the `delay` constraint when the activation event target is a text input to avoid interfering with potential text selections within the text input.\n\n- Updated dependencies []:\n  - @dnd-kit/abstract@0.1.13\n  - @dnd-kit/collision@0.1.13\n  - @dnd-kit/geometry@0.1.13\n  - @dnd-kit/state@0.1.13\n\n## 0.1.12\n\n### Patch Changes\n\n- [`2e0e2e2`](https://github.com/clauderic/dnd-kit/commit/2e0e2e256d2043831df6a245df9f618ac4b5ecc9) Thanks [@clauderic](https://github.com/clauderic)! - Exported `Cursor` and `PreventSelection` plugins which are used in the default preset.\n\n- [#1687](https://github.com/clauderic/dnd-kit/pull/1687) [`b86867b`](https://github.com/clauderic/dnd-kit/commit/b86867b1426525729357654a62f52fe0554f7f73) Thanks [@github-actions](https://github.com/apps/github-actions)! - Added `visibility: hidden` to the `::backdrop` pseudo element of the `Feedback` plugin to ensure it is not visible on Firefox, there is a bug where it can be shown even with `display: none` when there is a backdrop filter applied to it.\n\n- [#1687](https://github.com/clauderic/dnd-kit/pull/1687) [`a913f5e`](https://github.com/clauderic/dnd-kit/commit/a913f5e68435c5c0a4a073a7437f265bcc0b5d1d) Thanks [@github-actions](https://github.com/apps/github-actions)! - Fix calls to `requestAnimationFrame` scheduler in SSR environment\n\n- Updated dependencies []:\n  - @dnd-kit/abstract@0.1.12\n  - @dnd-kit/collision@0.1.12\n  - @dnd-kit/geometry@0.1.12\n  - @dnd-kit/state@0.1.12\n\n## 0.1.11\n\n### Patch Changes\n\n- [#1685](https://github.com/clauderic/dnd-kit/pull/1685) [`2370665`](https://github.com/clauderic/dnd-kit/commit/237066598f7da6cd59d78120260788593371e820) Thanks [@clauderic](https://github.com/clauderic)! - Minimize layout thrashing in `Scroller` and `Accessibility` plugins.\n\n- Updated dependencies []:\n  - @dnd-kit/abstract@0.1.11\n  - @dnd-kit/collision@0.1.11\n  - @dnd-kit/geometry@0.1.11\n  - @dnd-kit/state@0.1.11\n\n## 0.1.10\n\n### Patch Changes\n\n- [`a0f5c44`](https://github.com/clauderic/dnd-kit/commit/a0f5c44985b634e8044415db342354493d201f3e) Thanks [@clauderic](https://github.com/clauderic)! - **Feedback**: Optimistically update `dragOperation.shape` when there are no modifiers for better performance.\n\n- Updated dependencies []:\n  - @dnd-kit/abstract@0.1.10\n  - @dnd-kit/collision@0.1.10\n  - @dnd-kit/geometry@0.1.10\n  - @dnd-kit/state@0.1.10\n\n## 0.1.9\n\n### Patch Changes\n\n- [`ffdbf52`](https://github.com/clauderic/dnd-kit/commit/ffdbf52a93cbe0c1c785feca57622d4712175a3a) Thanks [@clauderic](https://github.com/clauderic)! - **Feedback**: Revert moving CSS variables to the root as we noticed performance regressions in applications that have complex DOM structures.\n\n- Updated dependencies []:\n  - @dnd-kit/abstract@0.1.9\n  - @dnd-kit/collision@0.1.9\n  - @dnd-kit/geometry@0.1.9\n  - @dnd-kit/state@0.1.9\n\n## 0.1.8\n\n### Patch Changes\n\n- [#1681](https://github.com/clauderic/dnd-kit/pull/1681) [`14dc059`](https://github.com/clauderic/dnd-kit/commit/14dc05950ad31c50240ee864431112d7f1b70da0) Thanks [@github-actions](https://github.com/apps/github-actions)! - Cache repeated calls to `getComputedStyles` when reading properties that are unlikely to change frequently.\n\n- [`fcd9bb5`](https://github.com/clauderic/dnd-kit/commit/fcd9bb56fafc5ec23ded219bfcd7fdfa31a0caff) Thanks [@clauderic](https://github.com/clauderic)! - Moved the CSS variables to the `[data-dnd-root]` element, which defaults to the `document.body` of the source element to avoid triggering `MutationObserver` callbacks every time the `--dnd-translate` CSS variable is updated.\n\n- [#1681](https://github.com/clauderic/dnd-kit/pull/1681) [`93d3c7c`](https://github.com/clauderic/dnd-kit/commit/93d3c7c8b01d640b017cf8d2cddc69cc47c74ca5) Thanks [@github-actions](https://github.com/apps/github-actions)! - Replace `innerText` with `textContent` for better performance across multiple plugins. This change improves performance since `textContent` is generally more efficient than `innerText` as it doesn't trigger layout reflows and doesn't parse HTML entities.\n\n- [`3c625d6`](https://github.com/clauderic/dnd-kit/commit/3c625d61fc8bdba026d445333c2d1ca1d8489294) Thanks [@clauderic](https://github.com/clauderic)! - Do not use cache when getting element animations to compute projected transforms.\n\n- Updated dependencies []:\n  - @dnd-kit/abstract@0.1.8\n  - @dnd-kit/collision@0.1.8\n  - @dnd-kit/geometry@0.1.8\n  - @dnd-kit/state@0.1.8\n\n## 0.1.7\n\n### Patch Changes\n\n- [`0618852`](https://github.com/clauderic/dnd-kit/commit/0618852fdeb6948e85d1330febee73e48458e740) Thanks [@clauderic](https://github.com/clauderic)! - Fix a regression with horizontal auto-scrolling.\n\n- Updated dependencies []:\n  - @dnd-kit/abstract@0.1.7\n  - @dnd-kit/collision@0.1.7\n  - @dnd-kit/geometry@0.1.7\n  - @dnd-kit/state@0.1.7\n\n## 0.1.6\n\n### Patch Changes\n\n- [#1671](https://github.com/clauderic/dnd-kit/pull/1671) [`4f49d1b`](https://github.com/clauderic/dnd-kit/commit/4f49d1b1de317adaa05cc0b7adacbaffda4fd8c2) Thanks [@github-actions](https://github.com/apps/github-actions)! - Improve animation handling and scheduling\n\n  - Refactor Scheduler to be more flexible and generic\n  - Cache successive document.getAnimations() calls\n  - Fix bugs in Safari when projecting animations in DOMRectangle\n  - Fix animation handling in Feedback and Sortable components\n\n- [#1672](https://github.com/clauderic/dnd-kit/pull/1672) [`b18115f`](https://github.com/clauderic/dnd-kit/commit/b18115f4b19c45c76c827921b25e47aad16c91ce) Thanks [@GuillaumeSalles](https://github.com/GuillaumeSalles)! - Improve Feedback clone performance by avoiding innerHtml reset on every mutation\n\n- [#1671](https://github.com/clauderic/dnd-kit/pull/1671) [`ac13c92`](https://github.com/clauderic/dnd-kit/commit/ac13c9298cc8b4eb680039cf17fb10582ab8d023) Thanks [@github-actions](https://github.com/apps/github-actions)! - Optimize pointer move handling in PointerSensor by using the rAF scheduler to batch move events.\n\n- Updated dependencies [[`7ceb799`](https://github.com/clauderic/dnd-kit/commit/7ceb799c7d214bc8223ec845357a0040c28ae40e), [`299389b`](https://github.com/clauderic/dnd-kit/commit/299389befcc747fe8d79231ba32f73afae88615e)]:\n  - @dnd-kit/abstract@0.1.6\n  - @dnd-kit/state@0.1.6\n  - @dnd-kit/collision@0.1.6\n  - @dnd-kit/geometry@0.1.6\n\n## 0.1.5\n\n### Patch Changes\n\n- [#1669](https://github.com/clauderic/dnd-kit/pull/1669) [`8fecc41`](https://github.com/clauderic/dnd-kit/commit/8fecc416fb8503fcb555563a44246cd177677b4e) Thanks [@github-actions](https://github.com/apps/github-actions)! - **PointerSensor**: Add support for multiple activator elements via `activatorElements` option to configure multiple elements that can trigger drag operations.\n\n- [#1669](https://github.com/clauderic/dnd-kit/pull/1669) [`a9c17df`](https://github.com/clauderic/dnd-kit/commit/a9c17df386697dc3236f3ba1b7e319cdf4c5a706) Thanks [@github-actions](https://github.com/apps/github-actions)! - Fix `Feedback` drop animation in Safari by always requesting an animation frame before performing the drop animation.\n\n- [#1669](https://github.com/clauderic/dnd-kit/pull/1669) [`f31589a`](https://github.com/clauderic/dnd-kit/commit/f31589ae579f1ce574207d44e4016e30b82549e9) Thanks [@github-actions](https://github.com/apps/github-actions)! - **KeyboardSensor**: Improve configuration options\n\n  - Add configurable offset for keyboard movements (number or {x, y})\n  - Add static `defaults` and `configure` properties for better configuration\n  - Support different x and y offset values for `offset`\n\n- [#1669](https://github.com/clauderic/dnd-kit/pull/1669) [`616db17`](https://github.com/clauderic/dnd-kit/commit/616db17cdded5974febf69718337db0604c613fc) Thanks [@github-actions](https://github.com/apps/github-actions)! - Refactor PointerSensor configuration:\n\n  - Partially configuring the pointer sensor no longer overrides other defaults. If you wish to override all defaults, you must explicitly set each option.\n  - Moved default pointer sensor configuration into to PointerSensor class.\n  - Add static `defaults` property to PointerSensor class for easier configuration and extension.\n\n- Updated dependencies []:\n  - @dnd-kit/abstract@0.1.5\n  - @dnd-kit/collision@0.1.5\n  - @dnd-kit/geometry@0.1.5\n  - @dnd-kit/state@0.1.5\n\n## 0.1.4\n\n### Patch Changes\n\n- [`b1d798d`](https://github.com/clauderic/dnd-kit/commit/b1d798d9454bf1d4c47c4e13d11bfd092bdc668b) Thanks [@clauderic](https://github.com/clauderic)! - Fixed regressions with keyboard sorting.\n\n- Updated dependencies []:\n  - @dnd-kit/abstract@0.1.4\n  - @dnd-kit/collision@0.1.4\n  - @dnd-kit/geometry@0.1.4\n  - @dnd-kit/state@0.1.4\n\n## 0.1.3\n\n### Patch Changes\n\n- [#1663](https://github.com/clauderic/dnd-kit/pull/1663) [`6c9a9ea`](https://github.com/clauderic/dnd-kit/commit/6c9a9ea060095884c90c72cd5d6b73820467ec29) Thanks [@github-actions](https://github.com/apps/github-actions)! - **PointerSensor**: Fixed a bug where `actions.stop()` would not be invoked if the drag operation had not finished initializing.\n\n- [#1663](https://github.com/clauderic/dnd-kit/pull/1663) [`79c6519`](https://github.com/clauderic/dnd-kit/commit/79c65195483bee3909177c1b46d1c1073dd2c765) Thanks [@github-actions](https://github.com/apps/github-actions)! - Fix tracking of initial index and group for `Sortable` instances that unmount and re-mount during a drag operation.\n\n- [#1663](https://github.com/clauderic/dnd-kit/pull/1663) [`52c1ba3`](https://github.com/clauderic/dnd-kit/commit/52c1ba3924be32a9c856d74a3e5221fd05fd91c1) Thanks [@github-actions](https://github.com/apps/github-actions)! - Implement default renderer for DOM using `requestAnimationFrame` to ensure the browser has time to render animation frames.\n\n- [#1663](https://github.com/clauderic/dnd-kit/pull/1663) [`1bef872`](https://github.com/clauderic/dnd-kit/commit/1bef8722d515079f998dc0608084e1d853e74d3a) Thanks [@github-actions](https://github.com/apps/github-actions)! - Improve drag operation control by:\n\n  - Introducing `AbortController` for better operation lifecycle management\n  - Remove `requestAnimationFram()` from `start()` action\n  - Replacing boolean returns with proper abort control\n  - Ensure proper cleanup of drag operations\n  - Improving status handling and initialization checks\n  - Making feedback plugin respect operation initialization state\n\n- [#1663](https://github.com/clauderic/dnd-kit/pull/1663) [`9a0edf6`](https://github.com/clauderic/dnd-kit/commit/9a0edf64cbde1bd761f3650e043b6612e61a5fab) Thanks [@github-actions](https://github.com/apps/github-actions)! - Refactor Sortable store implementation to use a new `WeakStore` class\n\n  - Add new `WeakStore` constructor in `@dnd-kit/state` package\n  - Replace Map-based store implementation in Sortable with new WeakStore utility\n\n- [#1663](https://github.com/clauderic/dnd-kit/pull/1663) [`18a7998`](https://github.com/clauderic/dnd-kit/commit/18a7998858e6504f0e3c6f613bd174eb9f68e553) Thanks [@github-actions](https://github.com/apps/github-actions)! - Removed unnecessary microtask in Sortable animation logic when index changes\n\n- Updated dependencies [[`8f91d91`](https://github.com/clauderic/dnd-kit/commit/8f91d9112608d2077c3b6c8fc939aa052606148c), [`6c9a9ea`](https://github.com/clauderic/dnd-kit/commit/6c9a9ea060095884c90c72cd5d6b73820467ec29), [`1bef872`](https://github.com/clauderic/dnd-kit/commit/1bef8722d515079f998dc0608084e1d853e74d3a), [`2522836`](https://github.com/clauderic/dnd-kit/commit/2522836fdb80520913ea35d94c6558bf7784afc9), [`9a0edf6`](https://github.com/clauderic/dnd-kit/commit/9a0edf64cbde1bd761f3650e043b6612e61a5fab), [`a9db4c7`](https://github.com/clauderic/dnd-kit/commit/a9db4c73467d9eda9f95fe5b582948c9fc735f57)]:\n  - @dnd-kit/state@0.1.3\n  - @dnd-kit/abstract@0.1.3\n  - @dnd-kit/geometry@0.1.3\n  - @dnd-kit/collision@0.1.3\n\n## 0.1.2\n\n### Patch Changes\n\n- [#1658](https://github.com/clauderic/dnd-kit/pull/1658) [`4682570`](https://github.com/clauderic/dnd-kit/commit/4682570a6b80868af0e51b1bbbf902430117df43) Thanks [@github-actions](https://github.com/apps/github-actions)! - Fix handling of aborted drag operations across sensors. The `start` method now returns a boolean to indicate whether the operation was aborted, allowing sensors to properly clean up when a drag operation is prevented. This affects the Keyboard and Pointer sensors, ensuring they properly handle cases where `beforeDragStart` events are prevented.\n\n- [#1658](https://github.com/clauderic/dnd-kit/pull/1658) [`f8d69b0`](https://github.com/clauderic/dnd-kit/commit/f8d69b01f4cf53fc368ef1fca9188c313192928d) Thanks [@github-actions](https://github.com/apps/github-actions)! - Allow `actions.start()` to optionally receive a `source` as input.\n\n- [#1658](https://github.com/clauderic/dnd-kit/pull/1658) [`ee55f58`](https://github.com/clauderic/dnd-kit/commit/ee55f582f92dc42cc6eea9ad7492fc782ca6455a) Thanks [@github-actions](https://github.com/apps/github-actions)! - Refactor the drag operation system to improve code organization and maintainability:\n\n  - Split `dragOperation.ts` into multiple focused files:\n    - `operation.ts` - Core drag operation logic\n    - `status.ts` - Status management\n    - `actions.ts` - Drag actions\n  - Update imports and exports to reflect new file structure\n  - Improve type definitions and exports\n\n- [#1660](https://github.com/clauderic/dnd-kit/pull/1660) [`374f81f`](https://github.com/clauderic/dnd-kit/commit/374f81f84c9401729e2e0ee48520c647a48e5afd) Thanks [@GuillaumeSalles](https://github.com/GuillaumeSalles)! - Add option `shouldActivate` on `KeyboardSensor`. By default `KeyboardSensor` activates if the Keyboard event is triggered from the `Draggable` `element` or `handle`. `shouldActivate` let the user override this behavior.\n\n- Updated dependencies [[`ee55f58`](https://github.com/clauderic/dnd-kit/commit/ee55f582f92dc42cc6eea9ad7492fc782ca6455a), [`4682570`](https://github.com/clauderic/dnd-kit/commit/4682570a6b80868af0e51b1bbbf902430117df43), [`f8d69b0`](https://github.com/clauderic/dnd-kit/commit/f8d69b01f4cf53fc368ef1fca9188c313192928d), [`d04e9a2`](https://github.com/clauderic/dnd-kit/commit/d04e9a2879fb00f092c3f8280c8081a48eebf193), [`ee55f58`](https://github.com/clauderic/dnd-kit/commit/ee55f582f92dc42cc6eea9ad7492fc782ca6455a)]:\n  - @dnd-kit/state@0.1.2\n  - @dnd-kit/geometry@0.1.2\n  - @dnd-kit/abstract@0.1.2\n  - @dnd-kit/collision@0.1.2\n\n## 0.1.1\n\n### Patch Changes\n\n- [#1656](https://github.com/clauderic/dnd-kit/pull/1656) [`569b6e3`](https://github.com/clauderic/dnd-kit/commit/569b6e3a1d3b199328f7a2362a10b446e657726f) Thanks [@github-actions](https://github.com/apps/github-actions)! - Export `SortableKeyboardPlugin` and `OptimisticSortingPlugin` from the sortable module to allow consumers to customize their sortable plugin configurations.\n\n- [#1655](https://github.com/clauderic/dnd-kit/pull/1655) [`a176848`](https://github.com/clauderic/dnd-kit/commit/a1768481e3f7dc4d1176a7fcb363acd020f2c46c) Thanks [@blancham](https://github.com/blancham)! - Fixed a bug where auto-scroll does not wotk with inverted element\n\n- Updated dependencies [[`f13cbc9`](https://github.com/clauderic/dnd-kit/commit/f13cbc978229844770d3c8aa03135e4352ee2532)]:\n  - @dnd-kit/abstract@0.1.1\n  - @dnd-kit/collision@0.1.1\n  - @dnd-kit/geometry@0.1.1\n  - @dnd-kit/state@0.1.1\n\n## 0.1.0\n\n### Patch Changes\n\n- [#1645](https://github.com/clauderic/dnd-kit/pull/1645) [`043c280`](https://github.com/clauderic/dnd-kit/commit/043c2807a7aa290ce9838a638422245b0bd89cf1) Thanks [@clauderic](https://github.com/clauderic)! - Add fallback logic to type-guards when instance checks fail to identify instances, for example to test if an element is an `Element` or `HTMLElement` or `SVGElement`, or if an `AnimationEffect` is a `KeyframeEffect`.\n\n- [#1644](https://github.com/clauderic/dnd-kit/pull/1644) [`ee40aac`](https://github.com/clauderic/dnd-kit/commit/ee40aacda6c015b1f357182c461650fde4c6704e) Thanks [@github-actions](https://github.com/apps/github-actions)! - **Feedback**: Use `revert` instead of `unset` to reset styles applied by the `popover` attribute.\n\n- [#1643](https://github.com/clauderic/dnd-kit/pull/1643) [`635d94f`](https://github.com/clauderic/dnd-kit/commit/635d94f6e719bcdf50e0024b6d1f09b9bb46c8a5) Thanks [@clauderic](https://github.com/clauderic)! - Fix a bug in the `Scroller` plugin that would always use `document.getElementFromPoint` instead of the document of the source element.\n\n- [#1644](https://github.com/clauderic/dnd-kit/pull/1644) [`0235cef`](https://github.com/clauderic/dnd-kit/commit/0235cefcf4942c86189e81fde4dc8f19ad420517) Thanks [@github-actions](https://github.com/apps/github-actions)! - **Cursor**: Ensure styles for Cursor plugin are added to the document of the draggable source element.\n\n- [#1644](https://github.com/clauderic/dnd-kit/pull/1644) [`1ba8700`](https://github.com/clauderic/dnd-kit/commit/1ba8700fd03f3fdc8f4fabe90befbc8fd54d99f5) Thanks [@github-actions](https://github.com/apps/github-actions)! - Fixed a bug in the `getDocument` helper to make it work with SVG elements.\n\n- [#1644](https://github.com/clauderic/dnd-kit/pull/1644) [`3080d2c`](https://github.com/clauderic/dnd-kit/commit/3080d2c8c122beabc41fb8d79beceb2188a01947) Thanks [@github-actions](https://github.com/apps/github-actions)! - **Feedback**: Set `popover` attribute value to `manual`.\n\n- Updated dependencies [[`00a33c9`](https://github.com/clauderic/dnd-kit/commit/00a33c99e777ab205a45309a4efc8b3560bafdaf)]:\n  - @dnd-kit/abstract@0.1.0\n  - @dnd-kit/collision@0.1.0\n  - @dnd-kit/geometry@0.1.0\n  - @dnd-kit/state@0.1.0\n\n## 0.0.10\n\n### Patch Changes\n\n- [#1606](https://github.com/clauderic/dnd-kit/pull/1606) [`2c53eb9`](https://github.com/clauderic/dnd-kit/commit/2c53eb95a980d143b179af5b7f0a071cdedd9089) Thanks [@github-actions](https://github.com/apps/github-actions)! - Use the `draggable.isDragging` property instead of `draggable.isDragSource` to set `aria-grabbing` and `aria-pressed` attributes.\n\n- [#1606](https://github.com/clauderic/dnd-kit/pull/1606) [`3155941`](https://github.com/clauderic/dnd-kit/commit/3155941608dbf16ed867e931381e7bb2c65a126d) Thanks [@github-actions](https://github.com/apps/github-actions)! - Fixed a bug with the `Feedback` plugin where the placeholder element was visible for a brief moment during the drop animation instead of being hidden until the animation completes.\n\n- [#1606](https://github.com/clauderic/dnd-kit/pull/1606) [`082836e`](https://github.com/clauderic/dnd-kit/commit/082836e517252262b7984b142093ba6c81c43ba8) Thanks [@github-actions](https://github.com/apps/github-actions)! - Fixed a bug with the `PointerSensor` where it was possible for it to activate while a drag operation was already in progress.\n\n- Updated dependencies []:\n  - @dnd-kit/abstract@0.0.10\n  - @dnd-kit/collision@0.0.10\n  - @dnd-kit/geometry@0.0.10\n  - @dnd-kit/state@0.0.10\n\n## 0.0.9\n\n### Patch Changes\n\n- [#1600](https://github.com/clauderic/dnd-kit/pull/1600) [`e36d954`](https://github.com/clauderic/dnd-kit/commit/e36d95420148659ba78bdbefd3a0a24ec5d02b8f) Thanks [@github-actions](https://github.com/apps/github-actions)! - Added `nativeEvent` property to `dragstart`, `dragmove` and `dragend` events. This can be used to distinguish user triggered events from sensor triggered events, as user or plugin triggered events will typically not have an associated `event` attached.\n\n- [#1600](https://github.com/clauderic/dnd-kit/pull/1600) [`bb4abcd`](https://github.com/clauderic/dnd-kit/commit/bb4abcd1957f2562072059ad8b5e701893a0fede) Thanks [@github-actions](https://github.com/apps/github-actions)! - Make sure the Feedback element is promoted to the top layer when synchronizing the placeholder and element position in the DOM.\n\n- [#1600](https://github.com/clauderic/dnd-kit/pull/1600) [`d86bbc7`](https://github.com/clauderic/dnd-kit/commit/d86bbc7e73ba16296c48f9af29f1893624157a0f) Thanks [@github-actions](https://github.com/apps/github-actions)! - Added `alignment` configuration option to draggable instances to let consumers decide how to align the draggable during the drop animation and while keyboard sorting. Defaults to the center of the target shape.\n\n- [#1600](https://github.com/clauderic/dnd-kit/pull/1600) [`f433fb2`](https://github.com/clauderic/dnd-kit/commit/f433fb21aa76c5b4badeec6423e3c930006c8d70) Thanks [@github-actions](https://github.com/apps/github-actions)! - Fixed a regression in the `Feedback` plugin where the initial `translate` style applied to the element being dragged was not properly accounted for anymore.\n\n- [#1600](https://github.com/clauderic/dnd-kit/pull/1600) [`7dc0103`](https://github.com/clauderic/dnd-kit/commit/7dc0103c5e5281e9ee61bcd9c3ab493fc9307073) Thanks [@github-actions](https://github.com/apps/github-actions)! - Removed some `!important` rules and updated the specificity of the `Feedback` plugin styles to `0-2-0` to make it easier for consumers to override certain styles, such as `width` and `height`.\n\n- [`cff3c3c`](https://github.com/clauderic/dnd-kit/commit/cff3c3cbbe96a6f401cb3900a8cd5f727a974c2d) Thanks [@clauderic](https://github.com/clauderic)! - Fixed a bug with the drop animation by using `intrinsicWidth` and `intrinsicHeight` to determine if the width and height of the source and target differ or not rather than the `width` and `height` properties which may be transformed.\n\n- [#1600](https://github.com/clauderic/dnd-kit/pull/1600) [`f87d633`](https://github.com/clauderic/dnd-kit/commit/f87d63347529f5c9600bcffb14ad2d15ff6eb107) Thanks [@github-actions](https://github.com/apps/github-actions)! - Fixed a regression introduced in `0.0.7` with optimistic updates not being persisted on drag end.\n\n- [`860759b`](https://github.com/clauderic/dnd-kit/commit/860759b15167616c465eef1738fd02c76aa53cb3) Thanks [@clauderic](https://github.com/clauderic)! - Added `intrinsicWidth` and `intrinsicHeight` properties on `DOMRectangle`, which return the intrinsic width and height of an element, before any transforms are applied.\n\n- [#1600](https://github.com/clauderic/dnd-kit/pull/1600) [`54e416f`](https://github.com/clauderic/dnd-kit/commit/54e416f6f0aaa19c11827f80b2df796bfe237ba0) Thanks [@github-actions](https://github.com/apps/github-actions)! - Only handle `dragmove` events that have an associated `KeyboardEvent` as their `event.nativeEvent` property.\n\n- [#1600](https://github.com/clauderic/dnd-kit/pull/1600) [`c51778d`](https://github.com/clauderic/dnd-kit/commit/c51778dde5bcd614b1891c5f7659130769ddc9f8) Thanks [@github-actions](https://github.com/apps/github-actions)! - **PointerSensor**: Use `capture` listener to prevent `dragstart` events.\n\n- [#1600](https://github.com/clauderic/dnd-kit/pull/1600) [`86ed6c8`](https://github.com/clauderic/dnd-kit/commit/86ed6c8e203bb167d451c36605c2a0e0d33f0157) Thanks [@github-actions](https://github.com/apps/github-actions)! - Fixed a regression in the `PointerSensor` where the same drag operation could fire a dragend event twice due to a race condition between `pointerup` and `lostpointercapture`.\n\n- [#1600](https://github.com/clauderic/dnd-kit/pull/1600) [`afedea9`](https://github.com/clauderic/dnd-kit/commit/afedea930bbfd1ea546c2bcbe5f42a3ea8b913fe) Thanks [@github-actions](https://github.com/apps/github-actions)! - **PreventSelection**: Remove text selection when a drag operation is initialized.\n\n- Updated dependencies [[`e36d954`](https://github.com/clauderic/dnd-kit/commit/e36d95420148659ba78bdbefd3a0a24ec5d02b8f), [`60e7297`](https://github.com/clauderic/dnd-kit/commit/60e72979850bfe4cbb8e2b2e2b8e84bce9edc9f5), [`3463da1`](https://github.com/clauderic/dnd-kit/commit/3463da1cac9f26e4b2ab3278ae52206bb99645e4), [`b7f1cf8`](https://github.com/clauderic/dnd-kit/commit/b7f1cf8f9e15a285c45f896e092f61001335cdff), [`3e629cc`](https://github.com/clauderic/dnd-kit/commit/3e629cc81dbaf9d112c4f1d2c10c75eb6779cf4e), [`8ae7014`](https://github.com/clauderic/dnd-kit/commit/8ae70143bc404bff7678fa8e8390a640c16f2579), [`ce31da7`](https://github.com/clauderic/dnd-kit/commit/ce31da736ec5d4f48bab45430be7b57223d60ee7)]:\n  - @dnd-kit/abstract@0.0.9\n  - @dnd-kit/geometry@0.0.9\n  - @dnd-kit/collision@0.0.9\n  - @dnd-kit/state@0.0.9\n\n## 0.0.8\n\n### Patch Changes\n\n- [#1598](https://github.com/clauderic/dnd-kit/pull/1598) [`0de7456`](https://github.com/clauderic/dnd-kit/commit/0de7456ade17b9a0aa127b8adf13495e7fdf1558) Thanks [@github-actions](https://github.com/apps/github-actions)! - Moved styles that override the default user agent styles for `[popover]` into a CSS layer to avoid overriding other layered styles on the page, such as Tailwind 4.\n\n- [#1598](https://github.com/clauderic/dnd-kit/pull/1598) [`c9716cf`](https://github.com/clauderic/dnd-kit/commit/c9716cf7b8b846faab451bd2f60c53c77d2d24ba) Thanks [@github-actions](https://github.com/apps/github-actions)! - Added `isDragging` and `isDropping` properties to `draggable` and `sortable` instances.\n\n- [#1598](https://github.com/clauderic/dnd-kit/pull/1598) [`74eedef`](https://github.com/clauderic/dnd-kit/commit/74eedef3441dc07d8fa8dd9337a6b2d748b0cdde) Thanks [@github-actions](https://github.com/apps/github-actions)! - **PointerSensor**\n\n  - End drag operation if `lostpointercapture` event is fired and the drag operation has not ended already. This can happen if the `pointerup` event is fired in a different frame.\n  - Prevent `contextmenu` from opening during a drag operation.\n\n- [#1598](https://github.com/clauderic/dnd-kit/pull/1598) [`42e7256`](https://github.com/clauderic/dnd-kit/commit/42e7256e7fb9c11ed6295b77e30c41ebe66a15d1) Thanks [@github-actions](https://github.com/apps/github-actions)! - - Fixed an invalid CSS selector in the `PreventSelection` plugin\n  - Removed logic to prevent user selection in `Feedback` plugin (defer to `PreventSelection` plugin to handle this)\n- Updated dependencies [[`c9716cf`](https://github.com/clauderic/dnd-kit/commit/c9716cf7b8b846faab451bd2f60c53c77d2d24ba), [`3ea0d31`](https://github.com/clauderic/dnd-kit/commit/3ea0d314649b186bfe0524d50145625da13a8787), [`3cf4db1`](https://github.com/clauderic/dnd-kit/commit/3cf4db126813ebe6ddfc025df5e42e9bfcfa9c38)]:\n  - @dnd-kit/abstract@0.0.8\n  - @dnd-kit/collision@0.0.8\n  - @dnd-kit/geometry@0.0.8\n  - @dnd-kit/state@0.0.8\n\n## 0.0.7\n\n### Patch Changes\n\n- [#1592](https://github.com/clauderic/dnd-kit/pull/1592) [`550a868`](https://github.com/clauderic/dnd-kit/commit/550a86870d7441a38a06b3e7c35aa0d7d89e32d1) Thanks [@github-actions](https://github.com/apps/github-actions)! - Added `aria-grabbed` to the list of attributes added by the Accessibility plugin.\n\n  Setting aria-grabbed to true indicates that the element has been selected for dragging. Setting aria-grabbed to false indicates that the element can be grabbed for a drag-and-drop operation, but is not currently grabbed.\n\n  While the `aria-grabbed` attribute has been deprecated in ARIA 1.1, in practice, since the accessibility API features for accessible drag and drop still don’t exist and likely won’t for several years, these attributes will continue to be supported by browsers and reflected in the accessibility tree for some years to come until a new API is introduced to replace it.\n\n- [#1592](https://github.com/clauderic/dnd-kit/pull/1592) [`75e23b6`](https://github.com/clauderic/dnd-kit/commit/75e23b6fdfdeadeae1b9a4b2b9be7682f48c10e4) Thanks [@github-actions](https://github.com/apps/github-actions)! - Added `aria-grabbed` and `aria-pressed` to the list of attributes that are not synchronized between the draggable element and its placeholder.\n\n- [#1592](https://github.com/clauderic/dnd-kit/pull/1592) [`cef9b46`](https://github.com/clauderic/dnd-kit/commit/cef9b46c5ed017e6a601b1d0ee9d0f05b7bbd19f) Thanks [@github-actions](https://github.com/apps/github-actions)! - Fix global modifiers set on `DragDropManager` / `<DragDropProvider>` being destroyed after the first drag operation.\n\n- [#1592](https://github.com/clauderic/dnd-kit/pull/1592) [`730064b`](https://github.com/clauderic/dnd-kit/commit/730064b8b06bd25ebde335305a303fdf4c9a9c7f) Thanks [@github-actions](https://github.com/apps/github-actions)! - Fix incorrect type for modifiers.\n\n- [#1592](https://github.com/clauderic/dnd-kit/pull/1592) [`808f184`](https://github.com/clauderic/dnd-kit/commit/808f184439125cf7e66054b3e85ac087aa04f13b) Thanks [@github-actions](https://github.com/apps/github-actions)! - Fix reconciliation of optimistic updates in `move` helper.\n\n- [#1592](https://github.com/clauderic/dnd-kit/pull/1592) [`c4e7a7c`](https://github.com/clauderic/dnd-kit/commit/c4e7a7cd98ccaec99fa1037cb1020d3d05cea090) Thanks [@github-actions](https://github.com/apps/github-actions)! - Fixed positioning of `Feedback` plugin when `direction` is set to `rtl`.\n\n- [#1592](https://github.com/clauderic/dnd-kit/pull/1592) [`280b7e2`](https://github.com/clauderic/dnd-kit/commit/280b7e229d5e6a5f067a66038e50c4fbb3b29dc0) Thanks [@github-actions](https://github.com/apps/github-actions)! - Fixed stale modifiers when using `useSortable`.\n\n- [#1592](https://github.com/clauderic/dnd-kit/pull/1592) [`84b75fc`](https://github.com/clauderic/dnd-kit/commit/84b75fc3a7b7a555481dbeba533bc28128783e72) Thanks [@github-actions](https://github.com/apps/github-actions)! - Fixed `element` not being set on initialization of `Sortable` instance even if an `element` was provided as input.\n\n- Updated dependencies [[`c1dadef`](https://github.com/clauderic/dnd-kit/commit/c1dadef118f8f5f096d36dac314bfe317ea950ce), [`cef9b46`](https://github.com/clauderic/dnd-kit/commit/cef9b46c5ed017e6a601b1d0ee9d0f05b7bbd19f)]:\n  - @dnd-kit/abstract@0.0.7\n  - @dnd-kit/collision@0.0.7\n  - @dnd-kit/geometry@0.0.7\n  - @dnd-kit/state@0.0.7\n\n## 0.0.6\n\n### Patch Changes\n\n- [#1567](https://github.com/clauderic/dnd-kit/pull/1567) [`081b7f2`](https://github.com/clauderic/dnd-kit/commit/081b7f2a11da2aad8ce3da7f0579974415d1fdf0) Thanks [@chrisvxd](https://github.com/chrisvxd)! - Add source maps to output.\n\n- [#1499](https://github.com/clauderic/dnd-kit/pull/1499) [`d436037`](https://github.com/clauderic/dnd-kit/commit/d43603740a4d056e9fc7501e9b2117c173b1df4d) Thanks [@chrisvxd](https://github.com/chrisvxd)! - Fix a bug that prevented all unique droppables that share an element from each receiving the cloned proxy.\n\n- [#1454](https://github.com/clauderic/dnd-kit/pull/1454) [`94920c8`](https://github.com/clauderic/dnd-kit/commit/94920c8a7a3a15accfb806b52e4935637b1a0781) Thanks [@github-actions](https://github.com/apps/github-actions)! - Batch write operations to `draggable` and `droppable`. Also ensured that droppable instance is registered before draggable instance.\n\n- [#1454](https://github.com/clauderic/dnd-kit/pull/1454) [`a04d3f8`](https://github.com/clauderic/dnd-kit/commit/a04d3f88d380853b97585ab3b608561f7b02ce69) Thanks [@github-actions](https://github.com/apps/github-actions)! - Rework how collisions are detected and how the position of elements is observed using a new `PositionObserver`.\n\n- [#1454](https://github.com/clauderic/dnd-kit/pull/1454) [`0676276`](https://github.com/clauderic/dnd-kit/commit/0676276f5423dbb4e0cad738ac3784937dc7504b) Thanks [@github-actions](https://github.com/apps/github-actions)! - Children contained in a closed `details ` element are no longer treated as visible.\n\n- [#1454](https://github.com/clauderic/dnd-kit/pull/1454) [`8053e4b`](https://github.com/clauderic/dnd-kit/commit/8053e4b4a727c6097b29fb559ce72362d7d6eb2a) Thanks [@github-actions](https://github.com/apps/github-actions)! - Allow `Sortable` to have a distinct `element` from the underlying `source` and `target` elements. This can be useful if you want the collision detection to operate on a subset of the sortable element, but the entirety of the element to move when its index changes.\n\n- [#1454](https://github.com/clauderic/dnd-kit/pull/1454) [`f400106`](https://github.com/clauderic/dnd-kit/commit/f400106072d12a902f6c113b889c7de97f43e1ea) Thanks [@github-actions](https://github.com/apps/github-actions)! - Improve the `Feedback` plugin to better handle when the feedback element resizes during a drag operation.\n\n- [#1454](https://github.com/clauderic/dnd-kit/pull/1454) [`c597b3f`](https://github.com/clauderic/dnd-kit/commit/c597b3fe1514f10e227c287dc8ad875134e9b4cb) Thanks [@github-actions](https://github.com/apps/github-actions)! - Introduce `rootElement` option on `Feedback` plugin.\n\n- [#1454](https://github.com/clauderic/dnd-kit/pull/1454) [`a9798f4`](https://github.com/clauderic/dnd-kit/commit/a9798f43450e406e8cb235b7d5fba8bb809fd1d7) Thanks [@github-actions](https://github.com/apps/github-actions)! - Fix issues with `instanceof` checks in cross-window environments where the `window` of an element can differ from the execution context window.\n\n- [#1454](https://github.com/clauderic/dnd-kit/pull/1454) [`e70b29a`](https://github.com/clauderic/dnd-kit/commit/e70b29ae64837e424f7279c95112fb6e420c4dcc) Thanks [@github-actions](https://github.com/apps/github-actions)! - Make sure the generic for `DragDropManager` is passed through to `Entity` so that the `manager` reference on classes extending `Entity` is strongly typed.\n\n- [#1454](https://github.com/clauderic/dnd-kit/pull/1454) [`3d0b00a`](https://github.com/clauderic/dnd-kit/commit/3d0b00a663b9dc38ccd7a46544c94a342694b626) Thanks [@github-actions](https://github.com/apps/github-actions)! - Fix an issue where we would update the shape of sortable items while the drag operation status was idle.\n\n- [#1454](https://github.com/clauderic/dnd-kit/pull/1454) [`e6a8e01`](https://github.com/clauderic/dnd-kit/commit/e6a8e018d2d7ad9a11e5b05f07774c7e3ac08da3) Thanks [@github-actions](https://github.com/apps/github-actions)! - Fix a bug with `event.preventDefault()` and `event.stopPropagation()` being called on pointer up even if there was no drag operation in progress, which would prevent interactive elements such as buttons from being clicked.\n\n- [#1454](https://github.com/clauderic/dnd-kit/pull/1454) [`7ef9864`](https://github.com/clauderic/dnd-kit/commit/7ef98642207c8beac1ca7e2704ce8805767dc89d) Thanks [@github-actions](https://github.com/apps/github-actions)! - Fixed bugs with the `OptimisticSortingPlugin` when sorting across different groups.\n\n- [#1454](https://github.com/clauderic/dnd-kit/pull/1454) [`51be6df`](https://github.com/clauderic/dnd-kit/commit/51be6dfe1b8cb42f74df34c76098e197b9208f81) Thanks [@github-actions](https://github.com/apps/github-actions)! - Fix `element` not being set when provided on initialization of `Droppable`\n\n- [#1454](https://github.com/clauderic/dnd-kit/pull/1454) [`fe76033`](https://github.com/clauderic/dnd-kit/commit/fe7603330fb4b0a397c0e2af641df94fc2879c35) Thanks [@github-actions](https://github.com/apps/github-actions)! - Fixed a bug in the `KeyboardSensor` that would cause the sensor to activate when focusing elements within the sortable element other than the handle.\n\n- [#1454](https://github.com/clauderic/dnd-kit/pull/1454) [`62a8118`](https://github.com/clauderic/dnd-kit/commit/62a81180c84f7782b14b69b56f891c810e7d0f69) Thanks [@github-actions](https://github.com/apps/github-actions)! - Added `Tab` to the list of default keycodes that end the current drag operation.\n\n- [#1454](https://github.com/clauderic/dnd-kit/pull/1454) [`0c7bf85`](https://github.com/clauderic/dnd-kit/commit/0c7bf85897992dc48c3cf2f1deeaa896995bfcc3) Thanks [@github-actions](https://github.com/apps/github-actions)! - Allow the `OptimisticSortingPlugin` to sort elements across different groups.\n\n- [#1454](https://github.com/clauderic/dnd-kit/pull/1454) [`f219549`](https://github.com/clauderic/dnd-kit/commit/f219549087d9100cee53ab0cf35d820fe256aa85) Thanks [@github-actions](https://github.com/apps/github-actions)! - Fix pointer events no longer being detected by the `PointerSensor` when the event target is disconnected from the DOM by setting pointer capture on the document body for `pointermove` events.\n\n- [#1454](https://github.com/clauderic/dnd-kit/pull/1454) [`bfc8ab2`](https://github.com/clauderic/dnd-kit/commit/bfc8ab21cfd9c16a8d90ab250386e6d52d0a40a3) Thanks [@github-actions](https://github.com/apps/github-actions)! - **PointerSensor**: Defer invoking `setPointerCapture` until activation constraints are met as it can interfere with `click` and other event handlers. Also deferred adding `touchmove`, `click` and `keydown` event listeners until the activation constraints are met.\n\n- [#1454](https://github.com/clauderic/dnd-kit/pull/1454) [`a5a556a`](https://github.com/clauderic/dnd-kit/commit/a5a556abfeec1d78effb3e047f529555e444c020) Thanks [@github-actions](https://github.com/apps/github-actions)! - Fixed React lifecycle regressions related to StrictMode.\n\n- [#1454](https://github.com/clauderic/dnd-kit/pull/1454) [`b5edff1`](https://github.com/clauderic/dnd-kit/commit/b5edff19279c07bbcd54ebc4579817b8a36cfff5) Thanks [@github-actions](https://github.com/apps/github-actions)! - Remove `event.stopImmediatePropagation()` in `PointerSensor` and replace with a different strategy to prevent other instances of PointerSensor from tracking an event that was already captured by another sensor.\n\n- [#1454](https://github.com/clauderic/dnd-kit/pull/1454) [`3fb972e`](https://github.com/clauderic/dnd-kit/commit/3fb972e228aabfe07d662b77c642405f909fddb0) Thanks [@github-actions](https://github.com/apps/github-actions)! - **AccessibilityPlugin**: Force `tabindex=\"0\"` in Safari even for natively focusable elements as they are not always focusable by default.\n\n- [#1454](https://github.com/clauderic/dnd-kit/pull/1454) [`5b36f8f`](https://github.com/clauderic/dnd-kit/commit/5b36f8fb36f5a4468793b469425b5c0461426f56) Thanks [@github-actions](https://github.com/apps/github-actions)! - Allow sortable animations when changing to a different group even when the index remains the same.\n\n- [#1454](https://github.com/clauderic/dnd-kit/pull/1454) [`69bfad7`](https://github.com/clauderic/dnd-kit/commit/69bfad7d795947987a4281f1a61f81b6a7839fe8) Thanks [@github-actions](https://github.com/apps/github-actions)! - `SortableKeyboardPlugin`: Use `closestCorners` collision detection algorithm instead of `closestCenter` when keyboard sorting.\n\n- [#1517](https://github.com/clauderic/dnd-kit/pull/1517) [`c42a11b`](https://github.com/clauderic/dnd-kit/commit/c42a11b60e950d50f8c243bdf8df4f32e1d47d23) Thanks [@clauderic](https://github.com/clauderic)! - Support dragging across same-origin iframes.\n\n- Updated dependencies [[`984b5ab`](https://github.com/clauderic/dnd-kit/commit/984b5ab7bec3145dedb9c9b3b560ffbf7e54b919), [`081b7f2`](https://github.com/clauderic/dnd-kit/commit/081b7f2a11da2aad8ce3da7f0579974415d1fdf0), [`69bfad7`](https://github.com/clauderic/dnd-kit/commit/69bfad7d795947987a4281f1a61f81b6a7839fe8), [`a04d3f8`](https://github.com/clauderic/dnd-kit/commit/a04d3f88d380853b97585ab3b608561f7b02ce69), [`a8542de`](https://github.com/clauderic/dnd-kit/commit/a8542de56d39c3cd3b6ef981172a0782454295b2), [`f7458d9`](https://github.com/clauderic/dnd-kit/commit/f7458d9dc32824dbea3a6d5dfb29236f19a2c073), [`b750c05`](https://github.com/clauderic/dnd-kit/commit/b750c05b4b14f5d9817dc07d974d40b74470e904), [`e70b29a`](https://github.com/clauderic/dnd-kit/commit/e70b29ae64837e424f7279c95112fb6e420c4dcc), [`4d1a030`](https://github.com/clauderic/dnd-kit/commit/4d1a0306c920ae064eb5b30c4c02961f50460c84), [`a6366f9`](https://github.com/clauderic/dnd-kit/commit/a6366f9e42836b4c5732141bf314489ede9f60cb), [`a5933d8`](https://github.com/clauderic/dnd-kit/commit/a5933d8607e63ed08818ffab43e858863cb35d47), [`a5a556a`](https://github.com/clauderic/dnd-kit/commit/a5a556abfeec1d78effb3e047f529555e444c020), [`96f28ef`](https://github.com/clauderic/dnd-kit/commit/96f28ef86adf95e77540732d39033c7f3fb0fd04), [`71dc39f`](https://github.com/clauderic/dnd-kit/commit/71dc39fb2ec21b9a680238a91be419c71ecabe86)]:\n  - @dnd-kit/abstract@0.0.6\n  - @dnd-kit/collision@0.0.6\n  - @dnd-kit/geometry@0.0.6\n  - @dnd-kit/state@0.0.6\n\n## 0.0.5\n\n### Patch Changes\n\n- Updated dependencies [[`e9be505`](https://github.com/clauderic/dnd-kit/commit/e9be5051b5c99e522fb6efd028d425220b171890)]:\n  - @dnd-kit/abstract@0.0.5\n  - @dnd-kit/collision@0.0.5\n  - @dnd-kit/geometry@0.0.5\n  - @dnd-kit/state@0.0.5\n\n## 0.0.4\n\n### Patch Changes\n\n- [#1443](https://github.com/clauderic/dnd-kit/pull/1443) [`2ccc27c`](https://github.com/clauderic/dnd-kit/commit/2ccc27c566b13d6de46719d0ad5978d655261177) Thanks [@clauderic](https://github.com/clauderic)! - Added `status` property to draggable instances to know the current status of a draggable instance. Useful to know if an instance is being dropped.\n\n- [#1443](https://github.com/clauderic/dnd-kit/pull/1443) [`1b9df29`](https://github.com/clauderic/dnd-kit/commit/1b9df29e03306c6d3fb3e8b2b321486f5c62847a) Thanks [@clauderic](https://github.com/clauderic)! - Force pointer events on children of the feedback element to `none`.\n\n- [#1443](https://github.com/clauderic/dnd-kit/pull/1443) [`4dbcb1c`](https://github.com/clauderic/dnd-kit/commit/4dbcb1c87c34273fecf7257cd4cb5ac67b42d3a4) Thanks [@clauderic](https://github.com/clauderic)! - Fix bugs with PointerSensor when interacting with anchor or image elements.\n\n- [#1443](https://github.com/clauderic/dnd-kit/pull/1443) [`e0d80f5`](https://github.com/clauderic/dnd-kit/commit/e0d80f59c733b3adcf1fc89d29aa80257e7edd98) Thanks [@clauderic](https://github.com/clauderic)! - Refactor the lifecycle to allow `manager` to be optional and provided later during the lifecycle of `draggable` / `droppable` / `sortable` instances.\n\n- [#1443](https://github.com/clauderic/dnd-kit/pull/1443) [`794cf2f`](https://github.com/clauderic/dnd-kit/commit/794cf2f4bdeeb57a197effb1df654c7c44cf34a3) Thanks [@clauderic](https://github.com/clauderic)! - Removed `options` and `options.register` from `Entity` base class. Passing an `undefined` manager when instantiating `Draggable` and `Droppable` now has the same effect.\n\n- Updated dependencies [[`2ccc27c`](https://github.com/clauderic/dnd-kit/commit/2ccc27c566b13d6de46719d0ad5978d655261177), [`a4d9150`](https://github.com/clauderic/dnd-kit/commit/a4d91500124698abf58355592913f84d438faa3d), [`e0d80f5`](https://github.com/clauderic/dnd-kit/commit/e0d80f59c733b3adcf1fc89d29aa80257e7edd98), [`794cf2f`](https://github.com/clauderic/dnd-kit/commit/794cf2f4bdeeb57a197effb1df654c7c44cf34a3)]:\n  - @dnd-kit/abstract@0.0.4\n  - @dnd-kit/state@0.0.4\n  - @dnd-kit/collision@0.0.4\n  - @dnd-kit/geometry@0.0.4\n\n## 0.0.3\n\n### Patch Changes\n\n- [`8530c12`](https://github.com/clauderic/dnd-kit/commit/8530c122c8db7723a8c13a207a11487b3354cb59) Thanks [@clauderic](https://github.com/clauderic)! - Fixed lifecycle related issues.\n\n- [#1440](https://github.com/clauderic/dnd-kit/pull/1440) [`8e45c2a`](https://github.com/clauderic/dnd-kit/commit/8e45c2a9d750283296b56b05a887be89fe7b0184) Thanks [@clauderic](https://github.com/clauderic)! - Better handling of elements that have `transform` or `translate` applied. The Feedback and Sortable plugins now no longer need to ignore transforms as the `DOMRectangle` can compute the projected final coordinates of an element that has transforms applied even if it is currently being animated by looking at the last animation keyframe.\n\n- Updated dependencies [[`5ccd5e6`](https://github.com/clauderic/dnd-kit/commit/5ccd5e668fb8d736ec3c195116559cb5c5684e80), [`886de33`](https://github.com/clauderic/dnd-kit/commit/886de33d0df851ebdcb3fcf2915f9623069b06d1)]:\n  - @dnd-kit/abstract@0.0.3\n  - @dnd-kit/collision@0.0.3\n  - @dnd-kit/geometry@0.0.3\n  - @dnd-kit/state@0.0.3\n\n## 0.0.2\n\n### Patch Changes\n\n- [#1430](https://github.com/clauderic/dnd-kit/pull/1430) [`6c84308`](https://github.com/clauderic/dnd-kit/commit/6c84308b45c55ca1324a5c752b0ec117235da9e2) Thanks [@clauderic](https://github.com/clauderic)! - - `Sortable`: Fixed a bug with optimistic re-ordering.\n\n  - `Scroller`: Fixed a bug with auto-scrolling when target is position fixed\n\n- [#1430](https://github.com/clauderic/dnd-kit/pull/1430) [`d273f70`](https://github.com/clauderic/dnd-kit/commit/d273f700c3f580cb781bd004ed025bbceee20c4e) Thanks [@clauderic](https://github.com/clauderic)! - - `Feedback`: Fixed a bug with transitions being interrupted on drop when the draggable element has not been moved.\n\n- [#1430](https://github.com/clauderic/dnd-kit/pull/1430) [`34c6fdc`](https://github.com/clauderic/dnd-kit/commit/34c6fdc6fb20c092a9370e35f22bf55d8065130c) Thanks [@clauderic](https://github.com/clauderic)! - - `AutoScroller`: Improve auto-scroller to continue scrolling even when outside the bounds of the element currently being scrolled.\n\n- [#1430](https://github.com/clauderic/dnd-kit/pull/1430) [`2c3ad5e`](https://github.com/clauderic/dnd-kit/commit/2c3ad5eab3aabfd0aaa5a3a299dae1e307e8edaf) Thanks [@clauderic](https://github.com/clauderic)! - - `Feedback`: Only restore focus after drop if the `activatorEvent` is a keyboard event.\n\n- Updated dependencies [[`6c84308`](https://github.com/clauderic/dnd-kit/commit/6c84308b45c55ca1324a5c752b0ec117235da9e2)]:\n  - @dnd-kit/state@0.0.2\n  - @dnd-kit/abstract@0.0.2\n  - @dnd-kit/geometry@0.0.2\n  - @dnd-kit/collision@0.0.2\n"
  },
  {
    "path": "packages/dom/README.md",
    "content": "# @dnd-kit/dom\n\n[![Stable release](https://img.shields.io/npm/v/@dnd-kit/dom.svg)](https://npm.im/@dnd-kit/dom)\n\nThe framework-agnostic DOM implementation layer for **@dnd-kit**, built on top of `@dnd-kit/abstract`. This package provides the core drag and drop primitives that work directly with the DOM, and serves as the foundation for all framework adapters (`@dnd-kit/react`, `@dnd-kit/vue`, `@dnd-kit/svelte`, `@dnd-kit/solid`).\n\n## Installation\n\n```bash\nnpm install @dnd-kit/dom\n```\n\n## Overview\n\nMost consumers will use one of the framework-specific adapters rather than this package directly. However, `@dnd-kit/dom` can be used standalone for framework-agnostic or vanilla JavaScript projects.\n\n### Entry points\n\n| Entry point              | Description                                                              |\n| ------------------------ | ------------------------------------------------------------------------ |\n| `@dnd-kit/dom`           | Core API — `DragDropManager`, `Draggable`, `Droppable`, sensors, plugins |\n| `@dnd-kit/dom/sortable`  | Sortable primitives — `Sortable`, sorting utilities                      |\n| `@dnd-kit/dom/modifiers` | Built-in modifiers for constraining drag movement                        |\n| `@dnd-kit/dom/utilities` | DOM utility functions                                                    |\n\n### Key concepts\n\n- **DragDropManager** — Orchestrates drag and drop operations, manages sensors, plugins, and collision detection.\n- **Draggable** — Represents a draggable DOM element.\n- **Droppable** — Represents a droppable DOM element.\n- **Sensors** — Detect user input (pointer, keyboard) and translate it into drag operations.\n- **Plugins** — Extend core behavior (feedback, auto-scrolling, accessibility, etc.).\n- **Modifiers** — Transform drag coordinates to constrain or modify movement.\n\n## Documentation\n\nVisit [dndkit.com](https://dndkit.com) for full documentation, guides, and interactive examples.\n"
  },
  {
    "path": "packages/dom/package.json",
    "content": "{\n  \"name\": \"@dnd-kit/dom\",\n  \"version\": \"0.3.2\",\n  \"type\": \"module\",\n  \"main\": \"./index.cjs\",\n  \"module\": \"./index.js\",\n  \"types\": \"./index.d.ts\",\n  \"sideEffects\": false,\n  \"license\": \"MIT\",\n  \"files\": [\n    \"LICENSE\",\n    \"README.md\",\n    \"index.js\",\n    \"index.js.map\",\n    \"index.d.ts\",\n    \"index.d.cts\",\n    \"index.cjs\",\n    \"index.cjs.map\",\n    \"plugins/*\",\n    \"modifiers.js\",\n    \"modifiers.js.map\",\n    \"modifiers.d.ts\",\n    \"modifiers.d.cts\",\n    \"modifiers.cjs\",\n    \"sortable.js\",\n    \"sortable.js.map\",\n    \"sortable.d.ts\",\n    \"sortable.d.cts\",\n    \"sortable.cjs\",\n    \"sortable.cjs.map\",\n    \"utilities.js\",\n    \"utilities.js.map\",\n    \"utilities.d.ts\",\n    \"utilities.d.cts\",\n    \"utilities.cjs\",\n    \"utilities.cjs.map\"\n  ],\n  \"exports\": {\n    \".\": {\n      \"types\": \"./index.d.ts\",\n      \"import\": \"./index.js\",\n      \"require\": \"./index.cjs\"\n    },\n    \"./modifiers\": {\n      \"types\": \"./modifiers.d.ts\",\n      \"import\": \"./modifiers.js\",\n      \"require\": \"./modifiers.cjs\"\n    },\n    \"./plugins/*\": {\n      \"types\": \"./plugins/*.d.ts\",\n      \"import\": \"./plugins/*.js\",\n      \"require\": \"./plugins/*.cjs\"\n    },\n    \"./sortable\": {\n      \"types\": \"./sortable.d.ts\",\n      \"import\": \"./sortable.js\",\n      \"require\": \"./sortable.cjs\"\n    },\n    \"./utilities\": {\n      \"types\": \"./utilities.d.ts\",\n      \"import\": \"./utilities.js\",\n      \"require\": \"./utilities.cjs\"\n    }\n  },\n  \"scripts\": {\n    \"build\": \"bun build:utilities && bun build:core && bun build:sortable && bun build:modifiers && bun build:plugins\",\n    \"build:core\": \"tsup src/core/index.ts\",\n    \"build:modifiers\": \"tsup --entry.modifiers src/modifiers/index.ts\",\n    \"build:plugins\": \"tsup --entry.debug src/plugins/debug/index.ts --outDir ./plugins\",\n    \"build:sortable\": \"tsup --entry.sortable src/sortable/index.ts\",\n    \"build:utilities\": \"tsup --entry.utilities src/utilities/index.ts\",\n    \"dev\": \"bun build:utilities --watch & bun build:core --watch & bun build:sortable --watch & bun build:modifiers --watch & bun build:plugins --watch\",\n    \"test\": \"bun test\",\n    \"lint\": \"TIMING=1 eslint src/**/*.ts* --fix\",\n    \"clean\": \"rm -rf .turbo && rm -rf node_modules && rm -rf dist\"\n  },\n  \"dependencies\": {\n    \"@dnd-kit/abstract\": \"^0.3.2\",\n    \"@dnd-kit/collision\": \"^0.3.2\",\n    \"@dnd-kit/geometry\": \"^0.3.2\",\n    \"@dnd-kit/state\": \"^0.3.2\",\n    \"tslib\": \"^2.6.2\"\n  },\n  \"devDependencies\": {\n    \"@dnd-kit/eslint-config\": \"*\",\n    \"bun-types\": \"^1.2.15\",\n    \"eslint\": \"^8.38.0\",\n    \"tsup\": \"8.3.0\",\n    \"typescript\": \"^5.5.2\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/clauderic/dnd-kit\"\n  }\n}\n"
  },
  {
    "path": "packages/dom/src/core/entities/draggable/draggable.ts",
    "content": "import {\n  Draggable as AbstractDraggable,\n  Sensor,\n  descriptor,\n} from '@dnd-kit/abstract';\nimport type {Data, DraggableInput} from '@dnd-kit/abstract';\nimport {reactive} from '@dnd-kit/state';\n\nimport type {DragDropManager} from '../../manager/index.ts';\nimport type {Sensors} from '../../sensors/types.ts';\n\nexport interface Input<T extends Data = Data> extends DraggableInput<T> {\n  handle?: Element;\n  element?: Element;\n  sensors?: Sensors;\n}\n\nexport class Draggable<T extends Data = Data> extends AbstractDraggable<\n  T,\n  DragDropManager\n> {\n  constructor(\n    {\n      element,\n      effects = () => [],\n      handle,\n      ...input\n    }: Input<T>,\n    manager: DragDropManager | undefined\n  ) {\n    super(\n      {\n        effects: () => [\n          ...effects(),\n          () => {\n            const {manager} = this;\n\n            if (!manager) return;\n\n            const sensors = this.sensors?.map(descriptor) ?? [\n              ...manager.sensors,\n            ];\n            const unbindFunctions = sensors.map((entry) => {\n              const sensorInstance =\n                entry instanceof Sensor\n                  ? entry\n                  : manager.registry.register(entry.plugin);\n              const options =\n                entry instanceof Sensor ? undefined : entry.options;\n\n              const unbind = sensorInstance.bind(this, options);\n              return unbind;\n            });\n\n            return function cleanup() {\n              unbindFunctions.forEach((unbind) => unbind());\n            };\n          },\n        ],\n        ...input,\n      },\n      manager\n    );\n\n    this.element = element;\n    this.handle = handle;\n  }\n\n  @reactive\n  public accessor handle: Element | undefined;\n\n  @reactive\n  public accessor element: Element | undefined;\n}\n"
  },
  {
    "path": "packages/dom/src/core/entities/draggable/index.ts",
    "content": "export {Draggable} from './draggable.ts';\nexport type {Input as DraggableInput} from './draggable.ts';\n"
  },
  {
    "path": "packages/dom/src/core/entities/droppable/droppable.ts",
    "content": "import {Droppable as AbstractDroppable} from '@dnd-kit/abstract';\nimport type {\n  Data,\n  DroppableInput as AbstractDroppableInput,\n} from '@dnd-kit/abstract';\nimport {defaultCollisionDetection} from '@dnd-kit/collision';\nimport type {CollisionDetector} from '@dnd-kit/collision';\nimport {reactive, signal, untracked} from '@dnd-kit/state';\nimport type {BoundingRectangle, Shape} from '@dnd-kit/geometry';\nimport {DOMRectangle, PositionObserver} from '@dnd-kit/dom/utilities';\n\nimport type {DragDropManager} from '../../manager/manager.ts';\n\ntype OptionalInput = 'collisionDetector';\n\nexport interface Input<T extends Data = Data>\n  extends Omit<AbstractDroppableInput<T>, OptionalInput> {\n  collisionDetector?: CollisionDetector;\n  element?: Element;\n}\n\nexport class Droppable<T extends Data = Data> extends AbstractDroppable<\n  T,\n  DragDropManager\n> {\n  constructor(\n    {element, effects = () => [], ...input}: Input<T>,\n    manager: DragDropManager | undefined\n  ) {\n    const {collisionDetector = defaultCollisionDetection} = input;\n    const updateShape = (boundingClientRect?: BoundingRectangle | null) => {\n      const {manager, element} = this;\n\n      if (!element || boundingClientRect === null) {\n        this.shape = undefined;\n        return undefined;\n      }\n\n      if (!manager) return;\n\n      const updatedShape = new DOMRectangle(element);\n\n      const shape = untracked(() => this.shape);\n      if (updatedShape && shape?.equals(updatedShape)) {\n        return shape;\n      }\n\n      this.shape = updatedShape;\n\n      return updatedShape;\n    };\n\n    const observePosition = signal(false);\n\n    super(\n      {\n        ...input,\n        collisionDetector,\n        effects: () => [\n          ...effects(),\n          () => {\n            const {element, manager} = this;\n            if (!manager) return;\n\n            const {dragOperation} = manager;\n            const {source} = dragOperation;\n\n            observePosition.value = Boolean(\n              source &&\n                dragOperation.status.initialized &&\n                element &&\n                !this.disabled &&\n                this.accepts(source)\n            );\n          },\n          () => {\n            const {element} = this;\n\n            if (observePosition.value && element) {\n              const positionObserver = new PositionObserver(\n                element,\n                updateShape\n              );\n\n              return () => {\n                positionObserver.disconnect();\n                this.shape = undefined;\n              };\n            }\n          },\n          () => {\n            if (this.manager?.dragOperation.status.initialized) {\n              return () => {\n                this.shape = undefined;\n              };\n            }\n          },\n        ],\n      },\n      manager\n    );\n\n    this.element = element;\n    this.refreshShape = () => updateShape();\n  }\n\n  @reactive\n  accessor #element: Element | undefined;\n\n  @reactive\n  public accessor proxy: Element | undefined;\n\n  set element(element: Element | undefined) {\n    this.#element = element;\n  }\n\n  get element() {\n    return this.proxy ?? this.#element;\n  }\n\n  public refreshShape: () => Shape | undefined;\n}\n"
  },
  {
    "path": "packages/dom/src/core/entities/droppable/index.ts",
    "content": "export {Droppable} from './droppable.ts';\nexport type {Input as DroppableInput} from './droppable.ts';\n"
  },
  {
    "path": "packages/dom/src/core/entities/index.ts",
    "content": "export * from './draggable/index.ts';\nexport * from './droppable/index.ts';\n"
  },
  {
    "path": "packages/dom/src/core/index.ts",
    "content": "export {DragDropManager, defaultPreset} from './manager/index.ts';\nexport {resolveCustomizable} from '@dnd-kit/abstract';\nexport type {DragDropManagerInput, Customizable} from './manager/index.ts';\n\nexport type {\n  CollisionEvent,\n  BeforeDragStartEvent,\n  DragStartEvent,\n  DragMoveEvent,\n  DragOverEvent,\n  DragEndEvent,\n} from './manager/events.ts';\n\nexport {Draggable, Droppable} from './entities/index.ts';\nexport type {\n  DraggableInput,\n  DroppableInput,\n} from './entities/index.ts';\n\nexport type {Sensors} from './sensors/types.ts';\nexport {\n  PointerSensor,\n  type PointerSensorOptions,\n} from './sensors/pointer/PointerSensor.ts';\nexport {PointerActivationConstraints} from './sensors/pointer/PointerActivationConstraints.ts';\nexport {\n  KeyboardSensor,\n  type KeyboardSensorOptions,\n} from './sensors/keyboard/KeyboardSensor.ts';\n\nexport {\n  Accessibility,\n  AutoScroller,\n  Cursor,\n  Feedback,\n  PreventSelection,\n  Scroller,\n  ScrollListener,\n  StyleInjector,\n} from './plugins/index.ts';\nexport type {\n  FeedbackType,\n  FeedbackOptions,\n  Transition,\n  DropAnimation,\n  DropAnimationOptions,\n  DropAnimationFunction,\n} from './plugins/index.ts';\n"
  },
  {
    "path": "packages/dom/src/core/manager/events.ts",
    "content": "import type {DragDropEventMap} from '@dnd-kit/abstract';\n\nimport type {Draggable} from '../entities/draggable/draggable.ts';\nimport type {Droppable} from '../entities/droppable/droppable.ts';\nimport type {DragDropManager} from './manager.ts';\n\ntype Events = DragDropEventMap<Draggable, Droppable, DragDropManager>;\n\nexport type CollisionEvent = Events['collision'];\nexport type BeforeDragStartEvent = Events['beforedragstart'];\nexport type DragStartEvent = Events['dragstart'];\nexport type DragMoveEvent = Events['dragmove'];\nexport type DragOverEvent = Events['dragover'];\nexport type DragEndEvent = Events['dragend'];\n"
  },
  {
    "path": "packages/dom/src/core/manager/index.ts",
    "content": "export {DragDropManager, defaultPreset} from './manager.ts';\nexport type {Input as DragDropManagerInput} from './manager.ts';\nexport type {Customizable} from '@dnd-kit/abstract';"
  },
  {
    "path": "packages/dom/src/core/manager/manager.ts",
    "content": "import {\n  DragDropManager as AbstractDragDropManager,\n  DragDropManagerInput,\n  resolveCustomizable,\n  type Data,\n  type Modifiers,\n  type Plugins,\n  type Sensors,\n} from '@dnd-kit/abstract';\n\nimport type {Draggable, Droppable} from '../entities/index.ts';\nimport {\n  Accessibility,\n  AutoScroller,\n  Cursor,\n  Feedback,\n  Scroller,\n  ScrollListener,\n  PreventSelection,\n  StyleInjector,\n} from '../plugins/index.ts';\nimport {KeyboardSensor} from '../sensors/keyboard/KeyboardSensor.ts';\nimport {PointerSensor} from '../sensors/pointer/PointerSensor.ts';\n\nexport interface Input extends DragDropManagerInput<DragDropManager> {}\n\nexport const defaultPreset: {\n  modifiers: Modifiers<DragDropManager>;\n  plugins: Plugins<DragDropManager>;\n  sensors: Sensors<DragDropManager>;\n} = {\n  modifiers: [],\n  plugins: [Accessibility, AutoScroller, Cursor, Feedback, PreventSelection],\n  sensors: [PointerSensor, KeyboardSensor],\n};\n\nexport class DragDropManager<\n  T extends Data = Data,\n  U extends Draggable<T> = Draggable<T>,\n  V extends Droppable<T> = Droppable<T>,\n> extends AbstractDragDropManager<U, V> {\n  constructor(input: Input = {}) {\n    const plugins = resolveCustomizable(input.plugins, defaultPreset.plugins);\n    const sensors = resolveCustomizable(input.sensors, defaultPreset.sensors);\n    const modifiers = resolveCustomizable(\n      input.modifiers,\n      defaultPreset.modifiers\n    );\n\n    super({\n      ...input,\n      plugins: [ScrollListener, Scroller, StyleInjector, ...plugins],\n      sensors,\n      modifiers,\n    });\n  }\n}\n"
  },
  {
    "path": "packages/dom/src/core/plugins/accessibility/Accessibility.ts",
    "content": "import {Plugin} from '@dnd-kit/abstract';\nimport {isSafari, generateUniqueId, scheduler} from '@dnd-kit/dom/utilities';\n\nimport type {DragDropManager} from '../../manager/index.ts';\nimport {\n  defaultAnnouncements,\n  defaultAttributes,\n  defaultAnnouncementIdPrefix,\n  defaultDescriptionIdPrefix,\n  defaultScreenReaderInstructions,\n} from './defaults.ts';\nimport type {Announcements, ScreenReaderInstructions} from './types.ts';\nimport {isFocusable} from './utilities.ts';\nimport {createHiddenText} from './HiddenText.ts';\nimport {createLiveRegion} from './LiveRegion.ts';\n\ninterface Options {\n  /**\n   * Optional id that should be used for the accessibility plugin's screen reader instructions and announcements.\n   */\n  id?: string;\n  /**\n   * Optional id prefix to use for the accessibility plugin's screen reader instructions and announcements.\n   */\n  idPrefix?: {\n    description?: string;\n    announcement?: string;\n  };\n  /**\n   * The announcements to use for the accessibility plugin.\n   */\n  announcements?: Announcements;\n  /**\n   * The screen reader instructions to use for the accessibility plugin.\n   */\n  screenReaderInstructions?: ScreenReaderInstructions;\n  /**\n   * The number of milliseconds to debounce the announcement updates.\n   *\n   * @remarks\n   * Only the `dragover` and `dragmove` announcements are debounced.\n   *\n   * @default 500\n   */\n  debounce?: number;\n}\n\nconst debouncedEvents = ['dragover', 'dragmove'];\n\nexport class Accessibility extends Plugin<DragDropManager> {\n  constructor(manager: DragDropManager, options?: Options) {\n    super(manager);\n\n    const {\n      id,\n      idPrefix: {\n        description: descriptionPrefix = defaultDescriptionIdPrefix,\n        announcement: announcementPrefix = defaultAnnouncementIdPrefix,\n      } = {},\n      announcements = defaultAnnouncements,\n      screenReaderInstructions = defaultScreenReaderInstructions,\n      debounce: debounceMs = 500,\n    } = options ?? {};\n\n    const descriptionId = id\n      ? `${descriptionPrefix}-${id}`\n      : generateUniqueId(descriptionPrefix);\n    const announcementId = id\n      ? `${announcementPrefix}-${id}`\n      : generateUniqueId(announcementPrefix);\n\n    let hiddenTextElement: HTMLElement | undefined;\n    let liveRegionElement: HTMLElement | undefined;\n    let liveRegionTextNode: Node | undefined;\n    let latestAnnouncement: string | undefined;\n\n    const updateAnnouncement = (value = latestAnnouncement) => {\n      if (!liveRegionTextNode || !value) return;\n      if (liveRegionTextNode?.nodeValue !== value) {\n        liveRegionTextNode.nodeValue = value;\n      }\n    };\n    const scheduleUpdateAnnouncement = () =>\n      scheduler.schedule(updateAnnouncement);\n    const debouncedUpdateAnnouncement = debounce(\n      scheduleUpdateAnnouncement,\n      debounceMs\n    );\n\n    const eventListeners = Object.entries(announcements).map(\n      ([eventName, getAnnouncement]) => {\n        return this.manager.monitor.addEventListener(\n          eventName as keyof Announcements,\n          (event: any, manager: DragDropManager) => {\n            const element = liveRegionTextNode;\n            if (!element) return;\n\n            const announcement = getAnnouncement?.(event, manager);\n\n            if (announcement && element.nodeValue !== announcement) {\n              latestAnnouncement = announcement;\n\n              if (debouncedEvents.includes(eventName)) {\n                debouncedUpdateAnnouncement();\n              } else {\n                scheduleUpdateAnnouncement();\n                debouncedUpdateAnnouncement.cancel();\n              }\n            }\n          }\n        );\n      }\n    );\n\n    const initialize = () => {\n      let elements = [];\n\n      if (!hiddenTextElement?.isConnected) {\n        hiddenTextElement = createHiddenText(\n          descriptionId,\n          screenReaderInstructions.draggable\n        );\n        elements.push(hiddenTextElement);\n      }\n\n      if (!liveRegionElement?.isConnected) {\n        liveRegionElement = createLiveRegion(announcementId);\n        liveRegionTextNode = document.createTextNode('');\n        liveRegionElement.appendChild(liveRegionTextNode);\n        elements.push(liveRegionElement);\n      }\n\n      if (elements.length > 0) {\n        document.body.append(...elements);\n      }\n    };\n\n    const mutations = new Set<() => void>();\n\n    function executeMutations() {\n      for (const operation of mutations) {\n        operation();\n      }\n    }\n\n    this.registerEffect(() => {\n      mutations.clear();\n\n      // Re-run effect when any of the draggable elements change\n      for (const draggable of this.manager.registry.draggables.value) {\n        const activator = draggable.handle ?? draggable.element;\n\n        if (activator) {\n          if (!hiddenTextElement || !liveRegionElement) {\n            mutations.add(initialize);\n          }\n\n          if (\n            (!isFocusable(activator) || isSafari()) &&\n            !activator.hasAttribute('tabindex')\n          ) {\n            mutations.add(() => activator.setAttribute('tabindex', '0'));\n          }\n\n          if (\n            !activator.hasAttribute('role') &&\n            !(activator.tagName.toLowerCase() === 'button')\n          ) {\n            mutations.add(() =>\n              activator.setAttribute('role', defaultAttributes.role)\n            );\n          }\n\n          if (!activator.hasAttribute('aria-roledescription')) {\n            mutations.add(() =>\n              activator.setAttribute(\n                'aria-roledescription',\n                defaultAttributes.roleDescription\n              )\n            );\n          }\n\n          if (!activator.hasAttribute('aria-describedby')) {\n            mutations.add(() =>\n              activator.setAttribute('aria-describedby', descriptionId)\n            );\n          }\n\n          for (const key of ['aria-pressed', 'aria-grabbed']) {\n            const value = String(draggable.isDragging);\n\n            if (activator.getAttribute(key) !== value) {\n              mutations.add(() => activator.setAttribute(key, value));\n            }\n          }\n\n          const disabled = String(draggable.disabled);\n\n          if (activator.getAttribute('aria-disabled') !== disabled) {\n            mutations.add(() =>\n              activator.setAttribute('aria-disabled', disabled)\n            );\n          }\n        }\n      }\n\n      if (mutations.size > 0) {\n        scheduler.schedule(executeMutations);\n      }\n    });\n\n    this.destroy = () => {\n      super.destroy();\n      hiddenTextElement?.remove();\n      liveRegionElement?.remove();\n      eventListeners.forEach((unsubscribe) => unsubscribe());\n    };\n  }\n}\n\nfunction debounce(fn: () => void, wait: number) {\n  let timeout: NodeJS.Timeout | undefined;\n  const debounced = () => {\n    clearTimeout(timeout);\n    timeout = setTimeout(fn, wait);\n  };\n\n  debounced.cancel = () => clearTimeout(timeout);\n\n  return debounced;\n}\n"
  },
  {
    "path": "packages/dom/src/core/plugins/accessibility/HiddenText.ts",
    "content": "export function createHiddenText(id: string, value: string) {\n  const element = document.createElement('div');\n\n  element.id = id;\n  element.style.setProperty('display', 'none');\n  element.textContent = value;\n\n  return element;\n}\n"
  },
  {
    "path": "packages/dom/src/core/plugins/accessibility/LiveRegion.ts",
    "content": "export function createLiveRegion(id: string) {\n  const element = document.createElement('div');\n\n  element.id = id;\n  element.setAttribute('role', 'status');\n  element.setAttribute('aria-live', 'polite');\n  element.setAttribute('aria-atomic', 'true');\n  element.style.setProperty('position', 'fixed');\n  element.style.setProperty('width', '1px');\n  element.style.setProperty('height', '1px');\n  element.style.setProperty('margin', '-1px');\n  element.style.setProperty('border', '0');\n  element.style.setProperty('padding', '0');\n  element.style.setProperty('overflow', 'hidden');\n  element.style.setProperty('clip', 'rect(0 0 0 0)');\n  element.style.setProperty('clip-path', 'inset(100%)');\n  element.style.setProperty('white-space', 'nowrap');\n\n  return element;\n}\n"
  },
  {
    "path": "packages/dom/src/core/plugins/accessibility/defaults.ts",
    "content": "import type {Announcements, ScreenReaderInstructions} from './types.ts';\n\nexport const defaultAttributes = {\n  role: 'button',\n  roleDescription: 'draggable',\n  tabIndex: 0,\n};\n\nexport const defaultDescriptionIdPrefix = `dnd-kit-description`;\nexport const defaultAnnouncementIdPrefix = `dnd-kit-announcement`;\n\nexport const defaultScreenReaderInstructions: ScreenReaderInstructions = {\n  draggable: `To pick up a draggable item, press the space bar. While dragging, use the arrow keys to move the item in a given direction. Press space again to drop the item in its new position, or press escape to cancel.`,\n};\n\nexport const defaultAnnouncements: Announcements = {\n  dragstart({operation: {source}}) {\n    if (!source) return;\n\n    return `Picked up draggable item ${source.id}.`;\n  },\n  dragover({operation: {source, target}}) {\n    if (!source || source.id === target?.id) return;\n\n    if (target) {\n      return `Draggable item ${source.id} was moved over droppable target ${target.id}.`;\n    }\n\n    return `Draggable item ${source.id} is no longer over a droppable target.`;\n  },\n  dragend({operation: {source, target}, canceled}) {\n    if (!source) return;\n\n    if (canceled) {\n      return `Dragging was cancelled. Draggable item ${source.id} was dropped.`;\n    }\n\n    if (target) {\n      return `Draggable item ${source.id} was dropped over droppable target ${target.id}`;\n    }\n\n    return `Draggable item ${source.id} was dropped.`;\n  },\n};\n"
  },
  {
    "path": "packages/dom/src/core/plugins/accessibility/index.ts",
    "content": "export {Accessibility} from './Accessibility.ts';\n"
  },
  {
    "path": "packages/dom/src/core/plugins/accessibility/types.ts",
    "content": "import type {DragDropEventMap} from '@dnd-kit/abstract';\nimport type {DragDropManager} from '../../manager/index.ts';\nimport type {Draggable, Droppable} from '../../entities/index.ts';\n\nexport type GetAnnouncementForEvent<\n  Key extends keyof DragDropEventMap<any, any, any>,\n> = (\n  event: DragDropEventMap<Draggable, Droppable, DragDropManager>[Key],\n  manager: DragDropManager\n) => string | undefined;\n\nexport interface Announcements {\n  dragstart: GetAnnouncementForEvent<'dragstart'>;\n  dragmove?: GetAnnouncementForEvent<'dragmove'>;\n  dragover?: GetAnnouncementForEvent<'dragover'>;\n  dragend: GetAnnouncementForEvent<'dragend'>;\n}\n\nexport interface ScreenReaderInstructions {\n  draggable: string;\n}\n"
  },
  {
    "path": "packages/dom/src/core/plugins/accessibility/utilities.ts",
    "content": "export function isFocusable(element: Element) {\n  const tagName = element.tagName.toLowerCase();\n\n  return ['input', 'select', 'textarea', 'a', 'button'].includes(tagName);\n}\n"
  },
  {
    "path": "packages/dom/src/core/plugins/cursor/Cursor.ts",
    "content": "import {Plugin} from '@dnd-kit/abstract';\n\nimport {DragDropManager} from '../../manager/index.ts';\nimport {StyleInjector} from '../stylesheet/StyleInjector.ts';\n\ninterface CursorPluginOptions {\n  /**\n   * The style of the cursor to be applied to the document body.\n   * @default 'grabbing'\n   */\n  cursor?: string;\n}\n\nexport class Cursor extends Plugin<DragDropManager> {\n  constructor(\n    public manager: DragDropManager,\n    options?: CursorPluginOptions\n  ) {\n    super(manager, options);\n\n    const {cursor = 'grabbing'} = options ?? {};\n    const styleInjector = manager.registry.plugins.get(\n      StyleInjector as any\n    ) as StyleInjector | undefined;\n\n    const unregisterStyles = styleInjector?.register(\n      `* { cursor: ${cursor} !important; }`\n    );\n\n    if (unregisterStyles) {\n      const originalDestroy = this.destroy.bind(this);\n      this.destroy = () => {\n        unregisterStyles();\n        originalDestroy();\n      };\n    }\n  }\n}\n"
  },
  {
    "path": "packages/dom/src/core/plugins/cursor/index.ts",
    "content": "export {Cursor} from './Cursor.ts';\n"
  },
  {
    "path": "packages/dom/src/core/plugins/feedback/Feedback.ts",
    "content": "import {effects, reactive, untracked} from '@dnd-kit/state';\nimport {configurator, Plugin} from '@dnd-kit/abstract';\nimport {\n  DOMRectangle,\n  getComputedStyles,\n  getFixedPositionOffset,\n  getFrameTransform,\n  getRoot,\n  getWindow,\n  isHTMLElement,\n  prefersReducedMotion,\n  isKeyboardEvent,\n  parseTransform,\n  parseTranslate,\n  showPopover,\n  Styles,\n  supportsPopover,\n} from '@dnd-kit/dom/utilities';\nimport {Coordinates, Point, Rectangle} from '@dnd-kit/geometry';\n\nimport type {DragDropManager} from '../../manager/index.ts';\nimport type {Draggable} from '../../entities/index.ts';\nimport {StyleInjector} from '../stylesheet/StyleInjector.ts';\n\nimport {ATTRIBUTE, CSS_PREFIX, CSS_RULES} from './constants.ts';\nimport {\n  createPlaceholder,\n  isSameFrame,\n  isTableRow,\n  preventPopoverClose,\n} from './utilities.ts';\nimport {\n  createElementMutationObserver,\n  createDocumentMutationObserver,\n  createResizeObserver,\n} from './observers.ts';\nimport {runDropAnimation, type DropAnimation} from './dropAnimation.ts';\n\nexport type FeedbackType = 'default' | 'move' | 'clone' | 'none';\n\nexport interface KeyboardTransition {\n  duration?: number;\n  easing?: string;\n}\n\nexport interface FeedbackOptions {\n  feedback?: FeedbackType;\n  rootElement?: Element | ((source: Draggable) => Element);\n  dropAnimation?: DropAnimation | null;\n  keyboardTransition?: KeyboardTransition | null;\n}\n\ninterface State {\n  current: {\n    translate?: Coordinates;\n  };\n  initial: {\n    dimensions?: {width: number; height: number};\n    coordinates?: Coordinates;\n    frameTransform?: {x: number; y: number; scaleX: number; scaleY: number};\n    translate?: Coordinates;\n    transformOrigin?: Coordinates;\n  };\n}\n\nexport class Feedback extends Plugin<DragDropManager, FeedbackOptions> {\n  @reactive\n  public accessor overlay: Element | undefined;\n\n  /**\n   * Override the drop animation configuration for this Feedback instance.\n   *\n   * - `undefined` – use the default from plugin options\n   * - `null` – disable the drop animation entirely\n   * - `DropAnimationOptions` – customize duration / easing\n   * - `DropAnimationFunction` – provide a fully custom animation\n   */\n  public dropAnimation: DropAnimation | null | undefined;\n\n  private state: State = {\n    initial: {},\n    current: {},\n  };\n\n  constructor(manager: DragDropManager, options?: FeedbackOptions) {\n    super(manager, options);\n\n    const styleInjector = manager.registry.plugins.get(\n      StyleInjector as any\n    ) as StyleInjector | undefined;\n\n    const unregisterStyles = styleInjector?.register(CSS_RULES);\n\n    if (unregisterStyles) {\n      const originalDestroy = this.destroy.bind(this);\n      this.destroy = () => {\n        unregisterStyles();\n        originalDestroy();\n      };\n    }\n\n    this.registerEffect(this.#trackOverlayRoot.bind(this, styleInjector));\n    this.registerEffect(this.#render);\n  }\n\n  #trackOverlayRoot(styleInjector: StyleInjector | undefined) {\n    const {overlay} = this;\n\n    if (!overlay || !styleInjector) return;\n\n    const root = getRoot(overlay);\n\n    if (!root) return;\n\n    return styleInjector.addRoot(root);\n  }\n\n  #render() {\n    const {state, manager, options} = this;\n    const {dragOperation} = manager;\n    const {position, source, status} = dragOperation;\n\n    if (status.idle) {\n      state.current = {};\n      state.initial = {};\n      return;\n    }\n\n    if (!source) return;\n\n    const {element} = source;\n    const entityOptions = source.pluginConfig(Feedback);\n    const feedback =\n      entityOptions?.feedback ?? options?.feedback ?? 'default';\n\n    if (\n      !element ||\n      feedback === 'none' ||\n      !status.initialized ||\n      status.initializing\n    ) {\n      return;\n    }\n\n    /* ---- Geometry computation ---- */\n\n    const {initial} = state;\n    const feedbackElement = this.overlay ?? element;\n    const frameTransform = getFrameTransform(feedbackElement);\n    const elementFrameTransform = getFrameTransform(element);\n    const crossFrame = !isSameFrame(element, feedbackElement);\n    const shape = new DOMRectangle(element, {\n      frameTransform: crossFrame ? elementFrameTransform : null,\n      ignoreTransforms: !crossFrame,\n    });\n    const scaleDelta = {\n      x: elementFrameTransform.scaleX / frameTransform.scaleX,\n      y: elementFrameTransform.scaleY / frameTransform.scaleY,\n    };\n\n    let {width, height, top, left} = shape;\n\n    if (crossFrame) {\n      width = width / scaleDelta.x;\n      height = height / scaleDelta.y;\n    }\n\n    const styles = new Styles(feedbackElement);\n    const elementStyles = getComputedStyles(element);\n    const {\n      transition,\n      translate,\n      boxSizing,\n      paddingBlockStart,\n      paddingBlockEnd,\n      paddingInlineStart,\n      paddingInlineEnd,\n      borderInlineStartWidth,\n      borderInlineEndWidth,\n      borderBlockStartWidth,\n      borderBlockEndWidth,\n    } = elementStyles;\n    // Filter out transform-related transitions that would interfere with\n    // Feedback-managed properties (--dnd-transform, --dnd-translate, --dnd-scale)\n    const feedbackTransition = transition\n      .split(',')\n      .filter((t) => !/^\\s*(transform|translate|scale)\\b/.test(t))\n      .join(',');\n    const parsedTransform = parseTransform(elementStyles);\n    // Eagerly capture the raw transform CSS value before the\n    // data-dnd-dragging attribute is set, since elementStyles is a live\n    // CSSStyleDeclaration and the CSS rule for [data-dnd-dragging] overrides\n    // transform via !important, which would cause the live object to return\n    // the overridden value instead of the original.\n    const initialTransformStyle = elementStyles.transform;\n    const clone = feedback === 'clone';\n    const contentBox = boxSizing === 'content-box';\n    const widthOffset = contentBox\n      ? parseInt(paddingInlineStart) +\n        parseInt(paddingInlineEnd) +\n        parseInt(borderInlineStartWidth) +\n        parseInt(borderInlineEndWidth)\n      : 0;\n    const heightOffset = contentBox\n      ? parseInt(paddingBlockStart) +\n        parseInt(paddingBlockEnd) +\n        parseInt(borderBlockStartWidth) +\n        parseInt(borderBlockEndWidth)\n      : 0;\n\n    const placeholder =\n      feedback !== 'move' && !this.overlay\n        ? createPlaceholder(source, clone ? 'clone' : 'hidden')\n        : null;\n    const isKeyboardOperation = untracked(() =>\n      isKeyboardEvent(manager.dragOperation.activatorEvent)\n    );\n\n    if (!initial.translate) {\n      if (this.overlay && parsedTransform) {\n        // When using an overlay, capture the full translation from both\n        // the CSS `translate` and `transform` properties, since the overlay\n        // element does not inherit the source element's `transform` property.\n        // This is needed for libraries like react-window v2 that use CSS\n        // `transform: translateY()` for positioning.\n        initial.translate = {x: parsedTransform.x, y: parsedTransform.y};\n      } else if (translate !== 'none') {\n        const parsedTranslate = parseTranslate(translate);\n\n        if (parsedTranslate) {\n          initial.translate = parsedTranslate;\n        }\n      }\n    }\n\n    if (!initial.transformOrigin) {\n      const current = untracked(() => position.current);\n\n      // Use the visual position (including transforms) since the cursor\n      // position is in screen coordinates. The shape's top/left have transforms\n      // stripped (ignoreTransforms), so we add them back for this calculation.\n      const visualLeft = left + (parsedTransform?.x ?? 0);\n      const visualTop = top + (parsedTransform?.y ?? 0);\n\n      initial.transformOrigin = {\n        x:\n          (current.x - visualLeft * frameTransform.scaleX - frameTransform.x) /\n          (width * frameTransform.scaleX),\n        y:\n          (current.y - visualTop * frameTransform.scaleY - frameTransform.y) /\n          (height * frameTransform.scaleY),\n      };\n    }\n\n    const {transformOrigin} = initial;\n    const relativeTop = top * frameTransform.scaleY + frameTransform.y;\n    const relativeLeft = left * frameTransform.scaleX + frameTransform.x;\n\n    if (!initial.coordinates) {\n      initial.coordinates = {\n        x: relativeLeft,\n        y: relativeTop,\n      };\n\n      // Compensate for transformOrigin when scaling\n      if (scaleDelta.x !== 1 || scaleDelta.y !== 1) {\n        const {scaleX, scaleY} = elementFrameTransform;\n        const {x: tX, y: tY} = transformOrigin;\n\n        initial.coordinates.x += (width * scaleX - width) * tX;\n        initial.coordinates.y += (height * scaleY - height) * tY;\n      }\n    }\n\n    if (!initial.dimensions) {\n      initial.dimensions = {width, height};\n    }\n\n    if (!initial.frameTransform) {\n      initial.frameTransform = frameTransform;\n    }\n\n    const coordinatesDelta = {\n      x: initial.coordinates.x - relativeLeft,\n      y: initial.coordinates.y - relativeTop,\n    };\n\n    const sizeDelta = {\n      width:\n        (initial.dimensions.width * initial.frameTransform.scaleX -\n          width * frameTransform.scaleX) *\n        transformOrigin.x,\n      height:\n        (initial.dimensions.height * initial.frameTransform.scaleY -\n          height * frameTransform.scaleY) *\n        transformOrigin.y,\n    };\n\n    const delta = {\n      x: coordinatesDelta.x / frameTransform.scaleX + sizeDelta.width,\n      y: coordinatesDelta.y / frameTransform.scaleY + sizeDelta.height,\n    };\n\n    const projected = {\n      left: left + delta.x,\n      top: top + delta.y,\n    };\n\n    /* ---- Apply initial feedback styles ---- */\n\n    feedbackElement.setAttribute(ATTRIBUTE, 'true');\n\n    const transform = untracked(() => dragOperation.transform);\n    const initialTranslate = initial.translate ?? {x: 0, y: 0};\n    const tX = transform.x * frameTransform.scaleX + initialTranslate.x;\n    const tY = transform.y * frameTransform.scaleY + initialTranslate.y;\n\n    const fixedOffset = getFixedPositionOffset();\n\n    styles.set(\n      {\n        width: width - widthOffset,\n        height: height - heightOffset,\n        top: projected.top + fixedOffset.y,\n        left: projected.left + fixedOffset.x,\n        translate: `${tX}px ${tY}px 0`,\n        transform: this.overlay ? 'none' : initialTransformStyle,\n        transition: feedbackTransition\n          ? `${feedbackTransition}, translate 0ms linear`\n          : 'translate 0ms linear',\n        scale: crossFrame ? `${scaleDelta.x} ${scaleDelta.y}` : '',\n        'transform-origin': `${transformOrigin.x * 100}% ${transformOrigin.y * 100}%`,\n      },\n      CSS_PREFIX\n    );\n\n    /* ---- Placeholder setup ---- */\n\n    if (placeholder) {\n      element.insertAdjacentElement('afterend', placeholder);\n\n      if (options?.rootElement) {\n        const root =\n          typeof options.rootElement === 'function'\n            ? options.rootElement(source)\n            : options.rootElement;\n\n        root.appendChild(element);\n      }\n    }\n\n    /* ---- Popover promotion ---- */\n\n    if (supportsPopover(feedbackElement)) {\n      if (!feedbackElement.hasAttribute('popover')) {\n        feedbackElement.setAttribute('popover', 'manual');\n      }\n      showPopover(feedbackElement);\n      feedbackElement.addEventListener('beforetoggle', preventPopoverClose);\n    }\n\n    /* ---- Observers ---- */\n\n    let elementMutationObserver: MutationObserver | undefined;\n    let documentMutationObserver: MutationObserver | undefined;\n    let savedCellWidths: string[] | undefined;\n\n    const resizeObserver = createResizeObserver({\n      placeholder: placeholder!,\n      element,\n      feedbackElement,\n      frameTransform,\n      transformOrigin,\n      width,\n      height,\n      top,\n      left,\n      widthOffset,\n      heightOffset,\n      delta,\n      styles,\n      dragOperation,\n      getTranslate: () => state.current.translate,\n      getElementMutationObserver: () => elementMutationObserver,\n      getSavedCellWidths: () => savedCellWidths,\n      setSavedCellWidths: (widths) => {\n        savedCellWidths = widths;\n      },\n    });\n\n    const initialShape = new DOMRectangle(feedbackElement);\n    untracked(() => (dragOperation.shape = initialShape));\n\n    const feedbackWindow = getWindow(feedbackElement);\n    const handleWindowResize = (event: Event) => {\n      this.manager.actions.stop({event});\n    };\n\n    const reducedMotion = prefersReducedMotion(feedbackWindow);\n\n    if (isKeyboardOperation) {\n      feedbackWindow.addEventListener('resize', handleWindowResize);\n    }\n\n    if (untracked(() => source.status) === 'idle') {\n      requestAnimationFrame(() => (source.status = 'dragging'));\n    }\n\n    if (placeholder) {\n      resizeObserver.observe(placeholder);\n\n      elementMutationObserver = createElementMutationObserver(\n        element,\n        placeholder,\n        clone\n      );\n      documentMutationObserver = createDocumentMutationObserver(\n        element,\n        placeholder,\n        feedbackElement\n      );\n    }\n\n    /* ---- Cleanup ---- */\n\n    const id = manager.dragOperation.source?.id;\n\n    const restoreFocus = () => {\n      if (!isKeyboardOperation || id == null) return;\n\n      const draggable = manager.registry.draggables.get(id);\n      const focusTarget = draggable?.handle ?? draggable?.element;\n\n      if (isHTMLElement(focusTarget)) {\n        focusTarget.focus();\n      }\n    };\n\n    const cleanup = () => {\n      elementMutationObserver?.disconnect();\n      documentMutationObserver?.disconnect();\n      resizeObserver.disconnect();\n      feedbackWindow.removeEventListener('resize', handleWindowResize);\n\n      if (supportsPopover(feedbackElement)) {\n        feedbackElement.removeEventListener(\n          'beforetoggle',\n          preventPopoverClose\n        );\n        feedbackElement.removeAttribute('popover');\n      }\n\n      feedbackElement.removeAttribute(ATTRIBUTE);\n      styles.reset();\n\n      if (savedCellWidths && isTableRow(element)) {\n        const cells = Array.from(element.cells);\n\n        for (const [index, cell] of cells.entries()) {\n          cell.style.width = savedCellWidths[index] ?? '';\n        }\n      }\n\n      source.status = 'idle';\n\n      const moved = state.current.translate != null;\n      const isDragging = dragOperation.status.dragging;\n\n      if (\n        placeholder &&\n        ((!isDragging && moved) ||\n          placeholder.parentElement !== feedbackElement.parentElement) &&\n        feedbackElement.isConnected\n      ) {\n        placeholder.replaceWith(feedbackElement);\n      }\n\n      placeholder?.remove();\n    };\n\n    /* ---- Reactive effects ---- */\n\n    const optionsDropAnimation = options?.dropAnimation;\n    const feedbackPlugin = this;\n\n    const cleanupEffects = effects(\n      // Update transform on move\n      () => {\n        const {transform, status} = dragOperation;\n\n        if (!transform.x && !transform.y && !state.current.translate) {\n          return;\n        }\n\n        if (status.dragging) {\n          const initialTranslate = initial.translate ?? {x: 0, y: 0};\n          const translate = {\n            x: transform.x / frameTransform.scaleX + initialTranslate.x,\n            y: transform.y / frameTransform.scaleY + initialTranslate.y,\n          };\n          const previousTranslate = state.current.translate;\n          const modifiers = untracked(() => dragOperation.modifiers);\n          const currentShape = untracked(() => dragOperation.shape?.current);\n          const keyboardTransition = options?.keyboardTransition;\n          const translateTransition =\n            isKeyboardOperation &&\n            !reducedMotion &&\n            keyboardTransition !== null\n              ? `${keyboardTransition?.duration ?? 250}ms ${keyboardTransition?.easing ?? 'cubic-bezier(0.25, 1, 0.5, 1)'}`\n              : '0ms linear';\n\n          styles.set(\n            {\n              transition: feedbackTransition\n                ? `${feedbackTransition}, translate ${translateTransition}`\n                : `translate ${translateTransition}`,\n              translate: `${translate.x}px ${translate.y}px 0`,\n            },\n            CSS_PREFIX\n          );\n          elementMutationObserver?.takeRecords();\n\n          if (\n            currentShape &&\n            currentShape !== initialShape &&\n            previousTranslate &&\n            !modifiers.length\n          ) {\n            const delta = Point.delta(translate, previousTranslate);\n\n            dragOperation.shape = Rectangle.from(\n              currentShape.boundingRectangle\n            ).translate(\n              delta.x * frameTransform.scaleX,\n              delta.y * frameTransform.scaleY\n            );\n          } else {\n            dragOperation.shape = new DOMRectangle(feedbackElement);\n          }\n\n          state.current.translate = translate;\n        }\n      },\n      // Drop animation\n      function () {\n        if (dragOperation.status.dropped) {\n          this.dispose();\n\n          source.status = 'dropping';\n\n          const dropAnimationConfig =\n            entityOptions?.dropAnimation !== undefined\n              ? entityOptions.dropAnimation\n              : feedbackPlugin.dropAnimation !== undefined\n                ? feedbackPlugin.dropAnimation\n                : optionsDropAnimation;\n\n          let translate = state.current.translate;\n          const moved = translate != null;\n\n          if (!translate && element !== feedbackElement) {\n            translate = {x: 0, y: 0};\n          }\n\n          if (!translate || dropAnimationConfig === null) {\n            cleanup();\n            return;\n          }\n\n          manager.renderer.rendering.then(() => {\n            runDropAnimation({\n              source,\n              element,\n              feedbackElement,\n              placeholder,\n              translate: translate!,\n              moved,\n              transition,\n              alignment: source.alignment,\n              styles,\n              animation: dropAnimationConfig ?? undefined,\n              getElementMutationObserver: () => elementMutationObserver,\n              cleanup,\n              restoreFocus,\n            });\n          });\n        }\n      }\n    );\n\n    return () => {\n      cleanup();\n      cleanupEffects();\n    };\n  }\n\n  static configure = configurator(Feedback);\n}\n"
  },
  {
    "path": "packages/dom/src/core/plugins/feedback/constants.ts",
    "content": "export const ATTR_PREFIX = 'data-dnd-';\nexport const DROPPING_ATTRIBUTE = `${ATTR_PREFIX}dropping`;\nexport const CSS_PREFIX = '--dnd-';\nexport const ATTRIBUTE = `${ATTR_PREFIX}dragging`;\nexport const PLACEHOLDER_ATTRIBUTE = `${ATTR_PREFIX}placeholder`;\n\nexport const IGNORED_ATTRIBUTES = [\n  ATTRIBUTE,\n  PLACEHOLDER_ATTRIBUTE,\n  'popover',\n  'aria-pressed',\n  'aria-grabbing',\n];\n\nexport const IGNORED_STYLES = ['view-transition-name'];\n\nexport const CSS_RULES = `\n  :is(:root,:host) [${ATTRIBUTE}] {\n    position: fixed !important;\n    pointer-events: none !important;\n    touch-action: none;\n    z-index: calc(infinity);\n    will-change: translate;\n    top: var(${CSS_PREFIX}top, 0px) !important;\n    left: var(${CSS_PREFIX}left, 0px) !important;\n    right: unset !important;\n    bottom: unset !important;\n    width: var(${CSS_PREFIX}width, auto);\n    max-width: var(${CSS_PREFIX}width, auto);\n    height: var(${CSS_PREFIX}height, auto);\n    max-height: var(${CSS_PREFIX}height, auto);\n    transform: var(${CSS_PREFIX}transform, none) !important;\n    transition: var(${CSS_PREFIX}transition) !important;\n  }\n\n  :is(:root,:host) [${PLACEHOLDER_ATTRIBUTE}] {\n    transition: none;\n  }\n\n  :is(:root,:host) [${PLACEHOLDER_ATTRIBUTE}='hidden'] {\n    visibility: hidden;\n  }\n\n  [${ATTRIBUTE}] * {\n    pointer-events: none !important;\n  }\n\n  [${ATTRIBUTE}]:not([${DROPPING_ATTRIBUTE}]) {\n    translate: var(${CSS_PREFIX}translate) !important;\n  }\n\n  [${ATTRIBUTE}][style*='${CSS_PREFIX}scale'] {\n    scale: var(${CSS_PREFIX}scale) !important;\n    transform-origin: var(${CSS_PREFIX}transform-origin) !important;\n  }\n\n  @layer dnd-kit {\n    :where([${ATTRIBUTE}][popover]) {\n      overflow: visible;\n      background: unset;\n      border: unset;\n      margin: unset;\n      padding: unset;\n      color: inherit;\n\n      &:is(input, button) {\n        border: revert;\n        background: revert;\n      }\n    }\n  }\n  [${ATTRIBUTE}]::backdrop, [${ATTR_PREFIX}overlay]:not([${ATTRIBUTE}]) {\n    display: none;\n    visibility: hidden;\n  }\n`\n  .replace(/\\n+/g, ' ')\n  .replace(/\\s+/g, ' ')\n  .trim();\n"
  },
  {
    "path": "packages/dom/src/core/plugins/feedback/dropAnimation.ts",
    "content": "import {\n  animateTransform,\n  DOMRectangle,\n  getComputedStyles,\n  getFinalKeyframe,\n  getWindow,\n  parseTranslate,\n  prefersReducedMotion,\n  showPopover,\n  type Styles,\n} from '@dnd-kit/dom/utilities';\nimport {Rectangle, type Coordinates, type Alignment} from '@dnd-kit/geometry';\n\nimport type {Draggable} from '../../entities/index.ts';\nimport {CSS_PREFIX, DROPPING_ATTRIBUTE} from './constants.ts';\nimport {isSameFrame} from './utilities.ts';\n\nexport interface DropAnimationOptions {\n  /** Duration in milliseconds. @default 250 */\n  duration?: number;\n  /** CSS easing function. @default 'ease' */\n  easing?: string;\n}\n\nexport type DropAnimationFunction = (context: {\n  source: Draggable;\n  element: Element;\n  feedbackElement: Element;\n  placeholder: Element | null | undefined;\n  translate: Coordinates;\n  moved: boolean;\n}) => Promise<void> | void;\n\nexport type DropAnimation = DropAnimationOptions | DropAnimationFunction;\n\nconst DEFAULT_DURATION = 250;\nconst DEFAULT_EASING = 'ease';\n\nexport interface DropAnimationContext {\n  source: Draggable;\n  element: Element;\n  feedbackElement: Element;\n  placeholder: Element | null | undefined;\n  translate: Coordinates;\n  moved: boolean;\n  transition: string;\n  alignment: Alignment | undefined;\n  styles: Styles;\n  animation: DropAnimation | undefined;\n  getElementMutationObserver: () => MutationObserver | undefined;\n  cleanup: () => void;\n  restoreFocus: () => void;\n}\n\nexport function runDropAnimation(ctx: DropAnimationContext): void {\n  const {animation} = ctx;\n\n  if (typeof animation === 'function') {\n    const result = animation({\n      source: ctx.source,\n      element: ctx.element,\n      feedbackElement: ctx.feedbackElement,\n      placeholder: ctx.placeholder,\n      translate: ctx.translate,\n      moved: ctx.moved,\n    });\n\n    Promise.resolve(result).then(() => {\n      ctx.cleanup();\n      requestAnimationFrame(ctx.restoreFocus);\n    });\n\n    return;\n  }\n\n  const {\n    duration = DEFAULT_DURATION,\n    easing = DEFAULT_EASING,\n  } = animation ?? {};\n\n  showPopover(ctx.feedbackElement);\n\n  const [, runningAnimation] =\n    getFinalKeyframe(\n      ctx.feedbackElement,\n      (keyframe) => 'translate' in keyframe\n    ) ?? [];\n\n  runningAnimation?.pause();\n\n  const target = ctx.placeholder ?? ctx.element;\n  const options = {\n    frameTransform: isSameFrame(ctx.feedbackElement, target)\n      ? null\n      : undefined,\n  };\n  const current = new DOMRectangle(ctx.feedbackElement, options);\n  const currentTranslate =\n    parseTranslate(getComputedStyles(ctx.feedbackElement).translate) ??\n    ctx.translate;\n  const final = new DOMRectangle(target, options);\n  const delta = Rectangle.delta(current, final, ctx.alignment);\n  const finalTranslate = {\n    x: currentTranslate.x - delta.x,\n    y: currentTranslate.y - delta.y,\n  };\n  const heightKeyframes =\n    Math.round(current.intrinsicHeight) !== Math.round(final.intrinsicHeight)\n      ? {\n          minHeight: [\n            `${current.intrinsicHeight}px`,\n            `${final.intrinsicHeight}px`,\n          ],\n          maxHeight: [\n            `${current.intrinsicHeight}px`,\n            `${final.intrinsicHeight}px`,\n          ],\n        }\n      : {};\n  const widthKeyframes =\n    Math.round(current.intrinsicWidth) !== Math.round(final.intrinsicWidth)\n      ? {\n          minWidth: [\n            `${current.intrinsicWidth}px`,\n            `${final.intrinsicWidth}px`,\n          ],\n          maxWidth: [\n            `${current.intrinsicWidth}px`,\n            `${final.intrinsicWidth}px`,\n          ],\n        }\n      : {};\n\n  ctx.styles.set({transition: ctx.transition}, CSS_PREFIX);\n  ctx.feedbackElement.setAttribute(DROPPING_ATTRIBUTE, '');\n  ctx.getElementMutationObserver()?.takeRecords();\n\n  animateTransform({\n    element: ctx.feedbackElement,\n    keyframes: {\n      ...heightKeyframes,\n      ...widthKeyframes,\n      translate: [\n        `${currentTranslate.x}px ${currentTranslate.y}px 0`,\n        `${finalTranslate.x}px ${finalTranslate.y}px 0`,\n      ],\n    },\n    options: {\n      duration: prefersReducedMotion(getWindow(ctx.feedbackElement))\n        ? 0\n        : ctx.moved || ctx.feedbackElement !== ctx.element\n          ? duration\n          : 0,\n      easing,\n    },\n  }).then(() => {\n    ctx.feedbackElement.removeAttribute(DROPPING_ATTRIBUTE);\n    runningAnimation?.finish();\n    ctx.cleanup();\n    requestAnimationFrame(ctx.restoreFocus);\n  });\n}\n"
  },
  {
    "path": "packages/dom/src/core/plugins/feedback/index.ts",
    "content": "export {Feedback} from './Feedback.ts';\nexport type {FeedbackType, FeedbackOptions, KeyboardTransition} from './Feedback.ts';\nexport type {Transition} from './types.ts';\nexport type {\n  DropAnimation,\n  DropAnimationOptions,\n  DropAnimationFunction,\n} from './dropAnimation.ts';\n"
  },
  {
    "path": "packages/dom/src/core/plugins/feedback/observers.ts",
    "content": "import {\n  supportsStyle,\n  showPopover,\n  DOMRectangle,\n  getFixedPositionOffset,\n  type Styles,\n} from '@dnd-kit/dom/utilities';\nimport {Rectangle, type Coordinates} from '@dnd-kit/geometry';\n\nimport {CSS_PREFIX, IGNORED_ATTRIBUTES, IGNORED_STYLES} from './constants.ts';\nimport {isTableRow} from './utilities.ts';\n\nexport function createElementMutationObserver(\n  element: Element,\n  placeholder: Element,\n  clone: boolean\n): MutationObserver {\n  const observer = new MutationObserver((mutations) => {\n    let hasChildrenMutations = false;\n\n    for (const mutation of mutations) {\n      if (mutation.target !== element) {\n        hasChildrenMutations = true;\n        continue;\n      }\n\n      if (mutation.type !== 'attributes') {\n        continue;\n      }\n\n      // Attribute name is guaranteed to be non-null if type is \"attributes\"\n      // https://developer.mozilla.org/en-US/docs/Web/API/MutationRecord/attributeName#value\n      const attributeName = mutation.attributeName!;\n\n      if (\n        attributeName.startsWith('aria-') ||\n        IGNORED_ATTRIBUTES.includes(attributeName)\n      ) {\n        continue;\n      }\n\n      const attributeValue = element.getAttribute(attributeName);\n\n      if (attributeName === 'style') {\n        if (supportsStyle(element) && supportsStyle(placeholder)) {\n          const styles = element.style;\n\n          for (const key of Array.from(placeholder.style)) {\n            if (styles.getPropertyValue(key) === '') {\n              placeholder.style.removeProperty(key);\n            }\n          }\n\n          for (const key of Array.from(styles)) {\n            if (\n              IGNORED_STYLES.includes(key) ||\n              key.startsWith(CSS_PREFIX)\n            ) {\n              continue;\n            }\n\n            const value = styles.getPropertyValue(key);\n\n            placeholder.style.setProperty(key, value);\n          }\n        }\n      } else if (attributeValue !== null) {\n        placeholder.setAttribute(attributeName, attributeValue);\n      } else {\n        placeholder.removeAttribute(attributeName);\n      }\n    }\n\n    if (hasChildrenMutations && clone) {\n      placeholder.innerHTML = element.innerHTML;\n    }\n  });\n\n  observer.observe(element, {\n    attributes: true,\n    subtree: true,\n    childList: true,\n  });\n\n  return observer;\n}\n\nexport function createDocumentMutationObserver(\n  element: Element,\n  placeholder: Element,\n  feedbackElement: Element\n): MutationObserver {\n  const observer = new MutationObserver((entries) => {\n    for (const entry of entries) {\n      if (entry.addedNodes.length === 0) continue;\n\n      for (const node of Array.from(entry.addedNodes)) {\n        if (\n          node.contains(element) &&\n          element.nextElementSibling !== placeholder\n        ) {\n          element.insertAdjacentElement('afterend', placeholder);\n          showPopover(feedbackElement);\n          return;\n        }\n\n        if (\n          node.contains(placeholder) &&\n          placeholder.previousElementSibling !== element\n        ) {\n          placeholder.insertAdjacentElement('beforebegin', element);\n          showPopover(feedbackElement);\n          return;\n        }\n      }\n    }\n\n    // Handle the case where siblings were moved around a stationary\n    // source element (e.g., a VDOM framework reordered children).\n    // The addedNodes won't contain the element or placeholder, but\n    // they may no longer be adjacent.\n    if (\n      element.isConnected &&\n      placeholder.isConnected &&\n      element.nextElementSibling !== placeholder\n    ) {\n      element.insertAdjacentElement('afterend', placeholder);\n      showPopover(feedbackElement);\n    }\n  });\n\n  observer.observe(element.ownerDocument.body, {\n    childList: true,\n    subtree: true,\n  });\n\n  return observer;\n}\n\nexport interface ResizeObserverContext {\n  placeholder: Element;\n  element: Element;\n  feedbackElement: Element;\n  frameTransform: {x: number; y: number; scaleX: number; scaleY: number};\n  transformOrigin: Coordinates;\n  width: number;\n  height: number;\n  top: number;\n  left: number;\n  widthOffset: number;\n  heightOffset: number;\n  delta: Coordinates;\n  styles: Styles;\n  dragOperation: {shape: any};\n  getTranslate: () => Coordinates | undefined;\n  getElementMutationObserver: () => MutationObserver | undefined;\n  getSavedCellWidths: () => string[] | undefined;\n  setSavedCellWidths: (widths: string[]) => void;\n}\n\nexport function createResizeObserver(ctx: ResizeObserverContext): ResizeObserver {\n  return new ResizeObserver(() => {\n    const placeholderShape = new DOMRectangle(ctx.placeholder, {\n      frameTransform: ctx.frameTransform,\n      ignoreTransforms: true,\n    });\n    const origin = ctx.transformOrigin ?? {x: 1, y: 1};\n    const dX = (ctx.width - placeholderShape.width) * origin.x + ctx.delta.x;\n    const dY = (ctx.height - placeholderShape.height) * origin.y + ctx.delta.y;\n    const fixedOffset = getFixedPositionOffset();\n\n    ctx.styles.set(\n      {\n        width: placeholderShape.width - ctx.widthOffset,\n        height: placeholderShape.height - ctx.heightOffset,\n        top: ctx.top + dY + fixedOffset.y,\n        left: ctx.left + dX + fixedOffset.x,\n      },\n      CSS_PREFIX\n    );\n    ctx.getElementMutationObserver()?.takeRecords();\n\n    if (isTableRow(ctx.element) && isTableRow(ctx.placeholder)) {\n      const cells = Array.from(ctx.element.cells);\n      const placeholderCells = Array.from(ctx.placeholder.cells);\n\n      if (!ctx.getSavedCellWidths()) {\n        ctx.setSavedCellWidths(cells.map((cell) => cell.style.width));\n      }\n\n      for (const [index, cell] of cells.entries()) {\n        const placeholderCell = placeholderCells[index];\n\n        cell.style.width = `${placeholderCell.getBoundingClientRect().width}px`;\n      }\n    }\n\n    // Compute the shape from the CSS values we just set plus the logical\n    // translate, rather than measuring the feedbackElement with DOMRectangle.\n    // This avoids capturing in-flight CSS transition values when the\n    // ResizeObserver fires before the browser has created the transition.\n    const translate = ctx.getTranslate() ?? {x: 0, y: 0};\n    const shapeLeft = ctx.left + dX + fixedOffset.x + translate.x;\n    const shapeTop = ctx.top + dY + fixedOffset.y + translate.y;\n    const shapeWidth = placeholderShape.width - ctx.widthOffset;\n    const shapeHeight = placeholderShape.height - ctx.heightOffset;\n    const ft = ctx.frameTransform;\n\n    ctx.dragOperation.shape = new Rectangle(\n      shapeLeft * ft.scaleX + ft.x,\n      shapeTop * ft.scaleY + ft.y,\n      shapeWidth * ft.scaleX,\n      shapeHeight * ft.scaleY\n    );\n  });\n}\n"
  },
  {
    "path": "packages/dom/src/core/plugins/feedback/types.ts",
    "content": "export interface Transition {\n  /**\n   * The duration of the transition in milliseconds.\n   * @default 250\n   */\n  duration?: number;\n  /**\n   * The easing function to use for the transition.\n   * @default 'ease-in-out'\n   */\n  easing?: string;\n}\n"
  },
  {
    "path": "packages/dom/src/core/plugins/feedback/utilities.ts",
    "content": "import {untracked} from '@dnd-kit/state';\nimport {\n  cloneElement,\n  generateUniqueId,\n  getFrameElement,\n  showPopover,\n  ProxiedElements,\n  isElement,\n} from '@dnd-kit/dom/utilities';\n\nimport type {Draggable, Droppable} from '../../entities/index.ts';\nimport {ATTR_PREFIX, PLACEHOLDER_ATTRIBUTE} from './constants.ts';\n\n/**\n * Creates a placeholder element for a draggable source\n * The placeholder maintains the original element's dimensions and position\n */\nexport function createPlaceholder(\n  source: Draggable,\n  type = 'hidden'\n): Element | undefined {\n  return untracked(() => {\n    const {element, manager} = source;\n\n    if (!element || !manager) return;\n\n    const containedDroppables = findContainedDroppables(\n      element,\n      manager.registry.droppables\n    );\n    const cleanup: Array<() => void> = [];\n    const placeholder = cloneElement(element);\n    const {remove} = placeholder;\n\n    proxyDroppableElements(containedDroppables, placeholder, cleanup);\n    configurePlaceholder(placeholder, type);\n\n    // Override remove to handle cleanup of proxies\n    placeholder.remove = () => {\n      cleanup.forEach((fn) => fn());\n      remove.call(placeholder);\n    };\n\n    return placeholder;\n  });\n}\n\n/**\n * Maps droppable elements contained within the source element\n * Returns a map of droppables to their temporary identifier attributes\n */\nfunction findContainedDroppables(\n  element: Element,\n  droppables: Iterable<Droppable>\n): Map<Droppable, string> {\n  const containedDroppables = new Map<Droppable, string>();\n\n  for (const droppable of droppables) {\n    if (!droppable.element) continue;\n\n    if (element === droppable.element || element.contains(droppable.element)) {\n      const identifierAttribute = `${ATTR_PREFIX}${generateUniqueId('dom-id')}`;\n      droppable.element.setAttribute(identifierAttribute, '');\n      containedDroppables.set(droppable, identifierAttribute);\n    }\n  }\n\n  return containedDroppables;\n}\n\n/**\n * Sets up proxy relationships between original droppable elements and their clones\n */\nfunction proxyDroppableElements(\n  containedDroppables: Map<Droppable, string>,\n  placeholder: Element,\n  cleanup: Array<() => void>\n): void {\n  for (const [droppable, identifierAttribute] of containedDroppables) {\n    if (!droppable.element) continue;\n\n    const selector = `[${identifierAttribute}]`;\n    const clonedElement = placeholder.matches(selector)\n      ? placeholder\n      : placeholder.querySelector(selector);\n\n    droppable.element.removeAttribute(identifierAttribute);\n\n    if (!clonedElement) continue;\n\n    const originalElement = droppable.element;\n\n    droppable.proxy = clonedElement;\n    clonedElement.removeAttribute(identifierAttribute);\n\n    ProxiedElements.set(originalElement, clonedElement);\n\n    cleanup.push(() => {\n      ProxiedElements.delete(originalElement);\n      droppable.proxy = undefined;\n    });\n  }\n}\n\n/**\n * Configures accessibility and visual attributes for the placeholder\n */\nfunction configurePlaceholder(placeholder: Element, type = 'hidden'): void {\n  placeholder.setAttribute('inert', 'true');\n  placeholder.setAttribute('tab-index', '-1');\n  placeholder.setAttribute('aria-hidden', 'true');\n  placeholder.setAttribute(PLACEHOLDER_ATTRIBUTE, type);\n}\n\n/**\n * Checks if two elements are in the same frame context\n */\nexport function isSameFrame(element: Element, target: Element): boolean {\n  if (element === target) return true;\n  return getFrameElement(element) === getFrameElement(target);\n}\n\n/**\n * Prevent an element with the `popover` attribute from being closed\n */\nexport function preventPopoverClose(event: Event) {\n  const {target} = event;\n\n  if (\n    'newState' in event &&\n    event.newState === 'closed' &&\n    isElement(target) &&\n    target.hasAttribute('popover')\n  ) {\n    requestAnimationFrame(() => showPopover(target));\n  }\n}\n\nexport function isTableRow(element: Element): element is HTMLTableRowElement {\n  return element.tagName === 'TR';\n}\n"
  },
  {
    "path": "packages/dom/src/core/plugins/index.ts",
    "content": "export {Accessibility} from './accessibility/index.ts';\n\nexport {Cursor} from './cursor/index.ts';\n\nexport {Feedback} from './feedback/index.ts';\nexport type {Transition} from './feedback/types.ts';\nexport type {\n  FeedbackType,\n  FeedbackOptions,\n  DropAnimation,\n  DropAnimationOptions,\n  DropAnimationFunction,\n  KeyboardTransition,\n} from './feedback/index.ts';\n\nexport {AutoScroller, Scroller, ScrollListener} from './scrolling/index.ts';\nexport type {AutoScrollerOptions} from './scrolling/index.ts';\n\nexport {PreventSelection} from './selection/PreventSelection.ts';\n\nexport {StyleInjector} from './stylesheet/StyleInjector.ts';\n"
  },
  {
    "path": "packages/dom/src/core/plugins/scrolling/AutoScroller.ts",
    "content": "import {configurator, Plugin} from '@dnd-kit/abstract';\nimport {effect} from '@dnd-kit/state';\nimport type {CleanupFunction} from '@dnd-kit/state';\nimport type {Axis} from '@dnd-kit/geometry';\n\nimport type {DragDropManager} from '../../manager/index.ts';\nimport {Scroller} from './Scroller.ts';\nimport {scheduler} from '../../../utilities/scheduling/scheduler.ts';\n\nexport interface AutoScrollerOptions {\n  /**\n   * Base scroll speed multiplier. Higher values scroll faster.\n   * @default 25\n   */\n  acceleration?: number;\n  /**\n   * Percentage of container dimensions that defines the scroll activation zone.\n   * A single number applies to both axes. Use `{ x, y }` to set per-axis\n   * thresholds. Set an axis to `0` to disable auto-scrolling on that axis.\n   * @default { x: 0.2, y: 0.2 }\n   */\n  threshold?: number | Record<Axis, number>;\n}\n\nconst AUTOSCROLL_INTERVAL = 10;\n\nexport class AutoScroller extends Plugin<DragDropManager, AutoScrollerOptions> {\n  public destroy: CleanupFunction;\n\n  constructor(manager: DragDropManager, options?: AutoScrollerOptions) {\n    super(manager, options);\n\n    const scroller = manager.registry.plugins.get(Scroller);\n\n    if (!scroller) {\n      throw new Error('AutoScroller plugin depends on Scroller plugin');\n    }\n\n    this.destroy = effect(() => {\n      if (this.disabled) {\n        return;\n      }\n\n      // We consume the position from the drag operation\n      // so that this effect is run when the position changes\n      const {position: _, status} = manager.dragOperation;\n\n      if (status.dragging) {\n        const scrollOptions = {\n          acceleration: this.options?.acceleration,\n          threshold:\n            typeof this.options?.threshold === 'number'\n              ? {x: this.options.threshold, y: this.options.threshold}\n              : this.options?.threshold,\n        };\n\n        const canScroll = scroller.scroll(undefined, scrollOptions);\n\n        if (canScroll) {\n          scroller.autoScrolling = true;\n          const interval = setInterval(\n            () =>\n              scheduler.schedule(() =>\n                scroller.scroll(undefined, scrollOptions)\n              ),\n            AUTOSCROLL_INTERVAL\n          );\n\n          return () => {\n            clearInterval(interval);\n          };\n        } else {\n          scroller.autoScrolling = false;\n        }\n      }\n    });\n  }\n\n  static configure = configurator(AutoScroller);\n}\n"
  },
  {
    "path": "packages/dom/src/core/plugins/scrolling/ScrollIntent.ts",
    "content": "import {batch, effect, signal, type Signal} from '@dnd-kit/state';\nimport {Plugin} from '@dnd-kit/abstract';\nimport {Axes} from '@dnd-kit/geometry';\nimport type {Coordinates} from '@dnd-kit/geometry';\nimport {ScrollDirection} from '@dnd-kit/dom/utilities';\n\nimport type {DragDropManager} from '../../manager/index.ts';\n\nimport {ScrollLock} from './ScrollLock.ts';\n\nconst DIRECTIONS = [ScrollDirection.Forward, ScrollDirection.Reverse];\n\nclass ScrollIntent {\n  public x = new ScrollLock();\n  public y = new ScrollLock();\n\n  public isLocked(): boolean {\n    return this.x.isLocked() && this.y.isLocked();\n  }\n}\n\nexport class ScrollIntentTracker extends Plugin<DragDropManager> {\n  private signal: Signal<ScrollIntent | null>;\n\n  constructor(manager: DragDropManager) {\n    super(manager);\n\n    const scrollIntent = signal<ScrollIntent>(new ScrollIntent());\n    let previousDelta: Coordinates | null = null;\n\n    this.signal = scrollIntent;\n\n    effect(() => {\n      const {status} = manager.dragOperation;\n\n      if (!status.initialized) {\n        previousDelta = null;\n        scrollIntent.value = new ScrollIntent();\n        return;\n      }\n\n      const {delta} = manager.dragOperation.position;\n\n      if (previousDelta) {\n        const directions = {\n          x: getDirection(delta.x, previousDelta.x),\n          y: getDirection(delta.y, previousDelta.y),\n        };\n\n        const intent = scrollIntent.peek();\n\n        batch(() => {\n          for (const axis of Axes) {\n            for (const direction of DIRECTIONS) {\n              if (directions[axis] === direction) {\n                intent[axis].unlock(direction);\n              }\n            }\n          }\n\n          scrollIntent.value = intent;\n        });\n      }\n\n      previousDelta = delta;\n    });\n  }\n\n  get current(): ScrollIntent | null {\n    return this.signal.peek();\n  }\n}\n\nfunction getDirection(a: number, b: number): ScrollDirection {\n  return Math.sign(a - b);\n}\n"
  },
  {
    "path": "packages/dom/src/core/plugins/scrolling/ScrollListener.ts",
    "content": "import {CorePlugin} from '@dnd-kit/abstract';\nimport {effect} from '@dnd-kit/state';\n\nimport type {DragDropManager} from '../../manager/index.ts';\n\nconst listenerOptions: AddEventListenerOptions = {\n  capture: true,\n  passive: true,\n};\n\nexport class ScrollListener extends CorePlugin<DragDropManager> {\n  #timeout: NodeJS.Timeout | undefined;\n\n  constructor(manager: DragDropManager) {\n    super(manager);\n\n    const {dragOperation} = this.manager;\n\n    this.destroy = effect(() => {\n      const enabled = dragOperation.status.dragging;\n\n      if (enabled) {\n        const root = dragOperation.source?.element?.ownerDocument ?? document;\n\n        root.addEventListener('scroll', this.handleScroll, listenerOptions);\n\n        return () => {\n          root.removeEventListener(\n            'scroll',\n            this.handleScroll,\n            listenerOptions\n          );\n        };\n      }\n    });\n  }\n\n  private handleScroll = () => {\n    if (this.#timeout == null) {\n      this.#timeout = setTimeout(() => {\n        this.manager.collisionObserver.forceUpdate(false);\n        this.#timeout = undefined;\n      }, 50);\n    }\n  };\n}\n"
  },
  {
    "path": "packages/dom/src/core/plugins/scrolling/ScrollLock.ts",
    "content": "import {reactive} from '@dnd-kit/state';\nimport {ScrollDirection as Direction} from '@dnd-kit/dom/utilities';\n\nconst LOCKED = true;\nconst UNLOCKED = false;\n\nexport class ScrollLock {\n  @reactive private accessor [Direction.Forward] = LOCKED;\n  @reactive private accessor [Direction.Reverse] = LOCKED;\n\n  public isLocked(direction?: Direction): boolean {\n    if (direction === Direction.Idle) {\n      return false;\n    }\n\n    if (direction == null) {\n      return (\n        this[Direction.Forward] === LOCKED && this[Direction.Reverse] === LOCKED\n      );\n    }\n\n    return this[direction] === LOCKED;\n  }\n\n  public unlock(direction: Direction) {\n    if (direction === Direction.Idle) {\n      return;\n    }\n\n    this[direction] = UNLOCKED;\n  }\n}\n"
  },
  {
    "path": "packages/dom/src/core/plugins/scrolling/Scroller.ts",
    "content": "import {CorePlugin} from '@dnd-kit/abstract';\nimport {computed, deepEqual, reactive} from '@dnd-kit/state';\nimport {\n  canScroll,\n  detectScrollIntent,\n  getScrollableAncestors,\n  getElementFromPoint,\n  ScrollDirection,\n  scheduler,\n  isKeyboardEvent,\n  getDocument,\n  getFrameTransform,\n  getRoot,\n} from '@dnd-kit/dom/utilities';\nimport {Axes, type Axis, type Coordinates} from '@dnd-kit/geometry';\n\nimport type {DragDropManager} from '../../manager/index.ts';\n\nimport {ScrollIntentTracker} from './ScrollIntent.ts';\n\nexport interface ScrollOptions {\n  acceleration?: number;\n  threshold?: Record<Axis, number>;\n}\n\nexport class Scroller extends CorePlugin<DragDropManager> {\n  public getScrollableElements: () => Set<Element> | null;\n\n  private scrollIntentTracker: ScrollIntentTracker;\n\n  @reactive\n  public accessor autoScrolling = false;\n\n  constructor(manager: DragDropManager) {\n    super(manager);\n\n    let previousElementFromPoint: Element | null = null;\n    let previousScrollableElements: Set<Element> | null = null;\n    const elementFromPoint = computed(() => {\n      const {position, source} = manager.dragOperation;\n\n      if (!position) {\n        return null;\n      }\n\n      const element = getElementFromPoint(\n        getRoot(source?.element),\n        position.current\n      );\n\n      if (element) {\n        previousElementFromPoint = element;\n      }\n\n      return element ?? previousElementFromPoint;\n    });\n    const scrollableElements = computed(() => {\n      const element = elementFromPoint.value;\n      const {documentElement} = getDocument(element);\n\n      if (!element || element === documentElement) {\n        const {target} = manager.dragOperation;\n        const targetElement = target?.element;\n\n        if (targetElement) {\n          const elements = getScrollableAncestors(targetElement, {\n            excludeElement: false,\n          });\n          previousScrollableElements = elements;\n\n          return elements;\n        }\n      }\n\n      if (element) {\n        const elements = getScrollableAncestors(element, {\n          excludeElement: false,\n        });\n\n        if (\n          this.autoScrolling &&\n          previousScrollableElements &&\n          elements.size < previousScrollableElements?.size\n        ) {\n          return previousScrollableElements;\n        }\n\n        previousScrollableElements = elements;\n\n        return elements;\n      }\n\n      previousScrollableElements = null;\n\n      return null;\n    }, deepEqual);\n\n    this.getScrollableElements = () => {\n      return scrollableElements.value;\n    };\n\n    this.scrollIntentTracker = new ScrollIntentTracker(manager);\n\n    this.destroy = manager.monitor.addEventListener('dragmove', (event) => {\n      if (\n        this.disabled ||\n        event.defaultPrevented ||\n        !isKeyboardEvent(manager.dragOperation.activatorEvent) ||\n        !event.by\n      ) {\n        return;\n      }\n\n      // Prevent the move event if we can scroll to the new coordinates\n      if (this.scroll({by: event.by})) {\n        event.preventDefault();\n      }\n    });\n  }\n\n  #meta: {element: Element; by: Coordinates} | undefined;\n\n  #scroll = () => {\n    if (!this.#meta) {\n      return;\n    }\n\n    const {element, by} = this.#meta;\n\n    if (by.y) element.scrollTop += by.y;\n    if (by.x) element.scrollLeft += by.x;\n  };\n\n  public scroll = (\n    options?: {by: Coordinates},\n    scrollOptions?: ScrollOptions\n  ): boolean => {\n    if (this.disabled) {\n      return false;\n    }\n\n    const elements = this.getScrollableElements();\n\n    if (!elements) {\n      this.#meta = undefined;\n      return false;\n    }\n\n    const {position} = this.manager.dragOperation;\n    const currentPosition = position?.current;\n\n    if (currentPosition) {\n      const {by} = options ?? {};\n      const intent = by\n        ? {\n            x: getScrollIntent(by.x),\n            y: getScrollIntent(by.y),\n          }\n        : undefined;\n      const scrollIntent = intent\n        ? undefined\n        : this.scrollIntentTracker.current;\n\n      if (scrollIntent?.isLocked()) {\n        return false;\n      }\n\n      for (const scrollableElement of elements) {\n        const elementCanScroll = canScroll(scrollableElement, by);\n\n        if (elementCanScroll.x || elementCanScroll.y) {\n          const {speed, direction} = detectScrollIntent(\n            scrollableElement,\n            currentPosition,\n            intent,\n            scrollOptions?.acceleration,\n            scrollOptions?.threshold\n          );\n\n          if (scrollIntent) {\n            for (const axis of Axes) {\n              if (scrollIntent[axis].isLocked(direction[axis])) {\n                speed[axis] = 0;\n                direction[axis] = 0;\n              }\n            }\n          }\n\n          if (direction.x || direction.y) {\n            const {x, y} = by ?? direction;\n            const scrollLeftBy = x * speed.x;\n            const scrollTopBy = y * speed.y;\n\n            if (scrollLeftBy || scrollTopBy) {\n              const previousScrollBy = this.#meta?.by;\n\n              if (this.autoScrolling && previousScrollBy) {\n                const scrollIntentMismatch =\n                  (previousScrollBy.x && !scrollLeftBy) ||\n                  (previousScrollBy.y && !scrollTopBy);\n\n                if (scrollIntentMismatch) continue;\n              }\n\n              this.#meta = {\n                element: scrollableElement,\n                by: {\n                  x: scrollLeftBy,\n                  y: scrollTopBy,\n                },\n              };\n\n              scheduler.schedule(this.#scroll);\n\n              return true;\n            }\n          }\n        }\n      }\n    }\n\n    this.#meta = undefined;\n    return false;\n  };\n}\n\nfunction getScrollIntent(value: number) {\n  if (value > 0) {\n    return ScrollDirection.Forward;\n  }\n\n  if (value < 0) {\n    return ScrollDirection.Reverse;\n  }\n\n  return ScrollDirection.Idle;\n}\n"
  },
  {
    "path": "packages/dom/src/core/plugins/scrolling/index.ts",
    "content": "export {Scroller} from './Scroller.ts';\nexport {AutoScroller} from './AutoScroller.ts';\nexport type {AutoScrollerOptions} from './AutoScroller.ts';\nexport {ScrollListener} from './ScrollListener.ts';\n"
  },
  {
    "path": "packages/dom/src/core/plugins/selection/PreventSelection.ts",
    "content": "import {Plugin} from '@dnd-kit/abstract';\nimport {effect} from '@dnd-kit/state';\n\nimport {DragDropManager} from '../../manager/index.ts';\nimport {StyleInjector} from '../stylesheet/StyleInjector.ts';\n\nconst CSS_RULES =\n  '* { user-select: none !important; -webkit-user-select: none !important; }';\n\nexport class PreventSelection extends Plugin<DragDropManager> {\n  constructor(public manager: DragDropManager) {\n    super(manager);\n\n    const styleInjector = manager.registry.plugins.get(\n      StyleInjector as any\n    ) as StyleInjector | undefined;\n\n    const unregisterStyles = styleInjector?.register(CSS_RULES);\n\n    this.destroy = effect(() => {\n      const {dragOperation} = this.manager;\n\n      if (dragOperation.status.initialized) {\n        removeSelection();\n        document.addEventListener('selectionchange', removeSelection, {\n          capture: true,\n        });\n\n        return () => {\n          document.removeEventListener('selectionchange', removeSelection, {\n            capture: true,\n          });\n        };\n      }\n    });\n\n    if (unregisterStyles) {\n      const originalDestroy = this.destroy.bind(this);\n      this.destroy = () => {\n        unregisterStyles();\n        originalDestroy();\n      };\n    }\n  }\n}\n\nfunction removeSelection() {\n  document.getSelection()?.removeAllRanges();\n}\n"
  },
  {
    "path": "packages/dom/src/core/plugins/stylesheet/StyleInjector.ts",
    "content": "import {CorePlugin, configurator} from '@dnd-kit/abstract';\nimport {derived, reactive, untracked} from '@dnd-kit/state';\nimport {getRoot, isDocument, isShadowRoot} from '@dnd-kit/dom/utilities';\n\nimport type {DragDropManager} from '../../manager/index.ts';\n\ntype CleanupFunction = () => void;\n\nexport interface StyleInjectorOptions {\n  nonce?: string;\n}\n\ninterface StyleRegistration {\n  refCount: number;\n  cleanup: CleanupFunction;\n}\n\nconst styleRegistry = new Map<\n  Document | ShadowRoot,\n  Map<string, StyleRegistration>\n>();\n\nexport class StyleInjector extends CorePlugin<\n  DragDropManager,\n  StyleInjectorOptions\n> {\n  #registeredRules = new Set<string>();\n\n  @reactive\n  private accessor additionalRoots = new Set<Document | ShadowRoot>();\n\n  constructor(manager: DragDropManager, options?: StyleInjectorOptions) {\n    super(manager, options);\n\n    this.registerEffect(this.#syncStyles);\n  }\n\n  /**\n   * Registers CSS rules to be injected into the active drag operation's\n   * document and shadow roots. The StyleInjector handles tracking\n   * which roots need the styles and cleaning up when they're no longer needed.\n   *\n   * Returns a cleanup function that unregisters the rules.\n   */\n  public register(cssRules: string): CleanupFunction {\n    this.#registeredRules.add(cssRules);\n\n    return () => {\n      this.#registeredRules.delete(cssRules);\n    };\n  }\n\n  /**\n   * Adds an additional root to track for style injection.\n   * Returns a cleanup function that removes the root.\n   */\n  public addRoot(root: Document | ShadowRoot): CleanupFunction {\n    untracked(() => {\n      const roots = new Set(this.additionalRoots);\n      roots.add(root);\n      this.additionalRoots = roots;\n    });\n\n    return () => {\n      untracked(() => {\n        const roots = new Set(this.additionalRoots);\n        roots.delete(root);\n        this.additionalRoots = roots;\n      });\n    };\n  }\n\n  @derived\n  private get sourceRoot() {\n    const {source} = this.manager.dragOperation;\n    return getRoot(source?.element ?? null);\n  }\n\n  @derived\n  private get targetRoot() {\n    const {target} = this.manager.dragOperation;\n    return getRoot(target?.element ?? null);\n  }\n\n  @derived\n  private get roots(): Set<Document | ShadowRoot> {\n    const {status} = this.manager.dragOperation;\n\n    if (status.initializing || status.initialized) {\n      const roots = [this.sourceRoot, this.targetRoot].filter(\n        (root) => root != null\n      );\n      return new Set([...roots, ...this.additionalRoots]);\n    }\n\n    return new Set();\n  }\n\n  #syncStyles() {\n    const {roots} = this;\n    const cleanups: CleanupFunction[] = [];\n\n    for (const root of roots) {\n      for (const cssRules of this.#registeredRules) {\n        cleanups.push(this.#inject(root, cssRules));\n      }\n    }\n\n    return () => {\n      for (const cleanup of cleanups) {\n        cleanup();\n      }\n    };\n  }\n\n  #inject(root: Document | ShadowRoot, cssRules: string): CleanupFunction {\n    let rootStyles = styleRegistry.get(root);\n\n    if (!rootStyles) {\n      rootStyles = new Map();\n      styleRegistry.set(root, rootStyles);\n    }\n\n    let registration = rootStyles.get(cssRules);\n\n    if (!registration) {\n      const created = isDocument(root)\n        ? this.#injectStyleElement(root, rootStyles, cssRules)\n        : this.#injectAdoptedSheet(root, rootStyles, cssRules);\n\n      if (!created) {\n        return () => {};\n      }\n\n      registration = created;\n      rootStyles.set(cssRules, registration);\n    }\n\n    registration.refCount++;\n\n    let disposed = false;\n\n    return () => {\n      if (disposed) return;\n      disposed = true;\n\n      registration!.refCount--;\n\n      if (registration!.refCount === 0) {\n        registration!.cleanup();\n      }\n    };\n  }\n\n  /**\n   * For Document roots, prepend a <style> element to <head> so that any\n   * @layer declarations appear before layers from regular stylesheets,\n   * giving them the lowest cascade priority.\n   */\n  #injectStyleElement(\n    root: Document,\n    rootStyles: Map<string, StyleRegistration>,\n    cssRules: string\n  ): StyleRegistration | null {\n    const style = root.createElement('style');\n    const {nonce} = this.options ?? {};\n\n    if (nonce) {\n      style.setAttribute('nonce', nonce);\n    }\n\n    style.textContent = cssRules;\n    root.head.prepend(style);\n\n    const observer = new MutationObserver((entries) => {\n      for (const entry of entries) {\n        for (const node of Array.from(entry.removedNodes)) {\n          if (node === style) {\n            root.head.prepend(style);\n            return;\n          }\n        }\n      }\n    });\n\n    observer.observe(root.head, {childList: true});\n\n    return {\n      refCount: 0,\n      cleanup: () => {\n        observer.disconnect();\n        style.remove();\n\n        rootStyles.delete(cssRules);\n\n        if (rootStyles.size === 0) {\n          styleRegistry.delete(root);\n        }\n      },\n    };\n  }\n\n  /**\n   * For ShadowRoot roots, use adoptedStyleSheets to avoid DOM side effects\n   * like interfering with :first-child or :nth-child selectors.\n   */\n  #injectAdoptedSheet(\n    root: ShadowRoot,\n    rootStyles: Map<string, StyleRegistration>,\n    cssRules: string\n  ): StyleRegistration | null {\n    if (\n      !(\n        'adoptedStyleSheets' in root &&\n        Array.isArray(root.adoptedStyleSheets)\n      ) &&\n      process.env.NODE_ENV !== 'production'\n    ) {\n      console.error(\n        \"Cannot inject styles: This browser doesn't support adoptedStyleSheets\"\n      );\n    }\n\n    const targetWindow = root.ownerDocument.defaultView;\n    const {CSSStyleSheet} = targetWindow ?? {};\n\n    if (!CSSStyleSheet) {\n      if (process.env.NODE_ENV !== 'production') {\n        console.error(\n          'Cannot inject styles: CSSStyleSheet constructor not available'\n        );\n      }\n\n      return null;\n    }\n\n    const sheet = new CSSStyleSheet();\n    sheet.replaceSync(cssRules);\n    root.adoptedStyleSheets.push(sheet);\n\n    return {\n      refCount: 0,\n      cleanup: () => {\n        if (isShadowRoot(root) && root.host?.isConnected) {\n          const index = root.adoptedStyleSheets.indexOf(sheet);\n          if (index !== -1) {\n            root.adoptedStyleSheets.splice(index, 1);\n          }\n        }\n\n        rootStyles.delete(cssRules);\n\n        if (rootStyles.size === 0) {\n          styleRegistry.delete(root);\n        }\n      },\n    };\n  }\n\n  static configure = configurator(StyleInjector);\n}\n"
  },
  {
    "path": "packages/dom/src/core/sensors/drag/DragSensor.ts",
    "content": "import {Sensor} from '@dnd-kit/abstract';\nimport {effect} from '@dnd-kit/state';\nimport type {CleanupFunction} from '@dnd-kit/state';\nimport {Listeners, isElement} from '@dnd-kit/dom/utilities';\n\nimport type {DragDropManager} from '../../manager/index.ts';\nimport type {Draggable} from '../../entities/index.ts';\n\nimport {encode, decode} from './encoding.ts';\n\ninterface DragSensorOptions {}\n\n/**\n * The DragSensor class is a Sensor that handles native HTML drag and drop events\n */\nexport class DragSensor extends Sensor<DragDropManager, DragSensorOptions> {\n  private listeners = new Listeners();\n  private unbind: CleanupFunction | undefined;\n\n  constructor(\n    public manager: DragDropManager,\n    public options: DragSensorOptions\n  ) {\n    super(manager);\n\n    this.listeners.bind(document, [\n      {type: 'dragenter', listener: this.handleDragEnter.bind(this)},\n      {type: 'dragleave', listener: this.handleDragLeave.bind(this)},\n    ]);\n  }\n\n  public bind(source: Draggable, options: DragSensorOptions) {\n    const unbind = effect(() => {\n      const target = source.handle ?? source.element;\n      const listener: EventListener = (event: Event) => {\n        if (event instanceof DragEvent) {\n          this.handleDragStart(event, source, options);\n        }\n      };\n\n      if (target) {\n        target.addEventListener('dragstart', listener);\n\n        return () => {\n          target.removeEventListener('dragstart', listener);\n        };\n      }\n    });\n\n    return unbind;\n  }\n\n  private handleDragStart = (\n    event: DragEvent,\n    source: Draggable,\n    _options: DragSensorOptions\n  ) => {\n    if (!isElement(event.target)) {\n      return;\n    }\n\n    if (source.disabled === true) {\n      return;\n    }\n\n    const element = source.handle ?? source.element;\n\n    if (!element) {\n      return;\n    }\n\n    this.manager.actions.setDragSource(source.id);\n\n    event.stopImmediatePropagation();\n\n    event.dataTransfer?.clearData();\n\n    const {width, height} = element.getBoundingClientRect();\n\n    const data = encode({\n      id: source.id,\n      type: source.type,\n      rect: {width, height},\n    });\n\n    event.dataTransfer?.setData(`application/dnd-kit;${data}`, ' ');\n\n    this.unbind = this.listeners.bind(document, [\n      {\n        type: 'drag',\n        listener: this.handlePointerMove.bind(this),\n      },\n      {\n        type: 'dragover',\n        listener: this.handleDragOver.bind(this),\n      },\n      {\n        type: 'dragend',\n        listener: this.handlePointerUp.bind(this),\n      },\n    ]);\n  };\n\n  private handleDragEnter(event: DragEvent) {\n    if (this.disabled || event.relatedTarget) {\n      return;\n    }\n\n    const data = event.dataTransfer?.types;\n    const type = data?.find((type) => type.startsWith('application/dnd-kit;'));\n\n    if (type) {\n      const [_, encoded] = type.split(';');\n\n      try {\n        const decoded = decode(encoded);\n\n        console.log(encoded, decoded);\n      } catch {\n        // no-op\n      }\n    }\n  }\n\n  private handleDragLeave(event: DragEvent) {\n    if (event.relatedTarget) {\n      return;\n    }\n  }\n\n  private handleDragOver(event: DragEvent) {\n    event.preventDefault();\n\n    if (event.dataTransfer) {\n      event.dataTransfer.dropEffect = 'move';\n    }\n  }\n\n  private handlePointerMove(event: DragEvent) {\n    event.preventDefault();\n    event.stopPropagation();\n\n    if (this.manager.dragOperation.status.idle) {\n      this.manager.actions.start({\n        event,\n        coordinates: {\n          x: event.clientX,\n          y: event.clientY,\n        },\n      });\n      return;\n    }\n\n    this.manager.actions.move({\n      to: {\n        x: event.clientX,\n        y: event.clientY,\n      },\n    });\n  }\n\n  private handlePointerUp(event: DragEvent) {\n    event.preventDefault();\n    event.stopPropagation();\n\n    this.manager.actions.stop();\n    this.unbind?.();\n  }\n\n  public destroy() {\n    this.listeners.clear();\n  }\n}\n"
  },
  {
    "path": "packages/dom/src/core/sensors/drag/encoding.ts",
    "content": "export function encode(data: Record<string, any>) {\n  return encodeUpperCase(btoa(JSON.stringify(data)));\n}\n\nexport function decode(data: string) {\n  return JSON.parse(atob(decodeUpperCase(data)));\n}\n\nconst PREFIX = '\\u200B\\u200C';\nconst SUFFIX = '\\u200C\\u200B';\n\nfunction encodeUpperCase(str: string): string {\n  return str.replace(/([A-Z]+)/g, `${PREFIX}$1${SUFFIX}`);\n}\n\nfunction decodeUpperCase(str: string): string {\n  const escapeRegExp = (escape: string) => ['', ...escape.split('')].join('\\\\');\n\n  return str.replace(\n    new RegExp(`${escapeRegExp(PREFIX)}(.*?)${escapeRegExp(SUFFIX)}`, 'g'),\n    (_, match: string) => match.toUpperCase()\n  );\n}\n"
  },
  {
    "path": "packages/dom/src/core/sensors/drag/index.ts",
    "content": "export {DragSensor} from './DragSensor.ts';\n"
  },
  {
    "path": "packages/dom/src/core/sensors/keyboard/KeyboardSensor.ts",
    "content": "import {configurator, Sensor} from '@dnd-kit/abstract';\nimport {effect} from '@dnd-kit/state';\nimport type {CleanupFunction} from '@dnd-kit/state';\nimport {\n  getDocument,\n  isElement,\n  isKeyboardEvent,\n  scrollIntoViewIfNeeded,\n  Listeners,\n  DOMRectangle,\n} from '@dnd-kit/dom/utilities';\n\nimport type {DragDropManager} from '../../manager/index.ts';\nimport type {Draggable} from '../../entities/index.ts';\nimport {AutoScroller} from '../../plugins/index.ts';\n\nexport type KeyCode = KeyboardEvent['code'];\n\nexport type KeyboardCodes = {\n  start: KeyCode[];\n  cancel: KeyCode[];\n  end: KeyCode[];\n  up: KeyCode[];\n  down: KeyCode[];\n  left: KeyCode[];\n  right: KeyCode[];\n};\n\nexport interface KeyboardSensorOptions {\n  /**\n   * The offset by which the keyboard sensor should move the draggable.\n   *\n   * @default 10\n   */\n  offset?: number | {x: number; y: number};\n  /**\n   * The keyboard codes that activate the keyboard sensor.\n   *\n   * @default {\n   *   start: ['Space', 'Enter'],\n   *   cancel: ['Escape'],\n   *   end: ['Space', 'Enter', 'Tab'],\n   *   up: ['ArrowUp'],\n   *   down: ['ArrowDown'],\n   *   left: ['ArrowLeft'],\n   *   right: ['ArrowRight']\n   * }\n   */\n  keyboardCodes?: KeyboardCodes;\n  /**\n   * Function that determines if the keyboard sensor should activate.\n   */\n  preventActivation?: (event: KeyboardEvent, source: Draggable) => boolean;\n}\n\nconst defaults = Object.freeze<Required<KeyboardSensorOptions>>({\n  offset: 10,\n  keyboardCodes: {\n    start: ['Space', 'Enter'],\n    cancel: ['Escape'],\n    end: ['Space', 'Enter', 'Tab'],\n    up: ['ArrowUp'],\n    down: ['ArrowDown'],\n    left: ['ArrowLeft'],\n    right: ['ArrowRight'],\n  },\n  preventActivation(event, source) {\n    const target = source.handle ?? source.element;\n    return event.target !== target;\n  },\n});\n\n/**\n * The KeyboardSensor class is an input sensor that handles Keyboard events.\n */\nexport class KeyboardSensor extends Sensor<\n  DragDropManager,\n  KeyboardSensorOptions\n> {\n  constructor(\n    public manager: DragDropManager,\n    public options?: KeyboardSensorOptions\n  ) {\n    super(manager);\n  }\n\n  #cleanupFunctions: CleanupFunction[] = [];\n\n  protected listeners = new Listeners();\n\n  public bind(source: Draggable, options = this.options) {\n    const unbind = effect(() => {\n      const target = source.handle ?? source.element;\n      const listener: EventListener = (event: Event) => {\n        if (isKeyboardEvent(event)) {\n          this.handleSourceKeyDown(event, source, options);\n        }\n      };\n\n      if (target) {\n        target.addEventListener('keydown', listener);\n\n        return () => {\n          target.removeEventListener('keydown', listener);\n        };\n      }\n    });\n\n    return unbind;\n  }\n\n  protected handleSourceKeyDown = (\n    event: KeyboardEvent,\n    source: Draggable,\n    options: KeyboardSensorOptions | undefined\n  ) => {\n    if (this.disabled || event.defaultPrevented) {\n      return;\n    }\n\n    if (!isElement(event.target)) {\n      return;\n    }\n\n    if (source.disabled) {\n      return;\n    }\n\n    const {\n      keyboardCodes = defaults.keyboardCodes,\n      preventActivation = defaults.preventActivation,\n    } = options ?? {};\n\n    if (!keyboardCodes.start.includes(event.code)) {\n      return;\n    }\n\n    if (!this.manager.dragOperation.status.idle) {\n      return;\n    }\n\n    if (preventActivation?.(event, source)) return;\n\n    this.handleStart(event, source, options);\n  };\n\n  protected handleStart(\n    event: KeyboardEvent,\n    source: Draggable,\n    options: KeyboardSensorOptions | undefined\n  ) {\n    const {element} = source;\n\n    if (!element) {\n      throw new Error('Source draggable does not have an associated element');\n    }\n\n    event.preventDefault();\n    event.stopImmediatePropagation();\n\n    scrollIntoViewIfNeeded(element);\n\n    const {center} = new DOMRectangle(element);\n    const controller = this.manager.actions.start({\n      event,\n      coordinates: {\n        x: center.x,\n        y: center.y,\n      },\n      source,\n    });\n\n    if (controller.signal.aborted) return this.cleanup();\n\n    this.sideEffects();\n\n    const sourceDocument = getDocument(element);\n    const listeners = [\n      this.listeners.bind(sourceDocument, [\n        {\n          type: 'keydown',\n          listener: (event: KeyboardEvent) =>\n            this.handleKeyDown(event, source, options),\n          options: {capture: true},\n        },\n      ]),\n    ];\n\n    this.#cleanupFunctions.push(...listeners);\n  }\n\n  protected handleKeyDown(\n    event: KeyboardEvent,\n    _source: Draggable,\n    options: KeyboardSensorOptions | undefined\n  ) {\n    const {keyboardCodes = defaults.keyboardCodes} = options ?? {};\n\n    if (isKeycode(event, [...keyboardCodes.end, ...keyboardCodes.cancel])) {\n      event.preventDefault();\n      const canceled = isKeycode(event, keyboardCodes.cancel);\n\n      this.handleEnd(event, canceled);\n      return;\n    }\n\n    if (isKeycode(event, keyboardCodes.up)) {\n      this.handleMove('up', event);\n    } else if (isKeycode(event, keyboardCodes.down)) {\n      this.handleMove('down', event);\n    }\n\n    if (isKeycode(event, keyboardCodes.left)) {\n      this.handleMove('left', event);\n    } else if (isKeycode(event, keyboardCodes.right)) {\n      this.handleMove('right', event);\n    }\n  }\n\n  protected handleEnd(event: Event, canceled: boolean) {\n    this.manager.actions.stop({\n      event,\n      canceled,\n    });\n\n    this.cleanup();\n  }\n\n  protected handleMove(\n    direction: 'up' | 'down' | 'left' | 'right',\n    event: KeyboardEvent\n  ) {\n    const {shape} = this.manager.dragOperation;\n    const factor = event.shiftKey ? 5 : 1;\n    let by = {\n      x: 0,\n      y: 0,\n    };\n    let offset = this.options?.offset ?? defaults.offset;\n\n    if (typeof offset === 'number') {\n      offset = {x: offset, y: offset};\n    }\n\n    if (!shape) {\n      return;\n    }\n\n    switch (direction) {\n      case 'up':\n        by = {x: 0, y: -offset.y * factor};\n        break;\n      case 'down':\n        by = {x: 0, y: offset.y * factor};\n        break;\n      case 'left':\n        by = {x: -offset.x * factor, y: 0};\n        break;\n      case 'right':\n        by = {x: offset.x * factor, y: 0};\n        break;\n    }\n\n    if (by.x || by.y) {\n      event.preventDefault();\n\n      this.manager.actions.move({\n        event,\n        by,\n      });\n    }\n  }\n\n  private sideEffects() {\n    const autoScroller = this.manager.registry.plugins.get(AutoScroller as any);\n\n    if (autoScroller?.disabled === false) {\n      autoScroller.disable();\n\n      this.#cleanupFunctions.push(() => {\n        autoScroller.enable();\n      });\n    }\n  }\n\n  protected cleanup() {\n    this.#cleanupFunctions.forEach((cleanup) => cleanup());\n    this.#cleanupFunctions = [];\n  }\n\n  public destroy() {\n    this.cleanup();\n    // Remove all event listeners\n    this.listeners.clear();\n  }\n\n  static configure = configurator(KeyboardSensor);\n\n  static defaults = defaults;\n}\n\nfunction isKeycode(event: KeyboardEvent, codes: KeyCode[]) {\n  return codes.includes(event.code);\n}\n"
  },
  {
    "path": "packages/dom/src/core/sensors/keyboard/index.ts",
    "content": "export {KeyboardSensor} from './KeyboardSensor.ts';\n"
  },
  {
    "path": "packages/dom/src/core/sensors/pointer/DelayConstraint.ts",
    "content": "import {ActivationConstraint} from '@dnd-kit/abstract';\nimport {\n  exceedsDistance,\n  type Distance,\n  type Coordinates,\n} from '@dnd-kit/geometry';\nimport {getEventCoordinates} from '@dnd-kit/dom/utilities';\n\nexport interface DelayConstraintOptions {\n  value: number;\n  tolerance: Distance;\n}\n\nexport class DelayConstraint extends ActivationConstraint<\n  PointerEvent,\n  DelayConstraintOptions\n> {\n  #timeout?: ReturnType<typeof setTimeout>;\n  #coordinates?: Coordinates;\n\n  onEvent(event: PointerEvent) {\n    switch (event.type) {\n      case 'pointerdown':\n        this.#coordinates = getEventCoordinates(event);\n        this.#timeout = setTimeout(\n          () => this.activate(event),\n          this.options.value\n        );\n        break;\n      case 'pointermove':\n        if (!this.#coordinates) return;\n\n        const {x, y} = getEventCoordinates(event);\n        const delta = {\n          x: x - this.#coordinates.x,\n          y: y - this.#coordinates.y,\n        };\n\n        if (exceedsDistance(delta, this.options.tolerance)) {\n          this.abort();\n        }\n        break;\n      case 'pointerup':\n        this.abort();\n        break;\n    }\n  }\n\n  abort() {\n    if (this.#timeout) {\n      clearTimeout(this.#timeout);\n      this.#coordinates = undefined;\n      this.#timeout = undefined;\n    }\n  }\n}\n"
  },
  {
    "path": "packages/dom/src/core/sensors/pointer/DistanceConstraint.ts",
    "content": "import {ActivationConstraint} from '@dnd-kit/abstract';\nimport {\n  exceedsDistance,\n  type Distance,\n  type Coordinates,\n} from '@dnd-kit/geometry';\nimport {getEventCoordinates} from '@dnd-kit/dom/utilities';\n\nexport interface DistanceConstraintOptions {\n  value: number;\n  tolerance?: Distance;\n}\n\nexport class DistanceConstraint extends ActivationConstraint<\n  PointerEvent,\n  DistanceConstraintOptions\n> {\n  #coordinates?: Coordinates;\n\n  onEvent(event: PointerEvent) {\n    switch (event.type) {\n      case 'pointerdown':\n        this.#coordinates = getEventCoordinates(event);\n        break;\n      case 'pointermove':\n        if (!this.#coordinates) return;\n\n        const {x, y} = getEventCoordinates(event);\n        const delta = {\n          x: x - this.#coordinates.x,\n          y: y - this.#coordinates.y,\n        };\n\n        const {tolerance} = this.options;\n\n        if (tolerance && exceedsDistance(delta, tolerance)) {\n          this.abort();\n          return;\n        }\n\n        if (exceedsDistance(delta, this.options.value)) {\n          this.activate(event);\n        }\n        break;\n      case 'pointerup':\n        this.abort();\n        break;\n    }\n  }\n\n  abort() {\n    this.#coordinates = undefined;\n  }\n}\n"
  },
  {
    "path": "packages/dom/src/core/sensors/pointer/PointerActivationConstraints.ts",
    "content": "import {DistanceConstraint} from './DistanceConstraint.ts';\nimport {DelayConstraint} from './DelayConstraint.ts';\n\nexport class PointerActivationConstraints {\n  static Delay = DelayConstraint;\n  static Distance = DistanceConstraint;\n}\n"
  },
  {
    "path": "packages/dom/src/core/sensors/pointer/PointerSensor.ts",
    "content": "import {effect} from '@dnd-kit/state';\nimport type {CleanupFunction} from '@dnd-kit/state';\nimport {\n  Sensor,\n  configurator,\n  ActivationController,\n  type ActivationConstraints,\n} from '@dnd-kit/abstract';\nimport type {Coordinates} from '@dnd-kit/geometry';\nimport {\n  getDocument,\n  getDocuments,\n  getEventCoordinates,\n  getFrameTransform,\n  isElement,\n  isHTMLElement,\n  isInteractiveElement,\n  isPointerEvent,\n  isTextInput,\n  Listeners,\n  scheduler,\n} from '@dnd-kit/dom/utilities';\n\nimport type {DragDropManager} from '../../manager/index.ts';\nimport type {Draggable} from '../../entities/index.ts';\n\nimport {PointerActivationConstraints} from './PointerActivationConstraints.ts';\n\ntype Maybe<T> = T | undefined;\n\nexport interface PointerSensorOptions {\n  activationConstraints?:\n    | ActivationConstraints<PointerEvent>\n    | ((\n        event: PointerEvent,\n        source: Draggable\n      ) => ActivationConstraints<PointerEvent> | undefined);\n  activatorElements?:\n    | Maybe<Element>[]\n    | ((source: Draggable) => Maybe<Element>[]);\n  preventActivation?: (event: PointerEvent, source: Draggable) => boolean;\n}\n\nconst defaults = Object.freeze<PointerSensorOptions>({\n  activationConstraints(event, source) {\n    const {pointerType, target} = event;\n\n    if (\n      pointerType === 'mouse' &&\n      isElement(target) &&\n      (source.handle === target || source.handle?.contains(target))\n    ) {\n      return undefined;\n    }\n\n    if (pointerType === 'touch') {\n      return [\n        new PointerActivationConstraints.Delay({value: 250, tolerance: 5}),\n      ];\n    }\n\n    if (isTextInput(target) && !event.defaultPrevented) {\n      return [\n        new PointerActivationConstraints.Delay({value: 200, tolerance: 0}),\n      ];\n    }\n\n    return [\n      new PointerActivationConstraints.Delay({value: 200, tolerance: 10}),\n      new PointerActivationConstraints.Distance({value: 5}),\n    ];\n  },\n  preventActivation(event, source) {\n    const {target} = event;\n\n    if (target === source.element) return false;\n    if (target === source.handle) return false;\n    if (!isElement(target)) return false;\n    if (source.handle?.contains(target)) return false;\n\n    return isInteractiveElement(target);\n  },\n});\n\ntype LatestState = {\n  event: PointerEvent | undefined;\n  coordinates: Coordinates | undefined;\n};\n\n/**\n * The PointerSensor class is an input sensor that handles Pointer events,\n * such as mouse, touch and pen interactions.\n */\nexport class PointerSensor extends Sensor<\n  DragDropManager,\n  PointerSensorOptions\n> {\n  #cleanup: Set<CleanupFunction> = new Set();\n\n  protected listeners = new Listeners();\n\n  protected initialCoordinates: Coordinates | undefined;\n\n  protected controller: ActivationController<PointerEvent> | undefined;\n\n  constructor(\n    public manager: DragDropManager,\n    public options?: PointerSensorOptions\n  ) {\n    super(manager);\n\n    this.handleCancel = this.handleCancel.bind(this);\n    this.handlePointerUp = this.handlePointerUp.bind(this);\n    this.handleKeyDown = this.handleKeyDown.bind(this);\n  }\n\n  protected activationConstraints(\n    event: PointerEvent,\n    source: Draggable,\n    options = this.options\n  ) {\n    const {activationConstraints = defaults.activationConstraints} =\n      options ?? {};\n\n    const constraints =\n      typeof activationConstraints === 'function'\n        ? activationConstraints(event, source)\n        : activationConstraints;\n\n    return constraints;\n  }\n\n  public bind(source: Draggable, options = this.options) {\n    const unbind = effect(() => {\n      const controller = new AbortController();\n      const {signal} = controller;\n      const listener: EventListener = (event: Event) => {\n        if (isPointerEvent(event)) {\n          this.handlePointerDown(event, source, options);\n        }\n      };\n      let targets = [source.handle ?? source.element];\n\n      if (options?.activatorElements) {\n        if (Array.isArray(options.activatorElements)) {\n          targets = options.activatorElements;\n        } else {\n          targets = options.activatorElements(source);\n        }\n      }\n\n      for (const target of targets) {\n        if (!target) continue;\n\n        patchWindow(target.ownerDocument.defaultView);\n        target.addEventListener('pointerdown', listener, {signal});\n      }\n\n      return () => controller.abort();\n    });\n\n    return unbind;\n  }\n\n  protected handlePointerDown(\n    event: PointerEvent,\n    source: Draggable,\n    options: PointerSensorOptions | undefined\n  ) {\n    if (\n      this.disabled ||\n      !event.isPrimary ||\n      event.button !== 0 ||\n      !isElement(event.target) ||\n      source.disabled ||\n      isCapturedBySensor(event) ||\n      !this.manager.dragOperation.status.idle\n    ) {\n      return;\n    }\n\n    const {preventActivation = defaults.preventActivation} = options ?? {};\n\n    if (preventActivation?.(event, source)) {\n      return;\n    }\n\n    const {target} = event;\n    const isNativeDraggable =\n      isHTMLElement(target) &&\n      target.draggable &&\n      target.getAttribute('draggable') === 'true';\n\n    const offset = getFrameTransform(source.element);\n    const {x, y} = getEventCoordinates(event);\n\n    this.initialCoordinates = {\n      x: x * offset.scaleX + offset.x,\n      y: y * offset.scaleY + offset.y,\n    };\n\n    const constraints = this.activationConstraints(event, source, options);\n    (event as any).sensor = this;\n\n    const controller = new ActivationController<PointerEvent>(\n      constraints,\n      (event) => this.handleStart(source, event)\n    );\n\n    controller.signal.onabort = () => this.handleCancel(event);\n    controller.onEvent(event);\n\n    this.controller = controller;\n\n    const documents = getDocuments();\n    const unbindListeners = this.listeners.bind(documents, [\n      {\n        type: 'pointermove',\n        listener: (event: PointerEvent) =>\n          this.handlePointerMove(event, source),\n      },\n      {\n        type: 'pointerup',\n        listener: this.handlePointerUp,\n        options: {\n          capture: true,\n        },\n      },\n      {                                                                     \n        type: 'pointercancel',                 \n        listener: this.handleCancel,                                        \n      },   \n      {\n        // Cancel activation if there is a competing Drag and Drop interaction\n        type: 'dragstart',\n        listener: isNativeDraggable ? this.handleCancel : preventDefault,\n        options: {\n          capture: true,\n        },\n      },\n    ]);\n\n    const cleanup = () => {\n      unbindListeners();\n      this.initialCoordinates = undefined;\n    };\n\n    this.#cleanup.add(cleanup);\n  }\n\n  private latest: LatestState = {\n    event: undefined,\n    coordinates: undefined,\n  };\n\n  protected handleMove = () => {\n    const {event, coordinates: to} = this.latest;\n\n    if (!event || !to) {\n      return;\n    }\n\n    this.manager.actions.move({event, to});\n  };\n\n  protected handlePointerMove(event: PointerEvent, source: Draggable) {\n    if (this.controller?.activated === false) {\n      this.controller?.onEvent(event);\n      return;\n    }\n\n    if (this.manager.dragOperation.status.dragging) {\n      const coordinates = getEventCoordinates(event);\n      const offset = getFrameTransform(source.element);\n\n      coordinates.x = coordinates.x * offset.scaleX + offset.x;\n      coordinates.y = coordinates.y * offset.scaleY + offset.y;\n\n      event.preventDefault();\n      event.stopPropagation();\n\n      this.latest.event = event;\n      this.latest.coordinates = coordinates;\n\n      scheduler.schedule(this.handleMove);\n    }\n  }\n\n  private handlePointerUp(event: PointerEvent) {\n    // End the drag and drop operation\n    const {status} = this.manager.dragOperation;\n\n    if (!status.idle) {\n      // Prevent the default behaviour of the event\n      event.preventDefault();\n      event.stopPropagation();\n\n      const canceled = !status.initialized;\n      this.manager.actions.stop({event, canceled});\n    }\n\n    this.cleanup();\n  }\n\n  protected handleKeyDown(event: KeyboardEvent) {\n    if (event.key === 'Escape') {\n      event.preventDefault();\n      this.handleCancel(event);\n    }\n  }\n\n  protected handleStart(source: Draggable, event: PointerEvent) {\n    const {manager, initialCoordinates} = this;\n\n    if (!initialCoordinates || !manager.dragOperation.status.idle) {\n      return;\n    }\n\n    if (event.defaultPrevented) {\n      return;\n    }\n\n    const controller = manager.actions.start({\n      coordinates: initialCoordinates,\n      event,\n      source,\n    });\n\n    if (controller.signal.aborted) return this.cleanup();\n\n    event.preventDefault();\n\n    const ownerDocument = getDocument(event.target);\n    const pointerCaptureTarget = ownerDocument.body;\n\n    try {\n      pointerCaptureTarget.setPointerCapture(event.pointerId);\n    } catch {\n      this.handleCancel(event);\n      return;\n    }\n\n    const listenerTargets = isElement(event.target)\n      ? [event.target, pointerCaptureTarget]\n      : pointerCaptureTarget;\n\n    const unbind = this.listeners.bind(listenerTargets, [\n      {\n        // Prevent scrolling on touch devices\n        type: 'touchmove',\n        listener: preventDefault,\n        options: {\n          passive: false,\n        },\n      },\n      {\n        // Prevent click events\n        type: 'click',\n        listener: preventDefault,\n      },\n      {\n        type: 'contextmenu',\n        listener: preventDefault,\n      },\n      {\n        type: 'keydown',\n        listener: this.handleKeyDown,\n      },\n    ]);\n\n    this.#cleanup.add(unbind);\n  }\n\n  protected handleCancel(event: Event) {\n    const {dragOperation} = this.manager;\n\n    if (dragOperation.status.initialized) {\n      this.manager.actions.stop({event, canceled: true});\n    }\n\n    this.cleanup();\n  }\n\n  protected cleanup() {\n    const {controller} = this;\n    this.controller = undefined;\n\n    if (controller && !controller.signal.aborted) {\n      controller.abort();\n    }\n\n    this.latest = {\n      event: undefined,\n      coordinates: undefined,\n    };\n    this.#cleanup.forEach((cleanup) => cleanup());\n    this.#cleanup.clear();\n  }\n\n  public destroy() {\n    this.cleanup();\n    this.listeners.clear();\n  }\n\n  static configure = configurator(PointerSensor);\n\n  static defaults = defaults;\n}\n\nfunction isCapturedBySensor(event: Event) {\n  return 'sensor' in event;\n}\n\nfunction preventDefault(event: Event) {\n  event.preventDefault();\n}\n\nfunction noop() {}\n\nconst windows = new WeakSet<Window>();\n\nfunction patchWindow(window: Window | null) {\n  if (!window || windows.has(window)) {\n    return;\n  }\n\n  window.addEventListener('touchmove', noop, {\n    capture: false,\n    passive: false,\n  });\n  windows.add(window);\n}\n"
  },
  {
    "path": "packages/dom/src/core/sensors/types.ts",
    "content": "import type {Sensors as AbstractSensors} from '@dnd-kit/abstract';\n\nimport type {DragDropManager} from '../manager/index.ts';\n\nexport type Sensors = AbstractSensors<DragDropManager>;\n"
  },
  {
    "path": "packages/dom/src/modifiers/RestrictToElement.ts",
    "content": "import {Modifier, configurator} from '@dnd-kit/abstract';\nimport {restrictShapeToBoundingRectangle} from '@dnd-kit/abstract/modifiers';\nimport {BoundingRectangle, Rectangle} from '@dnd-kit/geometry';\nimport {effect, signal} from '@dnd-kit/state';\nimport type {DragDropManager} from '@dnd-kit/dom';\nimport {getBoundingRectangle} from '@dnd-kit/dom/utilities';\n\ninterface Options {\n  element?:\n    | Element\n    | null\n    | ((operation: DragDropManager['dragOperation']) => Element | null);\n}\n\nexport class RestrictToElement extends Modifier<DragDropManager, Options> {\n  private boundingRectangle = signal<BoundingRectangle | null>(null);\n\n  constructor(manager: DragDropManager, options?: Options) {\n    super(manager, options);\n\n    this.destroy = effect(() => {\n      if (!this.options) {\n        return;\n      }\n\n      const {dragOperation} = manager;\n      const {status} = dragOperation;\n\n      if (status.initialized) {\n        const {element} = this.options;\n        const target =\n          typeof element === 'function' ? element(dragOperation) : element;\n\n        if (!target) {\n          return;\n        }\n\n        let timeout: NodeJS.Timeout | undefined;\n        const updateBoundingRectangle = () => {\n          this.boundingRectangle.value = getBoundingRectangle(target);\n        };\n        const handleScroll = () => {\n          if (timeout) {\n            return;\n          }\n\n          timeout = setTimeout(() => {\n            updateBoundingRectangle();\n            timeout = undefined;\n          }, 25);\n        };\n        const resizeObserver = new ResizeObserver(updateBoundingRectangle);\n\n        resizeObserver.observe(target);\n\n        document.addEventListener('scroll', handleScroll, {\n          passive: true,\n          capture: true,\n        });\n\n        return () => {\n          document.removeEventListener('scroll', handleScroll, {\n            capture: true,\n          });\n          resizeObserver.disconnect();\n          this.boundingRectangle.value = null;\n        };\n      }\n    });\n  }\n\n  apply(operation: DragDropManager['dragOperation']) {\n    const {shape, transform} = operation;\n\n    if (!shape) {\n      return transform;\n    }\n\n    const boundingRectangle = this.boundingRectangle.value;\n\n    if (!boundingRectangle) {\n      return transform;\n    }\n\n    const {initial, current} = shape;\n    const {height, width} = current.boundingRectangle;\n    const left = initial.center.x - width / 2;\n    const top = initial.center.y - height / 2;\n\n    const restrictedTransform = restrictShapeToBoundingRectangle(\n      new Rectangle(left, top, width, height),\n      transform,\n      boundingRectangle\n    );\n\n    return restrictedTransform;\n  }\n\n  static configure = configurator(RestrictToElement);\n}\n"
  },
  {
    "path": "packages/dom/src/modifiers/RestrictToWindow.ts",
    "content": "import {effect, untracked} from '@dnd-kit/state';\nimport {Modifier, type DragOperation} from '@dnd-kit/abstract';\nimport {restrictShapeToBoundingRectangle} from '@dnd-kit/abstract/modifiers';\nimport {Rectangle, type BoundingRectangle} from '@dnd-kit/geometry';\nimport type {DragDropManager} from '@dnd-kit/dom';\nimport {getViewportBoundingRectangle} from '@dnd-kit/dom/utilities';\n\nexport class RestrictToWindow extends Modifier<DragDropManager> {\n  constructor(manager: DragDropManager) {\n    super(manager);\n\n    const {dragOperation} = manager;\n\n    const getWindowBoundingRectangle = () =>\n      untracked(() => {\n        const {source} = dragOperation;\n        this.windowBoundingRectangle = getViewportBoundingRectangle(\n          source?.element ?? document.documentElement\n        );\n      });\n\n    this.destroy = effect(() => {\n      if (dragOperation.status.idle) {\n        return;\n      }\n\n      getWindowBoundingRectangle();\n\n      window.addEventListener('resize', getWindowBoundingRectangle);\n\n      return () => {\n        window.removeEventListener('resize', getWindowBoundingRectangle);\n      };\n    });\n  }\n\n  windowBoundingRectangle: BoundingRectangle | undefined;\n\n  apply({shape, transform}: DragOperation) {\n    if (!this.windowBoundingRectangle || !shape) {\n      return transform;\n    }\n\n    const {initial, current} = shape;\n    const {height, width} = current.boundingRectangle;\n    const left = initial.center.x - width / 2;\n    const top = initial.center.y - height / 2;\n\n    const restrictedTransform = restrictShapeToBoundingRectangle(\n      new Rectangle(left, top, width, height),\n      transform,\n      this.windowBoundingRectangle\n    );\n\n    return restrictedTransform;\n  }\n}\n"
  },
  {
    "path": "packages/dom/src/modifiers/index.ts",
    "content": "export {RestrictToWindow} from './RestrictToWindow.ts';\nexport {RestrictToElement} from './RestrictToElement.ts';\n"
  },
  {
    "path": "packages/dom/src/plugins/debug/debug.ts",
    "content": "import {effects} from '@dnd-kit/state';\nimport {Plugin} from '@dnd-kit/abstract';\nimport type {UniqueIdentifier} from '@dnd-kit/abstract';\nimport type {DragDropManager} from '@dnd-kit/dom';\nimport {showPopover, hidePopover, getFixedPositionOffset} from '@dnd-kit/dom/utilities';\n\nexport class Debug extends Plugin<DragDropManager> {\n  constructor(manager: DragDropManager) {\n    super(manager);\n\n    const elements = new Map<UniqueIdentifier, HTMLElement>();\n    let draggableElement: HTMLElement | null = null;\n    let positionElement: HTMLElement | null = null;\n\n    const cleanup = effects(() => {\n      const {dragOperation} = manager;\n      const {x, y} = dragOperation.position.current;\n      const {current: _, idle} = dragOperation.status;\n      const {collisions} = manager.collisionObserver;\n      const draggable = dragOperation.source;\n      const topCollisions = collisions.slice(1, 3);\n      const collidingIds = topCollisions.map(({id}) => id);\n\n      if (draggable && dragOperation.shape) {\n        const element = draggableElement ?? createDebugElement();\n        const {boundingRectangle} = dragOperation.shape.current;\n\n        if (!draggableElement) {\n          draggableElement = element;\n\n          const style = document.createElement('style');\n          style.textContent = `dialog[data-dnd-kit-debug]::backdrop {display: none;}`;\n\n          element.textContent = `${draggable.id}`;\n          element.setAttribute('data-dnd-kit-debug', '');\n          element.appendChild(style);\n          element.style.backgroundColor = 'rgba(118, 190, 250, 0.5)';\n          element.style.color = 'rgba(0,0,0,0.9)';\n\n          document.body.appendChild(element);\n        }\n\n        const draggableOffset = getFixedPositionOffset();\n        element.style.top = `${boundingRectangle.top + draggableOffset.y}px`;\n        element.style.left = `${boundingRectangle.left + draggableOffset.x}px`;\n        element.style.width = `${boundingRectangle.width}px`;\n        element.style.height = `${boundingRectangle.height}px`;\n\n        hidePopover(element);\n        showPopover(element);\n      } else {\n        draggableElement?.remove();\n        draggableElement = null;\n      }\n\n      for (const [id, element] of elements) {\n        if (!manager.registry.droppables.has(id)) {\n          element.remove();\n          elements.delete(id);\n        }\n      }\n\n      for (const droppable of manager.registry.droppables) {\n        const element = elements.get(droppable.id);\n\n        if (droppable.shape) {\n          const {boundingRectangle} = droppable.shape;\n          const debugElement = element ?? createDebugElement();\n\n          if (!element) {\n            elements.set(droppable.id, debugElement);\n            document.body.appendChild(debugElement);\n          }\n\n          debugElement.style.backgroundColor = droppable.isDropTarget\n            ? 'rgba(13, 210, 36, 0.6)'\n            : collidingIds.includes(droppable.id)\n              ? 'rgba(255, 193, 7, 0.5)'\n              : 'rgba(0, 0, 0, 0.1)';\n\n          const droppableOffset = getFixedPositionOffset();\n          debugElement.style.top = `${boundingRectangle.top + droppableOffset.y}px`;\n          debugElement.style.left = `${boundingRectangle.left + droppableOffset.x}px`;\n          debugElement.style.width = `${boundingRectangle.width}px`;\n          debugElement.style.height = `${boundingRectangle.height}px`;\n          debugElement.textContent = `${droppable.id}`;\n        } else if (element) {\n          element.remove();\n          elements.delete(droppable.id);\n        }\n      }\n\n      if (!idle) {\n        if (!positionElement) {\n          positionElement = createDebugElement();\n\n          const horizontal = document.createElement('div');\n          const vertical = document.createElement('div');\n\n          horizontal.style.position = 'absolute';\n          horizontal.style.width = '25px';\n          horizontal.style.height = '1px';\n          horizontal.style.backgroundColor = '#000';\n\n          vertical.style.position = 'absolute';\n          vertical.style.width = '1px';\n          vertical.style.height = '25px';\n          vertical.style.backgroundColor = '#000';\n\n          positionElement.appendChild(horizontal);\n          positionElement.appendChild(vertical);\n          document.body.appendChild(positionElement);\n        }\n\n        const posOffset = getFixedPositionOffset();\n        positionElement.style.top = `${y + posOffset.y}px`;\n        positionElement.style.left = `${x + posOffset.x}px`;\n\n        hidePopover(positionElement);\n        // Only one element can be promoted to the top layer per call stack\n        queueMicrotask(() => positionElement && showPopover(positionElement));\n      } else {\n        positionElement?.remove();\n        positionElement = null;\n      }\n    });\n\n    this.destroy = () => {\n      positionElement?.remove();\n      draggableElement?.remove();\n      elements.forEach((element) => element.remove());\n      cleanup();\n    };\n  }\n}\n\nfunction createDebugElement(tagName = 'div') {\n  const element = document.createElement(tagName);\n\n  element.setAttribute('popover', 'manual');\n  element.style.all = 'initial';\n  element.style.position = 'fixed';\n  element.style.display = 'flex';\n  element.style.alignItems = 'center';\n  element.style.justifyContent = 'center';\n  element.style.border = '1px solid rgba(0, 0, 0, 0.1)';\n  element.style.boxSizing = 'border-box';\n  element.style.pointerEvents = 'none';\n  element.style.zIndex = 'calc(infinity)';\n  element.style.color = 'rgba(0,0,0,0.5)';\n  element.style.fontFamily = 'sans-serif';\n  element.style.textShadow = '0 0 3px rgba(255,255,255,0.8)';\n  element.style.pointerEvents = 'none';\n\n  return element;\n}\n"
  },
  {
    "path": "packages/dom/src/plugins/debug/index.ts",
    "content": "export {Debug} from './debug.ts';\n"
  },
  {
    "path": "packages/dom/src/sortable/index.ts",
    "content": "export {\n  Sortable,\n  defaultSortableTransition,\n  SortableDraggable,\n  SortableDroppable,\n} from './sortable.ts';\nexport type {SortableInput, SortableTransition} from './sortable.ts';\nexport {isSortable, isSortableOperation} from './utilities.ts';\nexport {OptimisticSortingPlugin} from './plugins/OptimisticSortingPlugin.ts';\nexport {SortableKeyboardPlugin} from './plugins/SortableKeyboardPlugin.ts';\n"
  },
  {
    "path": "packages/dom/src/sortable/plugins/OptimisticSortingPlugin.ts",
    "content": "import {Plugin, type UniqueIdentifier} from '@dnd-kit/abstract';\nimport type {DragDropManager} from '@dnd-kit/dom';\nimport {move} from '@dnd-kit/helpers';\nimport {batch} from '@dnd-kit/state';\n\nimport {Sortable, SortableDroppable} from '../sortable.ts';\nimport {isSortable} from '../utilities.ts';\n\nconst defaultGroup = '__default__';\n\nexport class OptimisticSortingPlugin extends Plugin<DragDropManager> {\n  constructor(manager: DragDropManager) {\n    super(manager);\n\n    const getSortableInstances = () => {\n      const sortableInstances = new Map<\n        UniqueIdentifier | undefined,\n        Set<Sortable>\n      >();\n\n      for (const droppable of manager.registry.droppables) {\n        if (droppable instanceof SortableDroppable) {\n          const {sortable} = droppable;\n          const {group} = sortable;\n\n          let instances = sortableInstances.get(group);\n\n          if (!instances) {\n            instances = new Set();\n            sortableInstances.set(group, instances);\n          }\n\n          instances.add(sortable);\n        }\n      }\n\n      for (const [group, instances] of sortableInstances) {\n        sortableInstances.set(group, new Set(sort(instances)));\n      }\n\n      return sortableInstances;\n    };\n\n    const unsubscribe = [\n      manager.monitor.addEventListener('dragover', (event, manager) => {\n        if (this.disabled) {\n          return;\n        }\n\n        const {dragOperation} = manager;\n        const {source, target} = dragOperation;\n\n        if (!isSortable(source) || !isSortable(target)) {\n          return;\n        }\n\n        if (source.sortable === target.sortable) {\n          return;\n        }\n\n        const instances = getSortableInstances();\n        const sameGroup = source.sortable.group === target.sortable.group;\n        const sourceInstances = instances.get(source.sortable.group);\n        const targetInstances = sameGroup\n          ? sourceInstances\n          : instances.get(target.sortable.group);\n\n        if (!sourceInstances || !targetInstances) return;\n\n        queueMicrotask(() => {\n          if (event.defaultPrevented) return;\n\n          // Wait for the renderer to handle the event before attempting to optimistically update\n          manager.renderer.rendering.then(() => {\n            const newInstances = getSortableInstances();\n\n            for (const [group, sortableInstances] of instances.entries()) {\n              const entries = Array.from(sortableInstances).entries();\n\n              for (const [index, sortable] of entries) {\n                if (\n                  sortable.index !== index ||\n                  sortable.group !== group ||\n                  !newInstances.get(group)?.has(sortable)\n                ) {\n                  // At least one index or group was changed so we should abort optimistic updates\n                  return;\n                }\n              }\n            }\n\n            const sourceElement = source.sortable.element;\n            const targetElement = target.sortable.element;\n\n            if (!targetElement || !sourceElement) {\n              return;\n            }\n\n            if (!sameGroup && target.id === source.sortable.group) {\n              return;\n            }\n\n            const orderedSourceSortables = sort(sourceInstances);\n            const orderedTargetSortables = sameGroup\n              ? orderedSourceSortables\n              : sort(targetInstances);\n            const sourceGroup = source.sortable.group ?? defaultGroup;\n            const targetGroup = target.sortable.group ?? defaultGroup;\n            const state = {\n              [sourceGroup]: orderedSourceSortables,\n              [targetGroup]: orderedTargetSortables,\n            };\n            const newState = move(state, event);\n\n            if (state === newState) return;\n\n            const sourceIndex = newState[targetGroup].indexOf(source.sortable);\n            const targetIndex = newState[targetGroup].indexOf(target.sortable);\n\n            manager.collisionObserver.disable();\n\n            reorder(sourceElement, sourceIndex, targetElement, targetIndex);\n\n            batch(() => {\n              for (const [index, sortable] of newState[sourceGroup].entries()) {\n                sortable.index = index;\n              }\n\n              if (!sameGroup) {\n                for (const [index, sortable] of newState[\n                  targetGroup\n                ].entries()) {\n                  sortable.group = target.sortable.group;\n                  sortable.index = index;\n                }\n              }\n            });\n\n            manager.actions\n              .setDropTarget(source.id)\n              .then(() => manager.collisionObserver.enable());\n          });\n        });\n      }),\n      manager.monitor.addEventListener('dragend', (event, manager) => {\n        if (!event.canceled) {\n          return;\n        }\n\n        const {dragOperation} = manager;\n        const {source} = dragOperation;\n\n        if (!isSortable(source)) {\n          return;\n        }\n\n        if (\n          source.sortable.initialIndex === source.sortable.index &&\n          source.sortable.initialGroup === source.sortable.group\n        ) {\n          return;\n        }\n\n        queueMicrotask(() => {\n          const instances = getSortableInstances();\n          const initialGroupInstances = instances.get(\n            source.sortable.initialGroup\n          );\n\n          if (!initialGroupInstances) return;\n\n          // Wait for the renderer to handle the event before attempting to optimistically update\n          manager.renderer.rendering.then(() => {\n            for (const [group, sortableInstances] of instances.entries()) {\n              const entries = Array.from(sortableInstances).entries();\n\n              for (const [index, sortable] of entries) {\n                if (sortable.index !== index || sortable.group !== group) {\n                  // At least one index or group was changed so we should abort optimistic updates\n                  return;\n                }\n              }\n            }\n\n            const initialGroup = sort(initialGroupInstances);\n            const sourceElement = source.sortable.element;\n            const target = initialGroup[source.sortable.initialIndex];\n            const targetElement = target?.element;\n\n            if (!target || !targetElement || !sourceElement) {\n              return;\n            }\n\n            reorder(sourceElement, target.index, targetElement, source.index);\n\n            batch(() => {\n              for (const [_, sortableInstances] of instances.entries()) {\n                const entries = Array.from(sortableInstances).values();\n\n                for (const sortable of entries) {\n                  sortable.index = sortable.initialIndex;\n                  sortable.group = sortable.initialGroup;\n                }\n              }\n            });\n          });\n        });\n      }),\n    ];\n\n    this.destroy = () => {\n      for (const unsubscribeListener of unsubscribe) {\n        unsubscribeListener();\n      }\n    };\n  }\n}\n\nfunction reorder(\n  sourceElement: Element,\n  sourceIndex: number,\n  targetElement: Element,\n  targetIndex: number\n) {\n  const position = targetIndex < sourceIndex ? 'afterend' : 'beforebegin';\n\n  targetElement.insertAdjacentElement(position, sourceElement);\n}\n\nfunction sortByIndex(a: Sortable, b: Sortable) {\n  return a.index - b.index;\n}\n\nfunction sort(instances: Set<Sortable>) {\n  return Array.from(instances).sort(sortByIndex);\n}\n"
  },
  {
    "path": "packages/dom/src/sortable/plugins/SortableKeyboardPlugin.ts",
    "content": "import {batch, CleanupFunction, effect} from '@dnd-kit/state';\nimport {Plugin} from '@dnd-kit/abstract';\nimport {closestCorners} from '@dnd-kit/collision';\nimport {\n  DOMRectangle,\n  getVisibleBoundingRectangle,\n  isKeyboardEvent,\n  scrollIntoViewIfNeeded,\n} from '@dnd-kit/dom/utilities';\nimport {Rectangle, type Coordinates} from '@dnd-kit/geometry';\nimport {Scroller} from '@dnd-kit/dom';\nimport type {DragDropManager, Droppable} from '@dnd-kit/dom';\n\nimport {isSortable} from '../utilities.ts';\n\nconst TOLERANCE = 10;\n\nexport class SortableKeyboardPlugin extends Plugin<DragDropManager> {\n  constructor(manager: DragDropManager) {\n    super(manager);\n\n    const cleanupEffect = effect(() => {\n      const {dragOperation} = manager;\n\n      if (!isKeyboardEvent(dragOperation.activatorEvent)) {\n        return;\n      }\n\n      if (!isSortable(dragOperation.source)) {\n        return;\n      }\n\n      if (dragOperation.status.initialized) {\n        const scroller = manager.registry.plugins.get(Scroller);\n\n        if (scroller) {\n          scroller.disable();\n\n          return () => scroller.enable();\n        }\n      }\n    });\n\n    const unsubscribe = manager.monitor.addEventListener(\n      'dragmove',\n      (event, manager: DragDropManager) => {\n        queueMicrotask(() => {\n          if (this.disabled || event.defaultPrevented || !event.nativeEvent) {\n            return;\n          }\n\n          const {dragOperation} = manager;\n\n          if (!isKeyboardEvent(event.nativeEvent)) {\n            return;\n          }\n\n          if (!isSortable(dragOperation.source)) {\n            return;\n          }\n\n          if (!dragOperation.shape) {\n            return;\n          }\n\n          const {actions, collisionObserver, registry} = manager;\n          const {by} = event;\n\n          if (!by) {\n            return;\n          }\n\n          const direction = getDirection(by);\n          const {source, target} = dragOperation;\n          const {center} = dragOperation.shape.current;\n          const potentialTargets: Droppable[] = [];\n          const cleanup: CleanupFunction[] = [];\n\n          batch(() => {\n            for (const droppable of registry.droppables) {\n              const {id} = droppable;\n\n              if (\n                !droppable.accepts(source) ||\n                (id === target?.id && isSortable(droppable)) ||\n                !droppable.element\n              ) {\n                continue;\n              }\n\n              let previousShape = droppable.shape;\n              const shape = new DOMRectangle(droppable.element, {\n                getBoundingClientRect: (element) =>\n                  getVisibleBoundingRectangle(element, undefined, 0.2),\n              });\n\n              if (!shape.height || !shape.width) continue;\n\n              if (\n                (direction == 'down' &&\n                  center.y + TOLERANCE < shape.center.y) ||\n                (direction == 'up' && center.y - TOLERANCE > shape.center.y) ||\n                (direction == 'left' &&\n                  center.x - TOLERANCE > shape.center.x) ||\n                (direction == 'right' && center.x + TOLERANCE < shape.center.x)\n              ) {\n                potentialTargets.push(droppable);\n                droppable.shape = shape;\n                cleanup.push(() => (droppable.shape = previousShape));\n              }\n            }\n          });\n\n          event.preventDefault();\n          collisionObserver.disable();\n\n          const collisions = collisionObserver.computeCollisions(\n            potentialTargets,\n            closestCorners\n          );\n          batch(() => cleanup.forEach((clean) => clean()));\n\n          const [firstCollision] = collisions;\n\n          if (!firstCollision) {\n            return;\n          }\n\n          const {id} = firstCollision;\n          const {index, group} = source.sortable;\n\n          actions.setDropTarget(id).then(() => {\n            // Wait until optimistic sorting has a chance to update the DOM\n            const {source, target, shape} = dragOperation;\n\n            if (!source || !isSortable(source) || !shape) {\n              return;\n            }\n\n            const {\n              index: newIndex,\n              group: newGroup,\n              target: targetElement,\n            } = source.sortable;\n            const updated = index !== newIndex || group !== newGroup;\n\n            const element = updated ? targetElement : target?.element;\n\n            if (!element) return;\n\n            scrollIntoViewIfNeeded(element);\n            const updatedShape = new DOMRectangle(element);\n\n            if (!updatedShape) {\n              return;\n            }\n\n            const delta = Rectangle.delta(\n              updatedShape,\n              Rectangle.from(shape.current.boundingRectangle),\n              source.alignment\n            );\n\n            actions.move({\n              by: delta,\n            });\n\n            if (updated) {\n              actions\n                .setDropTarget(source.id)\n                .then(() => collisionObserver.enable());\n            } else {\n              collisionObserver.enable();\n            }\n          });\n        });\n      }\n    );\n\n    this.destroy = () => {\n      unsubscribe();\n      cleanupEffect();\n    };\n  }\n}\n\nfunction getDirection(delta: Coordinates) {\n  const {x, y} = delta;\n\n  if (x > 0) {\n    return 'right';\n  } else if (x < 0) {\n    return 'left';\n  } else if (y > 0) {\n    return 'down';\n  } else if (y < 0) {\n    return 'up';\n  }\n}\n"
  },
  {
    "path": "packages/dom/src/sortable/sortable.ts",
    "content": "import {batch, reactive, untracked, WeakStore} from '@dnd-kit/state';\nimport type {CollisionPriority, Modifiers, Plugins} from '@dnd-kit/abstract';\nimport type {\n  Data,\n  PluginConstructor,\n  Type,\n  UniqueIdentifier,\n} from '@dnd-kit/abstract';\nimport {\n  defaultCollisionDetection,\n  type CollisionDetector,\n} from '@dnd-kit/collision';\nimport type {Alignment} from '@dnd-kit/geometry';\nimport {Draggable, Droppable, Feedback} from '@dnd-kit/dom';\nimport type {\n  DraggableInput,\n  DroppableInput,\n  Sensors,\n  DragDropManager,\n} from '@dnd-kit/dom';\nimport {\n  animateTransform,\n  getComputedStyles,\n  getWindow,\n  computeTranslate,\n  prefersReducedMotion,\n  ProxiedElements,\n} from '@dnd-kit/dom/utilities';\n\nimport {SortableKeyboardPlugin} from './plugins/SortableKeyboardPlugin.ts';\nimport {OptimisticSortingPlugin} from './plugins/OptimisticSortingPlugin.ts';\n\nexport interface SortableTransition {\n  /**\n   * The duration of the transition in milliseconds.\n   * @default 300\n   */\n  duration?: number;\n  /**\n   * The easing function to use for the transition.\n   * @default 'cubic-bezier(0.25, 1, 0.5, 1)'\n   */\n  easing?: string;\n  /**\n   * Whether the sortable item should transition when its index changes,\n   * but there is no drag operation in progress.\n   * @default false\n   **/\n  idle?: boolean;\n}\n\nconst defaultPlugins: PluginConstructor[] = [\n  SortableKeyboardPlugin,\n  OptimisticSortingPlugin,\n];\n\nexport interface SortableInput<T extends Data>\n  extends DraggableInput<T>,\n    DroppableInput<T> {\n  /**\n   * The index of the sortable item within its group.\n   */\n  index: number;\n\n  /**\n   * The element that should be used as the droppable target for this sortable item.\n   */\n  target?: Element;\n\n  /**\n   * The optional unique identifier of the group that the sortable item belongs to.\n   */\n  group?: UniqueIdentifier;\n  /**\n   * The transition configuration to use when the index of the sortable item changes.\n   */\n  transition?: SortableTransition | null;\n  /**\n   * Plugins to register or configure per-entity.\n   *\n   * Bare constructors are registered globally (e.g. sortable-specific plugins).\n   * Descriptors from `Plugin.configure()` are applied as per-entity plugin config.\n   *\n   * @default [SortableKeyboardPlugin, OptimisticSortingPlugin]\n   */\n  plugins?: Plugins;\n}\n\nexport const defaultSortableTransition: SortableTransition = {\n  duration: 250,\n  easing: 'cubic-bezier(0.25, 1, 0.5, 1)',\n  idle: false,\n};\n\ninterface TemporaryState {\n  initialIndex: number;\n  initialGroup: UniqueIdentifier | undefined;\n}\n\nconst store = new WeakStore<\n  DragDropManager,\n  UniqueIdentifier,\n  TemporaryState\n>();\n\nexport class Sortable<T extends Data = Data> {\n  public draggable: Draggable<T>;\n  public droppable: Droppable<T>;\n\n  @reactive\n  public accessor index: number;\n\n  #previousGroup: UniqueIdentifier | undefined;\n\n  #previousIndex: number;\n\n  get initialIndex() {\n    return store.get(this.manager, this.id)?.initialIndex ?? this.index;\n  }\n\n  get initialGroup() {\n    return store.get(this.manager, this.id)?.initialGroup ?? this.group;\n  }\n\n  @reactive\n  public accessor group: UniqueIdentifier | undefined;\n\n  transition: SortableTransition | null;\n\n  constructor(\n    {\n      effects: inputEffects = () => [],\n      group,\n      index,\n      sensors,\n      type,\n      transition = defaultSortableTransition,\n      plugins = defaultPlugins,\n      ...input\n    }: SortableInput<T>,\n    manager: DragDropManager<any, any> | undefined\n  ) {\n    this.droppable = new SortableDroppable<T>(input, manager, this);\n    this.draggable = new SortableDraggable<T>(\n      {\n        ...input,\n        plugins,\n        effects: () => [\n          () => {\n            const status = this.manager?.dragOperation.status;\n\n            if (\n              status?.initializing &&\n              this.id === this.manager?.dragOperation.source?.id\n            ) {\n              store.clear(this.manager);\n            }\n\n            if (status?.dragging) {\n              store.set(\n                this.manager,\n                this.id,\n                untracked(() => ({\n                  initialIndex: this.index,\n                  initialGroup: this.group,\n                }))\n              );\n            }\n          },\n          () => {\n            const {index, group, manager: _} = this;\n            const previousIndex = this.#previousIndex;\n            const previousGroup = this.#previousGroup;\n\n            // Re-run this effect whenever the index changes\n            if (index !== previousIndex || group !== previousGroup) {\n              this.#previousIndex = index;\n              this.#previousGroup = group;\n\n              this.animate();\n            }\n          },\n          () => {\n            const {target} = this;\n            const {isDragSource} = this.draggable;\n            const feedback =\n              this.draggable.pluginConfig(Feedback)?.feedback ?? 'default';\n\n            if (feedback === 'move' && isDragSource) {\n              this.droppable.disabled = !target;\n            }\n          },\n          ...inputEffects(),\n        ],\n        type,\n        sensors,\n      },\n      manager,\n      this\n    );\n\n    this.#element = input.element;\n    this.manager = manager;\n    this.index = index;\n    this.#previousIndex = index;\n    this.group = group;\n    this.#previousGroup = group;\n    this.type = type;\n    this.transition = transition;\n  }\n\n  protected animate() {\n    untracked(() => {\n      const {manager, transition} = this;\n      const {shape} = this.droppable;\n\n      if (!manager) return;\n\n      const {idle} = manager.dragOperation.status;\n\n      if (!shape || !transition || (idle && !transition.idle)) {\n        return;\n      }\n\n      manager.renderer.rendering.then(() => {\n        const {element} = this;\n\n        if (!element) {\n          return;\n        }\n\n        // Cancel CSS transitions on transform-related properties before measuring.\n        // These transitions (e.g. `transition: transform` from user CSS) would cause\n        // getBoundingClientRect() to return the mid-transition position rather than\n        // the element's final resting position, resulting in an incorrect delta.\n        for (const animation of element.getAnimations()) {\n          if (\n            'transitionProperty' in animation &&\n            (animation.transitionProperty === 'transform' ||\n              animation.transitionProperty === 'translate' ||\n              animation.transitionProperty === 'scale')\n          ) {\n            animation.cancel();\n          }\n        }\n\n        const updatedShape = this.refreshShape();\n\n        if (!updatedShape) {\n          return;\n        }\n\n        const delta = {\n          x: shape.boundingRectangle.left - updatedShape.boundingRectangle.left,\n          y: shape.boundingRectangle.top - updatedShape.boundingRectangle.top,\n        };\n\n        const {translate} = getComputedStyles(element);\n        const currentTranslate = computeTranslate(element, translate, false);\n        const finalTranslate = computeTranslate(element, translate);\n\n        if (delta.x || delta.y) {\n          const resolvedTransition = prefersReducedMotion(getWindow(element))\n            ? {...transition, duration: 0}\n            : transition;\n\n          animateTransform({\n            element,\n            keyframes: {\n              translate: [\n                `${currentTranslate.x + delta.x}px ${currentTranslate.y + delta.y}px ${currentTranslate.z}`,\n                `${finalTranslate.x}px ${finalTranslate.y}px ${finalTranslate.z}`,\n              ],\n            },\n            options: resolvedTransition,\n          }).then(() => {\n            if (!manager.dragOperation.status.dragging) {\n              this.droppable.shape = undefined;\n            }\n          });\n        }\n      });\n    });\n  }\n\n  public get manager(): DragDropManager<any, any> | undefined {\n    return this.draggable.manager as any;\n  }\n\n  public set manager(manager: DragDropManager<any, any> | undefined) {\n    batch(() => {\n      this.draggable.manager = manager as any;\n      this.droppable.manager = manager as any;\n    });\n  }\n\n  #element: Element | undefined;\n\n  public set element(element: Element | undefined) {\n    batch(() => {\n      const previousElement = this.#element;\n      const droppableElement = this.droppable.element;\n      const draggableElement = this.draggable.element;\n\n      if (!droppableElement || droppableElement === previousElement) {\n        this.droppable.element = element;\n      }\n\n      if (!draggableElement || draggableElement === previousElement) {\n        this.draggable.element = element;\n      }\n\n      this.#element = element;\n    });\n  }\n\n  public get element() {\n    const element = this.#element;\n\n    if (!element) return;\n\n    return ProxiedElements.get(element) ?? element ?? this.droppable.element;\n  }\n\n  public set target(target: Element | undefined) {\n    this.droppable.element = target;\n  }\n\n  public get target() {\n    return this.droppable.element;\n  }\n\n  public set source(source: Element | undefined) {\n    this.draggable.element = source;\n  }\n\n  public get source() {\n    return this.draggable.element;\n  }\n\n  public get disabled() {\n    return this.draggable.disabled && this.droppable.disabled;\n  }\n\n  public set plugins(value: Plugins | undefined) {\n    this.draggable.plugins = value;\n  }\n\n  public set disabled(value: boolean) {\n    batch(() => {\n      this.droppable.disabled = value;\n      this.draggable.disabled = value;\n    });\n  }\n\n  public set data(data: T) {\n    batch(() => {\n      this.droppable.data = data;\n      this.draggable.data = data;\n    });\n  }\n\n  public set handle(handle: Element | undefined) {\n    this.draggable.handle = handle;\n  }\n\n  public set id(id: UniqueIdentifier) {\n    this.droppable.id = id;\n    this.draggable.id = id;\n  }\n\n  public get id() {\n    return this.droppable.id;\n  }\n\n  public set sensors(value: Sensors | undefined) {\n    this.draggable.sensors = value;\n  }\n\n  public set modifiers(value: Modifiers | undefined) {\n    this.draggable.modifiers = value;\n  }\n\n  public set collisionPriority(value: CollisionPriority | number | undefined) {\n    this.droppable.collisionPriority = value;\n  }\n\n  public set collisionDetector(value: CollisionDetector | undefined) {\n    this.droppable.collisionDetector = value ?? defaultCollisionDetection;\n  }\n\n  public set alignment(value: Alignment | undefined) {\n    this.draggable.alignment = value;\n  }\n\n  public get alignment() {\n    return this.draggable.alignment;\n  }\n\n  public set type(type: Type | undefined) {\n    batch(() => {\n      this.droppable.type = type;\n      this.draggable.type = type;\n    });\n  }\n\n  public get type() {\n    return this.draggable.type;\n  }\n\n  public set accept(value: Droppable['accept']) {\n    this.droppable.accept = value;\n  }\n\n  public get accept() {\n    return this.droppable.accept;\n  }\n\n  public get isDropTarget() {\n    return this.droppable.isDropTarget;\n  }\n\n  /**\n   * A boolean indicating whether the sortable item is the source of a drag operation.\n   */\n  public get isDragSource() {\n    return this.draggable.isDragSource;\n  }\n\n  /**\n   * A boolean indicating whether the sortable item is being dragged.\n   */\n  public get isDragging() {\n    return this.draggable.isDragging;\n  }\n\n  /**\n   * A boolean indicating whether the sortable item is being dropped.\n   */\n  public get isDropping() {\n    return this.draggable.isDropping;\n  }\n\n  public get status() {\n    return this.draggable.status;\n  }\n\n  public refreshShape() {\n    return this.droppable.refreshShape();\n  }\n\n  public accepts(draggable: Draggable): boolean {\n    return this.droppable.accepts(draggable);\n  }\n\n  public register = () => {\n    batch(() => {\n      this.manager?.registry.register(this.droppable);\n      this.manager?.registry.register(this.draggable);\n    });\n\n    return () => this.unregister();\n  };\n\n  public unregister = () => {\n    batch(() => {\n      this.manager?.registry.unregister(this.droppable);\n      this.manager?.registry.unregister(this.draggable);\n    });\n  };\n\n  public destroy = () => {\n    batch(() => {\n      this.droppable.destroy();\n      this.draggable.destroy();\n    });\n  };\n}\n\nexport class SortableDraggable<T extends Data> extends Draggable<T> {\n  constructor(\n    input: DraggableInput<T>,\n    manager: DragDropManager | undefined,\n    public sortable: Sortable<T>\n  ) {\n    super(input, manager);\n  }\n\n  get index() {\n    return this.sortable.index;\n  }\n\n  get initialIndex() {\n    return this.sortable.initialIndex;\n  }\n\n  get group() {\n    return this.sortable.group;\n  }\n\n  get initialGroup() {\n    return this.sortable.initialGroup;\n  }\n}\n\nexport class SortableDroppable<T extends Data> extends Droppable<T> {\n  constructor(\n    input: DraggableInput<T>,\n    manager: DragDropManager | undefined,\n    public sortable: Sortable<T>\n  ) {\n    super(input, manager);\n  }\n\n  get index() {\n    return this.sortable.index;\n  }\n\n  get group() {\n    return this.sortable.group;\n  }\n}\n"
  },
  {
    "path": "packages/dom/src/sortable/utilities.ts",
    "content": "import type {DragOperation} from '@dnd-kit/abstract';\nimport type {Droppable, Draggable} from '@dnd-kit/dom';\n\nimport {SortableDroppable, SortableDraggable} from './sortable.ts';\n\nexport function isSortable(\n  element: Draggable | Droppable | null\n): element is SortableDroppable<any> | SortableDraggable<any> {\n  return (\n    element instanceof SortableDroppable || element instanceof SortableDraggable\n  );\n}\n\nexport function isSortableOperation(\n  operation: DragOperation<Draggable, Droppable>\n): operation is DragOperation<SortableDraggable<any>, SortableDroppable<any>> {\n  return isSortable(operation.source) && isSortable(operation.target);\n}\n"
  },
  {
    "path": "packages/dom/src/utilities/animations/forceFinishAnimations.ts",
    "content": "import {Scheduler} from '../scheduling/scheduler.ts';\nimport {isKeyframeEffect} from '../type-guards/isKeyframeEffect.ts';\n\nconst scheduler = new Scheduler((callback) => setTimeout(callback, 0));\nconst animations = new Map<Document | Element, Animation[]>();\nconst clear = animations.clear.bind(animations);\n\nfunction getDocumentAnimations(element: Element): Animation[] {\n  const document = element.ownerDocument;\n  let documentAnimations = animations.get(document);\n\n  if (documentAnimations) return documentAnimations;\n\n  documentAnimations = document.getAnimations();\n  animations.set(document, documentAnimations);\n  scheduler.schedule(clear);\n\n  const elementAnimations = documentAnimations.filter(\n    (animation) =>\n      isKeyframeEffect(animation.effect) && animation.effect.target === element\n  );\n\n  animations.set(element, elementAnimations);\n\n  return documentAnimations;\n}\n\n/*\n * Force animations on ancestors of the element into their end state\n * and return a function to reset them back to their current state.\n *\n * This is useful as it allows us to immediately calculate the final position\n * of an element without having to wait for the animations to finish.\n */\nexport function forceFinishAnimations(\n  element: Element,\n  options: {\n    properties: string[];\n    isValidTarget?: (target: Element) => boolean;\n  }\n): (() => void) | undefined {\n  const animations = getDocumentAnimations(element)\n    .filter((animation) => {\n      if (isKeyframeEffect(animation.effect)) {\n        const {target} = animation.effect;\n        const isValidTarget =\n          (target && options.isValidTarget?.(target)) ?? true;\n\n        if (isValidTarget) {\n          return animation.effect.getKeyframes().some((keyframe) => {\n            for (const property of options.properties) {\n              if (keyframe[property]) return true;\n            }\n          });\n        }\n      }\n    })\n    .map((animation) => {\n      const {effect, currentTime} = animation;\n      const duration = effect?.getComputedTiming().duration;\n\n      if (animation.pending || animation.playState === 'finished') return;\n\n      if (\n        typeof duration == 'number' &&\n        typeof currentTime == 'number' &&\n        currentTime < duration\n      ) {\n        animation.currentTime = duration;\n\n        return () => {\n          animation.currentTime = currentTime;\n        };\n      }\n    });\n\n  if (animations.length > 0) {\n    return () => animations.forEach((reset) => reset?.());\n  }\n}\n"
  },
  {
    "path": "packages/dom/src/utilities/animations/getFinalKeyframe.ts",
    "content": "import {isKeyframeEffect} from '../type-guards/isKeyframeEffect.ts';\n\nexport function getFinalKeyframe(\n  element: Element,\n  match: (keyframe: Keyframe) => boolean\n): [Keyframe, Animation] | null {\n  const animations = element.getAnimations();\n  let result: [Keyframe, Animation] | null = null;\n\n  for (const animation of animations) {\n    if (animation.playState !== 'running') continue;\n    const {effect} = animation;\n    const keyframes = isKeyframeEffect(effect) ? effect.getKeyframes() : [];\n    const matchedKeyframes = keyframes.filter(match);\n\n    if (matchedKeyframes.length > 0) {\n      result = [matchedKeyframes[matchedKeyframes.length - 1], animation];\n    }\n  }\n\n  return result;\n}\n"
  },
  {
    "path": "packages/dom/src/utilities/bounding-rectangle/getBoundingRectangle.ts",
    "content": "import {BoundingRectangle} from '@dnd-kit/geometry';\n\nexport function getBoundingRectangle(element: Element): BoundingRectangle {\n  const {width, height, top, left, bottom, right} =\n    element.getBoundingClientRect();\n\n  return {width, height, top, left, bottom, right};\n}\n"
  },
  {
    "path": "packages/dom/src/utilities/bounding-rectangle/getViewportBoundingRectangle.ts",
    "content": "import type {BoundingRectangle} from '@dnd-kit/geometry';\n\nimport {getDocument} from '../execution-context/getDocument.ts';\nimport {getWindow} from '../execution-context/getWindow.ts';\n\n/**\n * Returns the bounding rectangle of the viewport.\n *\n * When the visual viewport is available, uses its dimensions and offset\n * to account for pinch-to-zoom. The returned rectangle is in layout viewport\n * coordinates, consistent with `clientX`/`clientY` and `getBoundingClientRect()`.\n *\n * @param element\n * @returns BoundingRectangle\n */\nexport function getViewportBoundingRectangle(\n  element: Element\n): BoundingRectangle {\n  const {documentElement} = getDocument(element);\n  const vv = getWindow(element).visualViewport;\n  const width = vv?.width ?? documentElement.clientWidth;\n  const height = vv?.height ?? documentElement.clientHeight;\n  const top = vv?.offsetTop ?? 0;\n  const left = vv?.offsetLeft ?? 0;\n\n  return {\n    top,\n    left,\n    right: left + width,\n    bottom: top + height,\n    width,\n    height,\n  };\n}\n"
  },
  {
    "path": "packages/dom/src/utilities/bounding-rectangle/getVisibleBoundingRectangle.ts",
    "content": "import type {BoundingRectangle} from '@dnd-kit/geometry';\n\nimport {isOverflowVisible} from './isOverflowVisible.ts';\n\n/*\n * Get the currently visible bounding rectangle of an element\n * @param element\n * @param boundingClientRect\n * @returns Rect\n */\nexport function getVisibleBoundingRectangle(\n  element: Element,\n  boundingClientRect = element.getBoundingClientRect(),\n  margin = 0\n): BoundingRectangle {\n  // Get the initial bounding client rect of the element\n  let rect: BoundingRectangle = boundingClientRect;\n  const {ownerDocument} = element;\n  const ownerWindow = ownerDocument.defaultView ?? window;\n\n  // Traverse up the DOM tree to clip the rect based on ancestors' bounding rects\n  let ancestor: HTMLElement | null = element.parentElement;\n\n  while (ancestor && ancestor !== ownerDocument.documentElement) {\n    if (!isOverflowVisible(ancestor)) {\n      const ancestorRect = ancestor.getBoundingClientRect();\n\n      const marginTop = margin * (ancestorRect.bottom - ancestorRect.top);\n      const marginRight = margin * (ancestorRect.right - ancestorRect.left);\n      const marginBottom = margin * (ancestorRect.bottom - ancestorRect.top);\n      const marginLeft = margin * (ancestorRect.right - ancestorRect.left);\n\n      // Clip the rect based on the ancestor's bounding rect\n      rect = {\n        top: Math.max(rect.top, ancestorRect.top - marginTop),\n        right: Math.min(rect.right, ancestorRect.right + marginRight),\n        bottom: Math.min(rect.bottom, ancestorRect.bottom + marginBottom),\n        left: Math.max(rect.left, ancestorRect.left - marginLeft),\n        width: 0, // Will be calculated next\n        height: 0, // Will be calculated next\n      };\n\n      // Calculate the width and height after clipping\n      rect.width = rect.right - rect.left;\n      rect.height = rect.bottom - rect.top;\n    }\n\n    // Move to the next ancestor\n    ancestor = ancestor.parentElement;\n  }\n\n  // Clip the rect based on the visual viewport (accounts for pinch-to-zoom)\n  const vv = ownerWindow.visualViewport;\n  const viewportTop = vv?.offsetTop ?? 0;\n  const viewportLeft = vv?.offsetLeft ?? 0;\n  const viewportWidth = vv?.width ?? ownerWindow.innerWidth;\n  const viewportHeight = vv?.height ?? ownerWindow.innerHeight;\n  const viewportMarginY = margin * viewportHeight;\n  const viewportMarginX = margin * viewportWidth;\n\n  rect = {\n    top: Math.max(rect.top, viewportTop - viewportMarginY),\n    right: Math.min(\n      rect.right,\n      viewportLeft + viewportWidth + viewportMarginX\n    ),\n    bottom: Math.min(\n      rect.bottom,\n      viewportTop + viewportHeight + viewportMarginY\n    ),\n    left: Math.max(rect.left, viewportLeft - viewportMarginX),\n    width: 0, // Will be calculated next\n    height: 0, // Will be calculated next\n  };\n\n  // Calculate the width and height after clipping\n  rect.width = rect.right - rect.left;\n  rect.height = rect.bottom - rect.top;\n\n  if (rect.width < 0) {\n    rect.width = 0;\n  }\n\n  if (rect.height < 0) {\n    rect.height = 0;\n  }\n\n  return rect;\n}\n"
  },
  {
    "path": "packages/dom/src/utilities/bounding-rectangle/index.ts",
    "content": "export {getBoundingRectangle} from './getBoundingRectangle.ts';\nexport {getViewportBoundingRectangle} from './getViewportBoundingRectangle.ts';\n"
  },
  {
    "path": "packages/dom/src/utilities/bounding-rectangle/isOverflowVisible.ts",
    "content": "/*\n * Check if an element has visible overflow.\n * @param element\n * @param style\n * @returns boolean\n */\nexport function isOverflowVisible(\n  element: Element,\n  style?: CSSStyleDeclaration\n) {\n  if (isDetailsElement(element) && element.open === false) {\n    return false;\n  }\n\n  const {overflow, overflowX, overflowY} = style ?? getComputedStyle(element);\n\n  return (\n    overflow === 'visible' && overflowX === 'visible' && overflowY === 'visible'\n  );\n}\n\nfunction isDetailsElement(element: Element): element is HTMLDetailsElement {\n  return element.tagName === 'DETAILS';\n}\n"
  },
  {
    "path": "packages/dom/src/utilities/bounding-rectangle/isRectEqual.ts",
    "content": "import type {BoundingRectangle} from '@dnd-kit/geometry';\n\nexport function isRectEqual(\n  a: BoundingRectangle | undefined,\n  b: BoundingRectangle | undefined\n) {\n  if (a === b) return true;\n  if (!a || !b) return false;\n\n  return (\n    a.top == b.top &&\n    a.left == b.left &&\n    a.right == b.right &&\n    a.bottom == b.bottom\n  );\n}\n"
  },
  {
    "path": "packages/dom/src/utilities/bounding-rectangle/isVisible.ts",
    "content": "import {getVisibleBoundingRectangle} from './getVisibleBoundingRectangle.ts';\n\nexport function isVisible(\n  element: Element,\n  boundingClientRect = element.getBoundingClientRect()\n): boolean {\n  const {width, height} = getVisibleBoundingRectangle(\n    element,\n    boundingClientRect\n  );\n\n  return width > 0 && height > 0;\n}\n"
  },
  {
    "path": "packages/dom/src/utilities/coordinates/getEventCoordinates.ts",
    "content": "import {type Coordinates} from '@dnd-kit/geometry';\n\nexport function getEventCoordinates(event: PointerEvent): Coordinates {\n  return {\n    x: event.clientX,\n    y: event.clientY,\n  };\n}\n"
  },
  {
    "path": "packages/dom/src/utilities/element/cloneElement.ts",
    "content": "export function cloneElement(element: Element): Element {\n  const selector = 'input, textarea, select, canvas, [contenteditable]';\n  const clonedElement = element.cloneNode(true) as HTMLElement;\n  const fields = Array.from(element.querySelectorAll(selector));\n  const clonedFields = Array.from(clonedElement.querySelectorAll(selector));\n\n  clonedFields.forEach((field, index) => {\n    const originalField = fields[index];\n\n    if (isField(field) && isField(originalField)) {\n      if (field.type !== 'file') {\n        field.value = originalField.value;\n      }\n\n      // Fixes an issue with original radio buttons losing their value once the\n      // clone is inserted in the DOM, as radio button `name` attributes must be unique\n      if (field.type === 'radio' && field.name) {\n        field.name = `Cloned__${field.name}`;\n      }\n    }\n\n    if (\n      isCanvasElement(field) &&\n      isCanvasElement(originalField) &&\n      originalField.width > 0 &&\n      originalField.height > 0\n    ) {\n      const destCtx = field.getContext('2d');\n      destCtx?.drawImage(originalField, 0, 0);\n    }\n  });\n\n  return clonedElement;\n}\n\nfunction isField(\n  element: Element\n): element is HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement {\n  return 'value' in element;\n}\n\nfunction isCanvasElement(element: Element): element is HTMLCanvasElement {\n  return element.tagName === 'CANVAS';\n}\n"
  },
  {
    "path": "packages/dom/src/utilities/element/getElementFromPoint.ts",
    "content": "import type {Coordinates} from '@dnd-kit/geometry';\n\nexport function getElementFromPoint(\n  root: Document | ShadowRoot,\n  {x, y}: Coordinates\n): Element | null {\n  const element = root.elementFromPoint(x, y); //supported by both document and shadowRoot.\n\n  if (isIFrameElement(element)) {\n    const {contentDocument} = element;\n\n    if (contentDocument) {\n      const {left, top} = element.getBoundingClientRect();\n\n      return getElementFromPoint(contentDocument, {\n        x: x - left,\n        y: y - top,\n      });\n    }\n  }\n\n  return element;\n}\n\nfunction isIFrameElement(\n  element: Element | null\n): element is HTMLIFrameElement {\n  return element?.tagName === 'IFRAME';\n}\n"
  },
  {
    "path": "packages/dom/src/utilities/element/index.ts",
    "content": "export {cloneElement} from './cloneElement.ts';\nexport {getElementFromPoint} from './getElementFromPoint.ts';\nexport {ProxiedElements} from './proxiedElements.ts';\n"
  },
  {
    "path": "packages/dom/src/utilities/element/isInteractiveElement.ts",
    "content": "export function isInteractiveElement(element: Element): boolean {\n  return Boolean(\n    element.closest(`\n      input:not([disabled]),\n      select:not([disabled]),\n      textarea:not([disabled]),\n      button:not([disabled]),\n      a[href],\n      [contenteditable]:not([contenteditable=\"false\"])\n    `)\n  );\n}\n"
  },
  {
    "path": "packages/dom/src/utilities/element/proxiedElements.ts",
    "content": "export const ProxiedElements = new WeakMap<Element, Element>();\n"
  },
  {
    "path": "packages/dom/src/utilities/event-listeners/Listeners.ts",
    "content": "export interface EventListenerDescriptor {\n  type: string;\n  listener(event: Event): void;\n  options?: AddEventListenerOptions;\n}\n\ntype EventListenerInput = EventListenerDescriptor[] | EventListenerDescriptor;\n\ntype EventListenerEntry = [EventTarget, EventListenerDescriptor];\n\nexport class Listeners {\n  private entries: Set<EventListenerEntry> = new Set();\n\n  constructor() {}\n\n  public bind(target: EventTarget | EventTarget[], input: EventListenerInput) {\n    const eventTargets = Array.isArray(target) ? target : [target];\n    const listeners = Array.isArray(input) ? input : [input];\n    const entries: EventListenerEntry[] = [];\n\n    for (const target of eventTargets) {\n      for (const descriptor of listeners) {\n        const {type, listener, options} = descriptor;\n        const entry: EventListenerEntry = [target, descriptor];\n\n        target.addEventListener(type, listener, options);\n        this.entries.add(entry);\n        entries.push(entry);\n      }\n    }\n\n    return function cleanup() {\n      for (const [target, {type, listener, options}] of entries) {\n        target.removeEventListener(type, listener, options);\n      }\n    };\n  }\n\n  public clear = () => {\n    for (const entry of this.entries) {\n      const [target, {type, listener, options}] = entry;\n\n      target.removeEventListener(type, listener, options);\n    }\n\n    this.entries.clear();\n  };\n}\n"
  },
  {
    "path": "packages/dom/src/utilities/event-listeners/index.ts",
    "content": "export {Listeners} from './Listeners.ts';\n"
  },
  {
    "path": "packages/dom/src/utilities/execution-context/canUseDOM.ts",
    "content": "// https://github.com/facebook/react/blob/master/packages/shared/ExecutionEnvironment.js\nexport const canUseDOM =\n  typeof window !== 'undefined' &&\n  typeof window.document !== 'undefined' &&\n  typeof window.document.createElement !== 'undefined';\n"
  },
  {
    "path": "packages/dom/src/utilities/execution-context/getDocument.ts",
    "content": "import {isDocument} from '../type-guards/isDocument.ts';\nimport {isHTMLElement} from '../type-guards/isHTMLElement.ts';\nimport {isNode} from '../type-guards/isNode.ts';\nimport {isSVGElement} from '../type-guards/isSVGElement.ts';\nimport {isWindow} from '../type-guards/isWindow.ts';\n\nexport function getDocument(target: Event['target'] | undefined): Document {\n  if (!target) {\n    return document;\n  }\n\n  if (isWindow(target)) {\n    return target.document;\n  }\n\n  if (!isNode(target)) {\n    return document;\n  }\n\n  if (isDocument(target)) {\n    return target;\n  }\n\n  if (isHTMLElement(target) || isSVGElement(target)) {\n    return target.ownerDocument;\n  }\n\n  return document;\n}\n"
  },
  {
    "path": "packages/dom/src/utilities/execution-context/getDocuments.ts",
    "content": "/**\n * Recursively finds all same-origin Document objects:\n * - the current document\n * - any same-origin parent documents\n * - any same-origin child documents (iframes, frames)\n *\n * @param rootDoc - The starting document (defaults to current document)\n * @param seen - Internal set to prevent duplicate traversal\n * @returns An array of all discovered same-origin Document objects\n */\nexport function getDocuments(\n  rootDoc: Document = document,\n  seen: Set<Document> = new Set()\n): Document[] {\n  if (seen.has(rootDoc)) return [];\n  seen.add(rootDoc);\n\n  const docs: Document[] = [rootDoc];\n\n  // --- Traverse same-origin child documents ---\n  for (const frame of Array.from<HTMLIFrameElement | HTMLFrameElement>(\n    rootDoc.querySelectorAll('iframe, frame')\n  )) {\n    try {\n      const childDoc = frame.contentDocument;\n      if (childDoc && !seen.has(childDoc)) {\n        docs.push(...getDocuments(childDoc, seen));\n      }\n    } catch {\n      // Ignore cross-origin frames\n    }\n  }\n\n  // --- Traverse same-origin parent documents ---\n  try {\n    const win = rootDoc.defaultView;\n    if (win && win !== window.top) {\n      const parentWin = win.parent;\n      if (parentWin && parentWin.document && parentWin.document !== rootDoc) {\n        docs.push(...getDocuments(parentWin.document, seen));\n      }\n    }\n  } catch {\n    // Ignore cross-origin parent access\n  }\n\n  return docs;\n}\n"
  },
  {
    "path": "packages/dom/src/utilities/execution-context/getFixedPositionOffset.ts",
    "content": "import {isSafari} from './isSafari.ts';\n\n/**\n * In Safari, `position: fixed` elements are anchored to the visual viewport\n * during pinch-to-zoom, rather than the layout viewport. Returns the offset\n * needed to compensate for this behavior.\n */\nexport function getFixedPositionOffset(): {x: number; y: number} {\n  const vv = isSafari() ? window.visualViewport : null;\n\n  return {\n    x: vv?.offsetLeft ?? 0,\n    y: vv?.offsetTop ?? 0,\n  };\n}\n"
  },
  {
    "path": "packages/dom/src/utilities/execution-context/getRoot.ts",
    "content": "import { isNode } from '../type-guards/isNode.ts';\nimport { isShadowRoot } from '../type-guards/isShadowRoot.ts';\nimport { getDocument } from './getDocument.ts';\n\nexport function getRoot(target: Event['target'] | undefined): Document | ShadowRoot {\n\n\tif (target && isNode(target)) {\n\t\tlet root = target.getRootNode();\n\t\tif (isShadowRoot(root)) {\n\t\t\treturn root as ShadowRoot;\n\t\t}\n\t\telse if (root instanceof Document) {\n\t\t\treturn root as Document;\n\t\t}\n\t}\n\treturn getDocument(target);\n}"
  },
  {
    "path": "packages/dom/src/utilities/execution-context/getWindow.ts",
    "content": "import {isWindow} from '../type-guards/isWindow.ts';\nimport {isNode} from '../type-guards/isNode.ts';\n\nexport function getWindow(\n  target: Event['target'] | null | undefined\n): typeof window {\n  if (!target) {\n    return window;\n  }\n\n  if (isWindow(target)) {\n    return target;\n  }\n\n  if (!isNode(target)) {\n    return window;\n  }\n\n  if ('defaultView' in target) {\n    return (target.defaultView as typeof window | null) ?? window;\n  }\n\n  return target.ownerDocument?.defaultView ?? window;\n}\n"
  },
  {
    "path": "packages/dom/src/utilities/execution-context/isSafari.ts",
    "content": "export function isSafari() {\n  return /^((?!chrome|android).)*safari/i.test(navigator.userAgent);\n}\n"
  },
  {
    "path": "packages/dom/src/utilities/execution-context/prefersReducedMotion.ts",
    "content": "export function prefersReducedMotion(window: Window): boolean {\n  return window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n}\n"
  },
  {
    "path": "packages/dom/src/utilities/frame/getFrameElement.ts",
    "content": "export function getFrameElement(el: Element | undefined) {\n  const refWindow = el?.ownerDocument.defaultView;\n\n  if (refWindow && refWindow.self !== refWindow.parent) {\n    return refWindow.frameElement;\n  }\n}\n"
  },
  {
    "path": "packages/dom/src/utilities/frame/getFrameElements.ts",
    "content": "import {getFrameElement} from './getFrameElement.ts';\n\nexport function getFrameElements(el: Element | undefined) {\n  const frames = new Set<Element>();\n  let frame = getFrameElement(el);\n\n  while (frame) {\n    frames.add(frame);\n    frame = getFrameElement(frame);\n  }\n\n  return frames;\n}\n"
  },
  {
    "path": "packages/dom/src/utilities/frame/getFrameTransform.ts",
    "content": "import {getComputedStyles} from '../styles/getComputedStyles.ts';\nimport {isHTMLElement} from '../type-guards/isHTMLElement.ts';\nimport type {Transform} from '../transform/index.ts';\n\nimport {getFrameElement} from './getFrameElement.ts';\nimport {getBoundingRectangle} from '../bounding-rectangle/getBoundingRectangle.ts';\n\nexport function getFrameTransform(\n  el: Element | undefined,\n  boundary: Element | null = window.frameElement\n): Transform {\n  const transform: Transform = {\n    x: 0,\n    y: 0,\n    scaleX: 1,\n    scaleY: 1,\n  };\n\n  if (!el) return transform;\n\n  let frame = getFrameElement(el);\n\n  while (frame) {\n    if (frame === boundary) {\n      return transform;\n    }\n\n    const rect = getBoundingRectangle(frame);\n    const {x: scaleX, y: scaleY} = getScale(frame, rect);\n\n    transform.x = transform.x + rect.left;\n    transform.y = transform.y + rect.top;\n    transform.scaleX = transform.scaleX * scaleX;\n    transform.scaleY = transform.scaleY * scaleY;\n\n    frame = getFrameElement(frame);\n  }\n\n  return transform;\n}\n\nfunction getScale(\n  element: Element,\n  boundingRectangle = getBoundingRectangle(element)\n) {\n  const width = Math.round(boundingRectangle.width);\n  const height = Math.round(boundingRectangle.height);\n\n  if (isHTMLElement(element)) {\n    return {\n      x: width / element.offsetWidth,\n      y: height / element.offsetHeight,\n    };\n  }\n\n  const styles = getComputedStyles(element, true);\n\n  return {\n    x: (parseFloat(styles.width) || width) / width,\n    y: (parseFloat(styles.height) || height) / height,\n  };\n}\n"
  },
  {
    "path": "packages/dom/src/utilities/index.ts",
    "content": "export {getFinalKeyframe} from './animations/getFinalKeyframe.ts';\n\nexport {\n  getBoundingRectangle,\n  getViewportBoundingRectangle,\n} from './bounding-rectangle/index.ts';\nexport {getVisibleBoundingRectangle} from './bounding-rectangle/getVisibleBoundingRectangle.ts';\n\nexport {getEventCoordinates} from './coordinates/getEventCoordinates.ts';\n\nexport {canUseDOM} from './execution-context/canUseDOM.ts';\nexport {getDocument} from './execution-context/getDocument.ts';\nexport {getWindow} from './execution-context/getWindow.ts';\nexport {getDocuments} from './execution-context/getDocuments.ts';\nexport {getFixedPositionOffset} from './execution-context/getFixedPositionOffset.ts';\nexport {isSafari} from './execution-context/isSafari.ts';\nexport {getRoot} from './execution-context/getRoot.ts';\nexport {prefersReducedMotion} from './execution-context/prefersReducedMotion.ts';\n\nexport {\n  cloneElement,\n  getElementFromPoint,\n  ProxiedElements,\n} from './element/index.ts';\nexport {isInteractiveElement} from './element/isInteractiveElement.ts';\n\nexport {Listeners} from './event-listeners/index.ts';\nexport {PositionObserver} from './observers/index.ts';\nexport {ResizeNotifier} from './observers/ResizeNotifier.ts';\n\nexport {showPopover, hidePopover, supportsPopover} from './popover/index.ts';\n\nexport {\n  canScroll,\n  detectScrollIntent,\n  getScrollableAncestors,\n  getFirstScrollableAncestor,\n  isDocumentScrollingElement,\n  ScrollDirection,\n  scrollIntoViewIfNeeded,\n} from './scroll/index.ts';\n\nexport {scheduler, Scheduler, timeout} from './scheduling/index.ts';\n\nexport {DOMRectangle, type DOMRectangleOptions} from './shapes/index.ts';\n\nexport {Styles, getComputedStyles} from './styles/index.ts';\n\nexport {\n  supportsViewTransition,\n  supportsStyle,\n  isElement,\n  isDocument,\n  isHTMLElement,\n  isKeyframeEffect,\n  isKeyboardEvent,\n  isPointerEvent,\n  isShadowRoot,\n} from './type-guards/index.ts';\nexport {isTextInput} from './type-guards/isTextInput.ts';\n\nexport {\n  animateTransform,\n  computeTranslate,\n  inverseTransform,\n  parseTransform,\n  parseTranslate,\n} from './transform/index.ts';\nexport type {Transform} from './transform/index.ts';\n\nexport {generateUniqueId} from './misc/generateUniqueId.ts';\n\nexport {getFrameElement} from './frame/getFrameElement.ts';\nexport {getFrameTransform} from './frame/getFrameTransform.ts';\n"
  },
  {
    "path": "packages/dom/src/utilities/misc/generateUniqueId.ts",
    "content": "const ids: Record<string, number> = {};\n\nexport function generateUniqueId(prefix: string) {\n  const id = ids[prefix] == null ? 0 : ids[prefix] + 1;\n  ids[prefix] = id;\n\n  return `${prefix}-${id}`;\n}\n"
  },
  {
    "path": "packages/dom/src/utilities/observers/FrameObserver.ts",
    "content": "import {getFrameElements} from '../frame/getFrameElements.ts';\nimport {throttle} from '../scheduling/throttle.ts';\nimport {\n  PositionObserver,\n  THROTTLE_INTERVAL,\n  type PositionObserverCallback,\n} from './PositionObserver.ts';\n\nconst framePositionObservers = new WeakMap<\n  Element,\n  {\n    disconnect: () => void;\n    callbacks: Set<PositionObserverCallback>;\n  }\n>();\n\nconst scrollListeners = new WeakMap<\n  Document,\n  {\n    disconnect: () => void;\n    listeners: Set<EventListener>;\n  }\n>();\n\nfunction addFrameListener(frame: Element, callback: PositionObserverCallback) {\n  // Check if already observed globally\n  let cached = framePositionObservers.get(frame);\n\n  if (!cached) {\n    const observer = new PositionObserver(\n      frame,\n      (boundingClientRect) => {\n        const cached = framePositionObservers.get(frame);\n        if (!cached) return;\n\n        cached.callbacks.forEach((callback) => callback(boundingClientRect));\n      },\n      {skipInitial: true}\n    );\n\n    cached = {disconnect: observer.disconnect, callbacks: new Set()};\n  }\n\n  cached.callbacks.add(callback);\n  framePositionObservers.set(frame, cached);\n\n  return () => {\n    cached.callbacks.delete(callback);\n\n    if (cached.callbacks.size === 0) {\n      framePositionObservers.delete(frame);\n      cached.disconnect();\n    }\n  };\n}\n\nfunction observeParentFrames(\n  frames: Set<Element>,\n  callback: PositionObserverCallback\n) {\n  const cleanup = new Set<() => void>();\n\n  for (const frame of frames) {\n    const remove = addFrameListener(frame, callback);\n    cleanup.add(remove);\n  }\n\n  return () => cleanup.forEach((remove) => remove());\n}\n\nfunction addScrollListener(element: Element, callback: EventListener) {\n  const doc = element.ownerDocument;\n\n  if (!scrollListeners.has(doc)) {\n    const controller = new AbortController();\n    const listeners = new Set<EventListener>();\n\n    document.addEventListener(\n      'scroll',\n      (event) => listeners.forEach((listener) => listener(event)),\n      {\n        capture: true,\n        passive: true,\n        signal: controller.signal,\n      }\n    );\n\n    scrollListeners.set(doc, {disconnect: () => controller.abort(), listeners});\n  }\n\n  const {listeners, disconnect} = scrollListeners.get(doc) ?? {};\n\n  if (!listeners || !disconnect) return () => {};\n\n  listeners.add(callback);\n\n  return () => {\n    listeners.delete(callback);\n\n    if (listeners.size === 0) {\n      disconnect();\n      scrollListeners.delete(doc);\n    }\n  };\n}\n\nexport class FrameObserver {\n  #elementObserver: PositionObserver;\n  #disconnected = false;\n  #frames: Set<Element>;\n\n  constructor(\n    element: Element,\n    private callback: PositionObserverCallback,\n    options?: {debug?: boolean}\n  ) {\n    const frames = getFrameElements(element);\n    const unobserveParentFrames = observeParentFrames(frames, callback);\n    const removeScrollListener = addScrollListener(element, this.#handleScroll);\n\n    this.#frames = frames;\n    this.#elementObserver = new PositionObserver(element, callback, options);\n    this.disconnect = () => {\n      if (this.#disconnected) return;\n      this.#disconnected = true;\n\n      unobserveParentFrames();\n      removeScrollListener();\n      this.#elementObserver.disconnect();\n    };\n  }\n\n  disconnect: () => void;\n\n  #handleScroll = throttle((event: Event) => {\n    if (this.#disconnected) return;\n    if (!event.target) return;\n    if (\n      'contains' in event.target &&\n      typeof event.target.contains === 'function'\n    ) {\n      for (const frame of this.#frames) {\n        if (event.target.contains(frame)) {\n          this.callback(this.#elementObserver.boundingClientRect);\n          break;\n        }\n      }\n    }\n  }, THROTTLE_INTERVAL);\n}\n"
  },
  {
    "path": "packages/dom/src/utilities/observers/PositionObserver.ts",
    "content": "import {BoundingRectangle, Rectangle} from '@dnd-kit/geometry';\n\nimport {throttle} from '../scheduling/throttle.ts';\n\nimport {isRectEqual} from '../bounding-rectangle/isRectEqual.ts';\nimport {isVisible} from '../bounding-rectangle/isVisible.ts';\nimport {getVisibleBoundingRectangle} from '../bounding-rectangle/getVisibleBoundingRectangle.ts';\n\nimport {ResizeNotifier} from './ResizeNotifier.ts';\n\nexport type PositionObserverCallback = (\n  boundingClientRect: BoundingRectangle | null\n) => void;\n\nconst threshold = Array.from({length: 100}, (_, index) => index / 100);\nexport const THROTTLE_INTERVAL = 75;\n\nexport class PositionObserver {\n  constructor(\n    public element: Element,\n    public callback: PositionObserverCallback,\n    options: {debug?: boolean; skipInitial?: boolean} = {\n      debug: false,\n      skipInitial: false,\n    }\n  ) {\n    this.boundingClientRect = element.getBoundingClientRect();\n    this.#visible = isVisible(element, this.boundingClientRect);\n\n    let initial = true;\n    this.callback = (boundingClientRect) => {\n      if (initial) {\n        initial = false;\n        if (options.skipInitial) return;\n      }\n\n      callback(boundingClientRect);\n    };\n\n    const root = element.ownerDocument;\n\n    if (options?.debug) {\n      this.#debug = document.createElement('div');\n      this.#debug.style.background = 'rgba(0,0,0,0.15)';\n      this.#debug.style.position = 'fixed';\n      this.#debug.style.pointerEvents = 'none';\n      root.body.appendChild(this.#debug);\n    }\n\n    this.#visibilityObserver = new IntersectionObserver(\n      (entries: IntersectionObserverEntry[]) => {\n        const entry = entries[entries.length - 1];\n        const {boundingClientRect, isIntersecting: visible} = entry;\n        const {width, height} = boundingClientRect;\n        const previousVisible = this.#visible;\n\n        this.#visible = visible;\n\n        if (!width && !height) return;\n\n        if (previousVisible && !visible) {\n          this.#positionObserver?.disconnect();\n          this.callback(null);\n          this.#resizeObserver?.disconnect();\n          this.#resizeObserver = undefined;\n\n          if (this.#debug) this.#debug.style.visibility = 'hidden';\n        } else {\n          this.#observePosition();\n        }\n\n        if (visible && !this.#resizeObserver) {\n          this.#resizeObserver = new ResizeNotifier(this.#observePosition);\n          this.#resizeObserver.observe(element);\n        }\n      },\n      {\n        threshold,\n        root,\n      }\n    );\n\n    if (this.#visible && !options.skipInitial) {\n      this.callback(this.boundingClientRect);\n    }\n\n    this.#visibilityObserver.observe(element);\n  }\n\n  public boundingClientRect: DOMRectReadOnly;\n\n  public disconnect = () => {\n    this.#disconnected = true;\n    this.#resizeObserver?.disconnect();\n    this.#positionObserver?.disconnect();\n    this.#visibilityObserver.disconnect();\n    this.#debug?.remove();\n  };\n\n  #visible = true;\n  #previousBoundingClientRect: DOMRectReadOnly | undefined;\n  #resizeObserver: ResizeNotifier | undefined;\n  #positionObserver: IntersectionObserver | undefined;\n  #visibilityObserver: IntersectionObserver;\n  #debug: HTMLElement | undefined;\n  #disconnected = false;\n\n  #observePosition = throttle(() => {\n    const {element} = this;\n\n    this.#positionObserver?.disconnect();\n\n    if (this.#disconnected || !this.#visible || !element.isConnected) {\n      return;\n    }\n\n    const root = element.ownerDocument ?? document;\n    const {innerHeight, innerWidth} = root.defaultView ?? window;\n    const clientRect = element.getBoundingClientRect();\n    const visibleRect = getVisibleBoundingRectangle(element, clientRect);\n    const {top, left, bottom, right} = visibleRect;\n    const insetTop = -Math.floor(top);\n    const insetLeft = -Math.floor(left);\n    const insetRight = -Math.floor(innerWidth - right);\n    const insetBottom = -Math.floor(innerHeight - bottom);\n    const rootMargin = `${insetTop}px ${insetRight}px ${insetBottom}px ${insetLeft}px`;\n\n    this.boundingClientRect = clientRect;\n    this.#positionObserver = new IntersectionObserver(\n      (entries: IntersectionObserverEntry[]) => {\n        const [entry] = entries;\n        const {intersectionRect} = entry;\n        /*\n         * The intersection ratio returned by the intersection observer entry\n         * represents the ratio of the intersectionRect to the boundingClientRect,\n         * which is not what we want. We want the ratio of the intersectionRect\n         * to the rootBounds (visible rect).\n         */\n        const intersectionRatio =\n          entry.intersectionRatio !== 1\n            ? entry.intersectionRatio\n            : Rectangle.intersectionRatio(\n                intersectionRect,\n                getVisibleBoundingRectangle(element)\n              );\n\n        if (intersectionRatio !== 1) {\n          this.#observePosition();\n        }\n      },\n      {\n        threshold,\n        rootMargin,\n        root,\n      }\n    );\n\n    this.#positionObserver.observe(element);\n    this.#notify();\n  }, THROTTLE_INTERVAL);\n\n  #notify() {\n    if (this.#disconnected) return;\n\n    this.#updateDebug();\n\n    if (isRectEqual(this.boundingClientRect, this.#previousBoundingClientRect))\n      return;\n\n    this.callback(this.boundingClientRect);\n    this.#previousBoundingClientRect = this.boundingClientRect;\n  }\n\n  #updateDebug() {\n    if (this.#debug) {\n      const {top, left, width, height} = getVisibleBoundingRectangle(\n        this.element\n      );\n\n      this.#debug.style.overflow = 'hidden';\n      this.#debug.style.visibility = 'visible';\n      this.#debug.style.top = `${Math.floor(top)}px`;\n      this.#debug.style.left = `${Math.floor(left)}px`;\n      this.#debug.style.width = `${Math.floor(width)}px`;\n      this.#debug.style.height = `${Math.floor(height)}px`;\n    }\n  }\n}\n"
  },
  {
    "path": "packages/dom/src/utilities/observers/ResizeNotifier.ts",
    "content": "import {canUseDOM} from '../execution-context/canUseDOM.ts';\n\nconst Observer = canUseDOM\n  ? ResizeObserver\n  : class MockResizeObserver implements ResizeObserver {\n      observe() {}\n      unobserve() {}\n      disconnect() {}\n    };\n\nexport class ResizeNotifier extends Observer {\n  #initialized = false;\n\n  constructor(callback: ResizeObserverCallback) {\n    super((entries) => {\n      if (!this.#initialized) {\n        this.#initialized = true;\n        return;\n      }\n      callback(entries, this);\n    });\n  }\n}\n"
  },
  {
    "path": "packages/dom/src/utilities/observers/index.ts",
    "content": "export {FrameObserver as PositionObserver} from './FrameObserver.ts';\n"
  },
  {
    "path": "packages/dom/src/utilities/popover/hidePopover.ts",
    "content": "import {supportsPopover} from './supportsPopover.ts';\n\nexport function hidePopover(element: Element) {\n  try {\n    if (\n      supportsPopover(element) &&\n      element.isConnected &&\n      element.hasAttribute('popover') &&\n      // This selector can throw an error in browsers that don't support it\n      element.matches(':popover-open')\n    ) {\n      element.hidePopover();\n    }\n  } catch (error) {\n    // no-op\n  }\n}\n"
  },
  {
    "path": "packages/dom/src/utilities/popover/index.ts",
    "content": "export {showPopover} from './showPopover.ts';\nexport {hidePopover} from './hidePopover.ts';\nexport {supportsPopover} from './supportsPopover.ts';\n"
  },
  {
    "path": "packages/dom/src/utilities/popover/showPopover.ts",
    "content": "import {supportsPopover} from './supportsPopover.ts';\n\nexport function showPopover(element: Element) {\n  try {\n    if (\n      supportsPopover(element) &&\n      element.isConnected &&\n      element.hasAttribute('popover') &&\n      // This selector can throw an error in browsers that don't support it\n      !element.matches(':popover-open')\n    ) {\n      element.showPopover();\n    }\n  } catch (error) {\n    // no-op\n  }\n}\n"
  },
  {
    "path": "packages/dom/src/utilities/popover/supportsPopover.ts",
    "content": "export function supportsPopover(element: Element): element is Element & {\n  showPopover(): void;\n  hidePopover(): void;\n} {\n  return (\n    'showPopover' in element &&\n    'hidePopover' in element &&\n    typeof element.showPopover === 'function' &&\n    typeof element.hidePopover === 'function'\n  );\n}\n"
  },
  {
    "path": "packages/dom/src/utilities/scheduling/index.ts",
    "content": "export {Scheduler, scheduler} from './scheduler.ts';\nexport {timeout} from './timeout.ts';\n"
  },
  {
    "path": "packages/dom/src/utilities/scheduling/scheduler.ts",
    "content": "type Callback = () => void;\n\nexport class Scheduler<T extends (callback: Callback) => any> {\n  constructor(private scheduler: T) {}\n\n  private pending: boolean = false;\n  private tasks: Set<() => void> = new Set();\n  private resolvers: Set<() => void> = new Set();\n\n  public schedule(task: () => void): Promise<void> {\n    this.tasks.add(task);\n\n    if (!this.pending) {\n      this.pending = true;\n      this.scheduler(this.flush);\n    }\n\n    return new Promise<void>((resolve) => this.resolvers.add(resolve));\n  }\n\n  public flush = () => {\n    const {tasks, resolvers} = this;\n\n    this.pending = false;\n    this.tasks = new Set();\n    this.resolvers = new Set();\n\n    for (const task of tasks) {\n      task();\n    }\n\n    for (const resolve of resolvers) {\n      resolve();\n    }\n  };\n}\n\nexport const scheduler = new Scheduler((callback) => {\n  if (typeof requestAnimationFrame === 'function') {\n    requestAnimationFrame(callback);\n  } else {\n    callback();\n  }\n});\n"
  },
  {
    "path": "packages/dom/src/utilities/scheduling/throttle.ts",
    "content": "import {timeout} from './timeout.ts';\n\nexport function throttle<T extends (...args: any[]) => any>(\n  func: T,\n  limit: number\n): (...args: Parameters<T>) => void {\n  const time = () => performance.now();\n  let cancel: () => void | undefined;\n  let lastRan: number;\n\n  return function (this: any, ...args: Parameters<T>) {\n    const context = this;\n    if (!lastRan) {\n      func.apply(context, args);\n      lastRan = time();\n    } else {\n      cancel?.();\n      cancel = timeout(\n        () => {\n          func.apply(context, args);\n          lastRan = time();\n        },\n        limit - (time() - lastRan)\n      );\n    }\n  };\n}\n"
  },
  {
    "path": "packages/dom/src/utilities/scheduling/timeout.ts",
    "content": "export function timeout(callback: () => void, duration: number): () => void {\n  const id = setTimeout(callback, duration);\n\n  return () => clearTimeout(id);\n}\n"
  },
  {
    "path": "packages/dom/src/utilities/scroll/canScroll.ts",
    "content": "import type {Coordinates} from '@dnd-kit/geometry';\n\nimport {getScrollPosition} from './getScrollPosition.ts';\n\nexport function canScroll(scrollableElement: Element, by?: Coordinates) {\n  const {isTop, isBottom, isLeft, isRight, position} =\n    getScrollPosition(scrollableElement);\n\n  const {x, y} = by ?? {x: 0, y: 0};\n\n  const top = !isTop && position.current.y + y > 0;\n  const bottom = !isBottom && position.current.y + y < position.max.y;\n  const left = !isLeft && position.current.x + x > 0;\n  const right = !isRight && position.current.x + x < position.max.x;\n\n  return {\n    top,\n    bottom,\n    left,\n    right,\n    x: left || right,\n    y: top || bottom,\n  };\n}\n"
  },
  {
    "path": "packages/dom/src/utilities/scroll/detectScrollIntent.ts",
    "content": "import {Rectangle, type Axis, type Coordinates} from '@dnd-kit/geometry';\n\nimport {getScrollPosition} from './getScrollPosition.ts';\nimport {getFrameTransform} from '../frame/getFrameTransform.ts';\nimport {getComputedStyles} from '../styles/getComputedStyles.ts';\nimport {parseTransform} from '../transform/parseTransform.ts';\n\nexport enum ScrollDirection {\n  Idle = 0,\n  Forward = 1,\n  Reverse = -1,\n}\n\nconst defaultThreshold: Record<Axis, number> = {\n  x: 0.2,\n  y: 0.2,\n};\n\nconst defaultTolerance: Record<Axis, number> = {\n  x: 10,\n  y: 10,\n};\n\ninterface ScrollIntent {\n  x: ScrollDirection;\n  y: ScrollDirection;\n}\n\nexport function detectScrollIntent(\n  scrollableElement: Element,\n  coordinates: Coordinates,\n  intent?: ScrollIntent,\n  acceleration = 25,\n  thresholdPercentage = defaultThreshold,\n  tolerance = defaultTolerance\n) {\n  const {x, y} = coordinates;\n  const {rect, isTop, isBottom, isLeft, isRight} =\n    getScrollPosition(scrollableElement);\n  const frameTransform = getFrameTransform(scrollableElement);\n  const computedStyles = getComputedStyles(scrollableElement, true);\n  const parsedTransform = parseTransform(computedStyles);\n  const isXAxisInverted =\n    parsedTransform !== null ? parsedTransform?.scaleX < 0 : false;\n  const isYAxisInverted =\n    parsedTransform !== null ? parsedTransform?.scaleY < 0 : false;\n  const scrollContainerRect = new Rectangle(\n    rect.left * frameTransform.scaleX + frameTransform.x,\n    rect.top * frameTransform.scaleY + frameTransform.y,\n    rect.width * frameTransform.scaleX,\n    rect.height * frameTransform.scaleY\n  );\n  const direction: Record<Axis, ScrollDirection> = {\n    x: ScrollDirection.Idle,\n    y: ScrollDirection.Idle,\n  };\n  const speed = {\n    x: 0,\n    y: 0,\n  };\n  const threshold = {\n    height: scrollContainerRect.height * thresholdPercentage.y,\n    width: scrollContainerRect.width * thresholdPercentage.x,\n  };\n\n  if (\n    threshold.height > 0 &&\n    (!isTop || (isYAxisInverted && !isBottom)) &&\n    y <= scrollContainerRect.top + threshold.height &&\n    intent?.y !== ScrollDirection.Forward &&\n    x >= scrollContainerRect.left - tolerance.x &&\n    x <= scrollContainerRect.right + tolerance.x\n  ) {\n    // Scroll Up (or Down if inverted)\n    direction.y = isYAxisInverted\n      ? ScrollDirection.Forward\n      : ScrollDirection.Reverse;\n    speed.y =\n      acceleration *\n      Math.abs(\n        (scrollContainerRect.top + threshold.height - y) / threshold.height\n      );\n  } else if (\n    threshold.height > 0 &&\n    (!isBottom || (isYAxisInverted && !isTop)) &&\n    y >= scrollContainerRect.bottom - threshold.height &&\n    intent?.y !== ScrollDirection.Reverse &&\n    x >= scrollContainerRect.left - tolerance.x &&\n    x <= scrollContainerRect.right + tolerance.x\n  ) {\n    // Scroll Down (or Up if inverted)\n    direction.y = isYAxisInverted\n      ? ScrollDirection.Reverse\n      : ScrollDirection.Forward;\n    speed.y =\n      acceleration *\n      Math.abs(\n        (scrollContainerRect.bottom - threshold.height - y) / threshold.height\n      );\n  }\n\n  if (\n    threshold.width > 0 &&\n    (!isRight || (isXAxisInverted && !isLeft)) &&\n    x >= scrollContainerRect.right - threshold.width &&\n    intent?.x !== ScrollDirection.Reverse &&\n    y >= scrollContainerRect.top - tolerance.y &&\n    y <= scrollContainerRect.bottom + tolerance.y\n  ) {\n    // Scroll Right (or Left if inverted)\n    direction.x = isXAxisInverted\n      ? ScrollDirection.Reverse\n      : ScrollDirection.Forward;\n    speed.x =\n      acceleration *\n      Math.abs(\n        (scrollContainerRect.right - threshold.width - x) / threshold.width\n      );\n  } else if (\n    threshold.width > 0 &&\n    (!isLeft || (isXAxisInverted && !isRight)) &&\n    x <= scrollContainerRect.left + threshold.width &&\n    intent?.x !== ScrollDirection.Forward &&\n    y >= scrollContainerRect.top - tolerance.y &&\n    y <= scrollContainerRect.bottom + tolerance.y\n  ) {\n    // Scroll Left (or Right if inverted)\n    direction.x = isXAxisInverted\n      ? ScrollDirection.Forward\n      : ScrollDirection.Reverse;\n    speed.x =\n      acceleration *\n      Math.abs(\n        (scrollContainerRect.left + threshold.width - x) / threshold.width\n      );\n  }\n\n  return {\n    direction,\n    speed,\n  };\n}\n"
  },
  {
    "path": "packages/dom/src/utilities/scroll/documentScrollingElement.ts",
    "content": "import {canUseDOM} from '../execution-context/canUseDOM.ts';\nimport {getDocument} from '../execution-context/getDocument.ts';\n\nexport function isDocumentScrollingElement(element: Element | null) {\n  if (!canUseDOM || !element) {\n    return false;\n  }\n\n  return element === getDocument(element).scrollingElement;\n}\n"
  },
  {
    "path": "packages/dom/src/utilities/scroll/getScrollPosition.ts",
    "content": "import {getBoundingRectangle} from '../bounding-rectangle/getBoundingRectangle.ts';\nimport {getViewportBoundingRectangle} from '../bounding-rectangle/getViewportBoundingRectangle.ts';\nimport {getWindow} from '../execution-context/getWindow.ts';\nimport {isDocumentScrollingElement} from './documentScrollingElement.ts';\n\nexport function getScrollPosition(scrollableElement: Element) {\n  const window = getWindow(scrollableElement);\n  const rect = isDocumentScrollingElement(scrollableElement)\n    ? getViewportBoundingRectangle(scrollableElement)\n    : getBoundingRectangle(scrollableElement);\n\n  const vv = window.visualViewport;\n  const dimensions = isDocumentScrollingElement(scrollableElement)\n    ? {\n        height: vv?.height ?? window.innerHeight,\n        width: vv?.width ?? window.innerWidth,\n      }\n    : {\n        height: scrollableElement.clientHeight,\n        width: scrollableElement.clientWidth,\n      };\n  const position = {\n    current: {\n      x: scrollableElement.scrollLeft,\n      y: scrollableElement.scrollTop,\n    },\n    max: {\n      x: scrollableElement.scrollWidth - dimensions.width,\n      y: scrollableElement.scrollHeight - dimensions.height,\n    },\n  };\n\n  const isTop = position.current.y <= 0;\n  const isLeft = position.current.x <= 0;\n  const isBottom = position.current.y >= position.max.y;\n  const isRight = position.current.x >= position.max.x;\n\n  return {\n    rect,\n    position,\n    isTop,\n    isLeft,\n    isBottom,\n    isRight,\n  };\n}\n"
  },
  {
    "path": "packages/dom/src/utilities/scroll/getScrollableAncestors.ts",
    "content": "import {getWindow} from '../execution-context/getWindow.ts';\nimport {isDocument} from '../type-guards/isDocument.ts';\nimport {isHTMLElement} from '../type-guards/isHTMLElement.ts';\nimport {isSVGElement} from '../type-guards/isSVGElement.ts';\nimport {getComputedStyles} from '../styles/getComputedStyles.ts';\nimport {isFixed} from './isFixed.ts';\nimport {isScrollable} from './isScrollable.ts';\nimport { isShadowRoot } from '../type-guards/isShadowRoot.ts';\n\ninterface Options {\n  limit?: number;\n  excludeElement?: boolean;\n  escapeShadowDOM?: boolean; // if false, stop at shadowRoot; otherwise keep finding upwards outside shadow host\n}\n\nconst defaultOptions: Options = {\n  excludeElement: true,\n  escapeShadowDOM: true,\n};\n\nexport function getScrollableAncestors(\n  element: Node | null,\n  options: Options = defaultOptions\n): Set<Element> {\n  const {limit, excludeElement, escapeShadowDOM} = options;\n  const scrollParents = new Set<Element>();\n\n  function findScrollableAncestors(node: Node | null): Set<Element> {\n    if (limit != null && scrollParents.size >= limit) {\n      return scrollParents;\n    }\n\n    if (!node) {\n      return scrollParents;\n    }\n\n    if (\n      isDocument(node) &&\n      node.scrollingElement != null &&\n      !scrollParents.has(node.scrollingElement)\n    ) {\n      scrollParents.add(node.scrollingElement);\n\n      return scrollParents;\n    }\n\n    if (escapeShadowDOM && isShadowRoot(node)){\n      return findScrollableAncestors(node.host);\n    }\n\n    if (!isHTMLElement(node)) {\n      if (isSVGElement(node)) {\n        return findScrollableAncestors(node.parentElement);\n      }\n\n      return scrollParents;\n    }\n\n    if (scrollParents.has(node)) {\n      return scrollParents;\n    }\n\n    const computedStyle = getComputedStyles(node, true);\n\n    if (excludeElement && node === element) {\n      // no-op\n    } else if (isScrollable(node, computedStyle)) {\n      scrollParents.add(node);\n    }\n\n    if (isFixed(node, computedStyle)) {\n      const {scrollingElement} = node.ownerDocument;\n\n      if (scrollingElement) scrollParents.add(scrollingElement);\n\n      return scrollParents;\n    }\n\n    return findScrollableAncestors(node.parentNode);\n  }\n\n  if (!element) {\n    return scrollParents;\n  }\n\n  return findScrollableAncestors(element);\n}\n\nexport function getFirstScrollableAncestor(node: Node | null): Element | null {\n  const [firstScrollableAncestor] = getScrollableAncestors(node, {limit: 1});\n\n  return firstScrollableAncestor ?? null;\n}\n"
  },
  {
    "path": "packages/dom/src/utilities/scroll/getScrollableElement.ts",
    "content": "import {canUseDOM} from '../execution-context/canUseDOM.ts';\nimport {getDocument} from '../execution-context/getDocument.ts';\nimport {isDocument} from '../type-guards/isDocument.ts';\nimport {isHTMLElement} from '../type-guards/isHTMLElement.ts';\nimport {isNode} from '../type-guards/isNode.ts';\nimport {isWindow} from '../type-guards/isWindow.ts';\n\nexport function getScrollableElement(element: EventTarget | null) {\n  if (!canUseDOM || !element) {\n    return null;\n  }\n\n  if (isWindow(element)) {\n    return element;\n  }\n\n  if (!isNode(element)) {\n    return null;\n  }\n\n  if (\n    isDocument(element) ||\n    element === getDocument(element).scrollingElement\n  ) {\n    return window;\n  }\n\n  if (isHTMLElement(element)) {\n    return element;\n  }\n\n  return null;\n}\n"
  },
  {
    "path": "packages/dom/src/utilities/scroll/index.ts",
    "content": "export {canScroll} from './canScroll.ts';\nexport {\n  getFirstScrollableAncestor,\n  getScrollableAncestors,\n} from './getScrollableAncestors.ts';\nexport {getScrollableElement} from './getScrollableElement.ts';\nexport {detectScrollIntent, ScrollDirection} from './detectScrollIntent.ts';\nexport {getScrollPosition} from './getScrollPosition.ts';\nexport {isDocumentScrollingElement} from './documentScrollingElement.ts';\nexport {isScrollable} from './isScrollable.ts';\nexport {isFixed} from './isFixed.ts';\nexport {scrollIntoViewIfNeeded} from './scrollIntoViewIfNeeded.ts';\n"
  },
  {
    "path": "packages/dom/src/utilities/scroll/isFixed.ts",
    "content": "import {getComputedStyles} from '../styles/getComputedStyles.ts';\n\nexport function isFixed(\n  node: Element,\n  computedStyle: CSSStyleDeclaration = getComputedStyles(node, true)\n): boolean {\n  return (\n    computedStyle.position === 'fixed' || computedStyle.position === 'sticky'\n  );\n}\n"
  },
  {
    "path": "packages/dom/src/utilities/scroll/isScrollable.ts",
    "content": "import {getComputedStyles} from '../styles/getComputedStyles.ts';\n\nexport function isScrollable(\n  element: HTMLElement,\n  computedStyle: CSSStyleDeclaration = getComputedStyles(element, true)\n): boolean {\n  const overflowRegex = /(auto|scroll|overlay)/;\n  const properties = ['overflow', 'overflowX', 'overflowY'];\n\n  return properties.some((property) => {\n    const value = computedStyle[property as keyof CSSStyleDeclaration];\n\n    return typeof value === 'string' ? overflowRegex.test(value) : false;\n  });\n}\n"
  },
  {
    "path": "packages/dom/src/utilities/scroll/scrollIntoViewIfNeeded.ts",
    "content": "import {getComputedStyles} from '../styles/getComputedStyles.ts';\nimport {isHTMLElement} from '../type-guards/isHTMLElement.ts';\nimport {getFirstScrollableAncestor} from './getScrollableAncestors.ts';\n\nexport function scrollIntoViewIfNeeded(el: Element, centerIfNeeded = false) {\n  if (!isHTMLElement(el)) {\n    return;\n  }\n\n  const parent = getFirstScrollableAncestor(el);\n\n  if (!isHTMLElement(parent)) {\n    return;\n  }\n\n  const parentComputedStyle = getComputedStyles(parent, true),\n    parentBorderTopWidth = parseInt(\n      parentComputedStyle.getPropertyValue('border-top-width')\n    ),\n    parentBorderLeftWidth = parseInt(\n      parentComputedStyle.getPropertyValue('border-left-width')\n    ),\n    overTop = el.offsetTop - parent.offsetTop < parent.scrollTop,\n    overBottom =\n      el.offsetTop - parent.offsetTop + el.clientHeight - parentBorderTopWidth >\n      parent.scrollTop + parent.clientHeight,\n    overLeft = el.offsetLeft - parent.offsetLeft < parent.scrollLeft,\n    overRight =\n      el.offsetLeft -\n        parent.offsetLeft +\n        el.clientWidth -\n        parentBorderLeftWidth >\n      parent.scrollLeft + parent.clientWidth,\n    alignWithTop = overTop && !overBottom;\n\n  if ((overTop || overBottom) && centerIfNeeded) {\n    parent.scrollTop =\n      el.offsetTop -\n      parent.offsetTop -\n      parent.clientHeight / 2 -\n      parentBorderTopWidth +\n      el.clientHeight / 2;\n  }\n\n  if ((overLeft || overRight) && centerIfNeeded) {\n    parent.scrollLeft =\n      el.offsetLeft -\n      parent.offsetLeft -\n      parent.clientWidth / 2 -\n      parentBorderLeftWidth +\n      el.clientWidth / 2;\n  }\n\n  if ((overTop || overBottom || overLeft || overRight) && !centerIfNeeded) {\n    if (alignWithTop) {\n      parent.scrollTop = el.offsetTop - parent.offsetTop;\n    } else if (overBottom) {\n      parent.scrollTop =\n        el.offsetTop -\n        parent.offsetTop +\n        el.clientHeight -\n        parent.clientHeight;\n    }\n\n    if (overLeft) {\n      parent.scrollLeft = el.offsetLeft - parent.offsetLeft;\n    } else if (overRight) {\n      parent.scrollLeft =\n        el.offsetLeft -\n        parent.offsetLeft +\n        el.clientWidth -\n        parent.clientWidth;\n    }\n  }\n}\n"
  },
  {
    "path": "packages/dom/src/utilities/shapes/DOMRectangle.ts",
    "content": "import {Rectangle, type BoundingRectangle} from '@dnd-kit/geometry';\n\nimport {applyTransform} from '../transform/applyTransform.ts';\nimport {inverseTransform} from '../transform/inverseTransform.ts';\nimport {getComputedStyles} from '../styles/getComputedStyles.ts';\nimport {parseTransform, type Transform} from '../transform/index.ts';\nimport {getBoundingRectangle} from '../bounding-rectangle/getBoundingRectangle.ts';\nimport {getFrameTransform} from '../frame/getFrameTransform.ts';\nimport {isKeyframeEffect} from '../type-guards/isKeyframeEffect.ts';\nimport {forceFinishAnimations} from '../animations/forceFinishAnimations.ts';\nimport {isSafari} from '../execution-context/isSafari.ts';\n\nexport interface DOMRectangleOptions {\n  getBoundingClientRect?: (element: Element) => BoundingRectangle;\n  /* Whether to ignore transforms when calculating the rectangle */\n  ignoreTransforms?: boolean;\n  frameTransform?: Transform | null;\n}\n\nexport class DOMRectangle extends Rectangle {\n  constructor(element: Element, options: DOMRectangleOptions = {}) {\n    const {\n      frameTransform = getFrameTransform(element),\n      ignoreTransforms,\n      getBoundingClientRect = getBoundingRectangle,\n    } = options;\n    const resetAnimations = forceFinishAnimations(element, {\n      properties: ['transform', 'translate', 'scale', 'width', 'height'],\n      isValidTarget: (target) =>\n        (target !== element || isSafari()) && target.contains(element),\n    });\n    const boundingRectangle = getBoundingClientRect(element);\n    let {top, left, width, height} = boundingRectangle;\n    let updated: BoundingRectangle | undefined;\n\n    const computedStyles = getComputedStyles(element);\n    const parsedTransform = parseTransform(computedStyles);\n\n    const scale = {\n      x: parsedTransform?.scaleX ?? 1,\n      y: parsedTransform?.scaleY ?? 1,\n    };\n\n    const projectedTransform = getProjectedTransform(element, computedStyles);\n\n    resetAnimations?.();\n\n    if (parsedTransform) {\n      updated = inverseTransform(\n        boundingRectangle,\n        parsedTransform,\n        computedStyles.transformOrigin\n      );\n\n      if (ignoreTransforms || projectedTransform) {\n        top = updated.top;\n        left = updated.left;\n        width = updated.width;\n        height = updated.height;\n      }\n    }\n\n    const intrinsic = {\n      width: updated?.width ?? width,\n      height: updated?.height ?? height,\n    };\n\n    if (projectedTransform && !ignoreTransforms && updated) {\n      const projected = applyTransform(\n        updated,\n        projectedTransform,\n        computedStyles.transformOrigin\n      );\n\n      top = projected.top;\n      left = projected.left;\n      width = projected.width;\n      height = projected.height;\n      scale.x = projectedTransform.scaleX;\n      scale.y = projectedTransform.scaleY;\n    }\n\n    if (frameTransform) {\n      if (!ignoreTransforms) {\n        left *= frameTransform.scaleX;\n        width *= frameTransform.scaleX;\n        top *= frameTransform.scaleY;\n        height *= frameTransform.scaleY;\n      }\n\n      left += frameTransform.x;\n      top += frameTransform.y;\n    }\n\n    super(left, top, width, height);\n\n    this.scale = scale;\n    this.intrinsicWidth = intrinsic.width;\n    this.intrinsicHeight = intrinsic.height;\n  }\n\n  public intrinsicWidth: number;\n  public intrinsicHeight: number;\n}\n\n/*\n * Get the projected transform of an element based on the final keyframes\n * of its running animations.\n *\n * Uses last-wins-per-property semantics: for each CSS property (transform,\n * translate, scale), the value from the highest composite-order animation\n * wins. This correctly handles overlapping animations with the default\n * `composite: 'replace'` mode.\n *\n * `element.getAnimations()` returns animations sorted by composite order\n * (oldest first), so iterating forward and overwriting gives us the\n * effective final value for each property.\n *\n * @see https://drafts.csswg.org/web-animations-1/#dom-animatable-getanimations\n * @see https://drafts.csswg.org/css-animations-2/#animation-composite-order\n * @see https://developer.mozilla.org/en-US/docs/Web/CSS/animation-composition\n */\nfunction getProjectedTransform(\n  element: Element,\n  computedStyles: CSSStyleDeclaration\n): Transform | null {\n  const animations = element.getAnimations();\n\n  if (!animations.length) return null;\n\n  let latestTransform: string | undefined;\n  let latestTranslate: string | undefined;\n  let latestScale: string | undefined;\n  let hasAnimatedProperty = false;\n\n  for (const animation of animations) {\n    if (animation.playState !== 'running') continue;\n\n    const keyframes = isKeyframeEffect(animation.effect)\n      ? animation.effect.getKeyframes()\n      : [];\n    const keyframe = keyframes[keyframes.length - 1];\n\n    if (!keyframe) continue;\n\n    const {transform, translate, scale} = keyframe;\n\n    if (typeof transform === 'string' && transform) {\n      latestTransform = transform;\n      hasAnimatedProperty = true;\n    }\n\n    if (typeof translate === 'string' && translate) {\n      latestTranslate = translate;\n      hasAnimatedProperty = true;\n    }\n\n    if (typeof scale === 'string' && scale) {\n      latestScale = scale;\n      hasAnimatedProperty = true;\n    }\n  }\n\n  if (!hasAnimatedProperty) return null;\n\n  return parseTransform({\n    transform: latestTransform ?? computedStyles.transform,\n    translate: latestTranslate ?? computedStyles.translate,\n    scale: latestScale ?? computedStyles.scale,\n  });\n}\n"
  },
  {
    "path": "packages/dom/src/utilities/shapes/index.ts",
    "content": "export {DOMRectangle} from './DOMRectangle.ts';\nexport type {DOMRectangleOptions} from './DOMRectangle.ts';\n"
  },
  {
    "path": "packages/dom/src/utilities/styles/Styles.ts",
    "content": "import {supportsStyle} from '../type-guards/supportsStyle.ts';\n\ntype ExtractStringProperties<T> = {\n  [K in keyof T]?: T[K] extends string ? string : never;\n};\n\nexport type StyleDeclaration = ExtractStringProperties<CSSStyleDeclaration> & {\n  viewTransitionName?: string;\n};\n\nexport class Styles {\n  private initial = new Map<string, string>();\n\n  constructor(private element: Element) {}\n\n  public set(properties: Record<string, string | number>, prefix = '') {\n    const {element} = this;\n\n    if (!supportsStyle(element)) {\n      return;\n    }\n\n    for (const [key, value] of Object.entries(properties)) {\n      const property = `${prefix}${key}`;\n\n      if (!this.initial.has(property)) {\n        this.initial.set(property, element.style.getPropertyValue(property));\n      }\n\n      element.style.setProperty(\n        property,\n        typeof value === 'string' ? value : `${value}px`\n      );\n    }\n  }\n\n  public remove(properties: string[], prefix = '') {\n    const {element} = this;\n\n    if (!supportsStyle(element)) {\n      return;\n    }\n\n    for (const key of properties) {\n      const property = `${prefix}${key}`;\n\n      element.style.removeProperty(property);\n    }\n  }\n\n  public reset() {\n    const {element} = this;\n\n    if (!supportsStyle(element)) {\n      return;\n    }\n\n    for (const [key, value] of this.initial) {\n      element.style.setProperty(key, value);\n    }\n\n    if (element.getAttribute('style') === '') {\n      element.removeAttribute('style');\n    }\n  }\n}\n"
  },
  {
    "path": "packages/dom/src/utilities/styles/getComputedStyles.ts",
    "content": "import {getWindow} from '../execution-context/getWindow.ts';\nimport {Scheduler} from '../scheduling/scheduler.ts';\n\nconst scheduler = new Scheduler((callback) => setTimeout(callback, 50));\nconst cachedStyles = new Map<Element, CSSStyleDeclaration>();\nconst clear = cachedStyles.clear.bind(cachedStyles);\n\n/**\n * Get the computed styles for an element.\n * @param element - The element to get the computed styles for.\n * @param cached - Whether to cache the computed styles.\n * @returns The computed styles for the element.\n */\nexport function getComputedStyles(\n  element: Element,\n  cached = false\n): CSSStyleDeclaration {\n  if (!cached) return computeStyles(element);\n\n  let styles = cachedStyles.get(element);\n\n  if (styles) return styles;\n\n  styles = computeStyles(element);\n  cachedStyles.set(element, styles);\n  scheduler.schedule(clear);\n\n  return styles;\n}\n\nfunction computeStyles(element: Element): CSSStyleDeclaration {\n  return getWindow(element).getComputedStyle(element);\n}\n"
  },
  {
    "path": "packages/dom/src/utilities/styles/index.ts",
    "content": "export {Styles} from './Styles.ts';\nexport {getComputedStyles} from './getComputedStyles.ts';\n"
  },
  {
    "path": "packages/dom/src/utilities/transform/animateTransform.ts",
    "content": "interface Arguments {\n  element: Element;\n  keyframes: PropertyIndexedKeyframes | Keyframe[];\n  options: KeyframeAnimationOptions;\n}\n\nexport function animateTransform({element, keyframes, options}: Arguments) {\n  return element.animate(keyframes, options).finished;\n}\n"
  },
  {
    "path": "packages/dom/src/utilities/transform/applyTransform.ts",
    "content": "import type {BoundingRectangle} from '@dnd-kit/geometry';\n\nimport {type Transform} from './parseTransform.ts';\n\nexport function applyTransform(\n  rect: BoundingRectangle,\n  parsedTransform: Transform,\n  transformOrigin: string\n): BoundingRectangle {\n  const {scaleX, scaleY, x: translateX, y: translateY} = parsedTransform;\n  const x = rect.left + translateX + (1 - scaleX) * parseFloat(transformOrigin);\n  const y =\n    rect.top +\n    translateY +\n    (1 - scaleY) *\n      parseFloat(transformOrigin.slice(transformOrigin.indexOf(' ') + 1));\n  const w = scaleX ? rect.width * scaleX : rect.width;\n  const h = scaleY ? rect.height * scaleY : rect.height;\n\n  return {\n    width: w,\n    height: h,\n    top: y,\n    right: x + w,\n    bottom: y + h,\n    left: x,\n  };\n}\n"
  },
  {
    "path": "packages/dom/src/utilities/transform/computeTranslate.ts",
    "content": "import {getFinalKeyframe} from '../animations/getFinalKeyframe.ts';\nimport {getComputedStyles} from '../styles/getComputedStyles.ts';\n\nimport {parseTranslate} from './parseTranslate.ts';\n\nexport function computeTranslate(\n  element: Element,\n  translate = getComputedStyles(element).translate,\n  projected = true\n): {\n  x: number;\n  y: number;\n  z: number;\n} {\n  if (projected) {\n    const keyframe = getFinalKeyframe(\n      element,\n      (keyframe) => 'translate' in keyframe\n    );\n\n    if (keyframe) {\n      const {translate = ''} = keyframe[0];\n\n      if (typeof translate === 'string') {\n        const finalTranslate = parseTranslate(translate);\n\n        if (finalTranslate) {\n          return finalTranslate;\n        }\n      }\n    }\n  }\n\n  if (translate) {\n    const finalTranslate = parseTranslate(translate);\n\n    if (finalTranslate) {\n      return finalTranslate;\n    }\n  }\n\n  return {x: 0, y: 0, z: 0};\n}\n"
  },
  {
    "path": "packages/dom/src/utilities/transform/index.ts",
    "content": "export {animateTransform} from './animateTransform.ts';\nexport {computeTranslate} from './computeTranslate.ts';\nexport {inverseTransform} from './inverseTransform.ts';\nexport {parseTransform} from './parseTransform.ts';\nexport {parseTranslate} from './parseTranslate.ts';\nexport type {Transform} from './parseTransform.ts';\n"
  },
  {
    "path": "packages/dom/src/utilities/transform/inverseTransform.ts",
    "content": "import type {BoundingRectangle} from '@dnd-kit/geometry';\n\nimport {type Transform} from './parseTransform.ts';\n\nexport function inverseTransform(\n  rect: BoundingRectangle,\n  parsedTransform: Transform,\n  transformOrigin: string\n): BoundingRectangle {\n  const {scaleX, scaleY, x: translateX, y: translateY} = parsedTransform;\n  const x = rect.left - translateX - (1 - scaleX) * parseFloat(transformOrigin);\n  const y =\n    rect.top -\n    translateY -\n    (1 - scaleY) *\n      parseFloat(transformOrigin.slice(transformOrigin.indexOf(' ') + 1));\n  const w = scaleX ? rect.width / scaleX : rect.width;\n  const h = scaleY ? rect.height / scaleY : rect.height;\n\n  return {\n    width: w,\n    height: h,\n    top: y,\n    right: x + w,\n    bottom: y + h,\n    left: x,\n  };\n}\n"
  },
  {
    "path": "packages/dom/src/utilities/transform/parseScale.ts",
    "content": "export function parseScale(scale: string) {\n  if (scale === 'none') {\n    return null;\n  }\n\n  const values = scale.split(' ');\n  const x = parseFloat(values[0]);\n  const y = parseFloat(values[1]);\n\n  if (isNaN(x) && isNaN(y)) {\n    return null;\n  }\n\n  return {\n    x: isNaN(x) ? y : x,\n    y: isNaN(y) ? x : y,\n  };\n}\n"
  },
  {
    "path": "packages/dom/src/utilities/transform/parseTransform.ts",
    "content": "import type {Coordinates} from '@dnd-kit/geometry';\n\nimport {parseScale} from './parseScale.ts';\nimport {parseTranslate} from './parseTranslate.ts';\n\nexport interface Transform extends Coordinates {\n  z?: number;\n  scaleX: number;\n  scaleY: number;\n}\n\nexport function parseTransform(computedStyles: {\n  scale: string;\n  transform: string;\n  translate: string;\n}): Transform | null {\n  const {scale, transform, translate} = computedStyles;\n  const parsedScale = parseScale(scale);\n  const parsedTranslate = parseTranslate(translate);\n  const parsedMatrix = parseTransformMatrix(transform);\n\n  if (!parsedMatrix && !parsedScale && !parsedTranslate) {\n    return null;\n  }\n\n  const normalizedScale = {\n    x: parsedScale?.x ?? 1,\n    y: parsedScale?.y ?? 1,\n  };\n\n  const normalizedTranslate = {\n    x: parsedTranslate?.x ?? 0,\n    y: parsedTranslate?.y ?? 0,\n  };\n\n  const normalizedMatrix = {\n    x: parsedMatrix?.x ?? 0,\n    y: parsedMatrix?.y ?? 0,\n    scaleX: parsedMatrix?.scaleX ?? 1,\n    scaleY: parsedMatrix?.scaleY ?? 1,\n  };\n\n  return {\n    x: normalizedTranslate.x + normalizedMatrix.x,\n    y: normalizedTranslate.y + normalizedMatrix.y,\n    z: parsedTranslate?.z ?? 0,\n    scaleX: normalizedScale.x * normalizedMatrix.scaleX,\n    scaleY: normalizedScale.y * normalizedMatrix.scaleY,\n  };\n}\n\nfunction parseTransformMatrix(transform: string) {\n  if (transform.startsWith('matrix3d(')) {\n    const transformArray = transform.slice(9, -1).split(/, /);\n\n    return {\n      x: +transformArray[12],\n      y: +transformArray[13],\n      scaleX: +transformArray[0],\n      scaleY: +transformArray[5],\n    };\n  } else if (transform.startsWith('matrix(')) {\n    const transformArray = transform.slice(7, -1).split(/, /);\n\n    return {\n      x: +transformArray[4],\n      y: +transformArray[5],\n      scaleX: +transformArray[0],\n      scaleY: +transformArray[3],\n    };\n  }\n\n  return null;\n}\n"
  },
  {
    "path": "packages/dom/src/utilities/transform/parseTranslate.ts",
    "content": "export function parseTranslate(translate: string) {\n  if (translate === 'none') {\n    return null;\n  }\n\n  const [x, y, z = '0'] = translate.split(' ');\n  const output = {x: parseFloat(x), y: parseFloat(y), z: parseInt(z, 10)};\n\n  if (isNaN(output.x) && isNaN(output.y)) {\n    return null;\n  }\n\n  return {\n    x: isNaN(output.x) ? 0 : output.x,\n    y: isNaN(output.y) ? 0 : output.y,\n    z: isNaN(output.z) ? 0 : output.z,\n  };\n}\n"
  },
  {
    "path": "packages/dom/src/utilities/type-guards/index.ts",
    "content": "export {isDocument} from './isDocument.ts';\nexport {isElement} from './isElement.ts';\nexport {isHTMLElement} from './isHTMLElement.ts';\nexport {isKeyframeEffect} from './isKeyframeEffect.ts';\nexport {isKeyboardEvent} from './isKeyboardEvent.ts';\nexport {isPointerEvent} from './isPointerEvent.ts';\nexport {isNode} from './isNode.ts';\nexport {isSVGElement} from './isSVGElement.ts';\nexport {isWindow} from './isWindow.ts';\nexport {isShadowRoot} from './isShadowRoot.ts'\nexport {supportsViewTransition} from './supportsViewTransition.ts';\nexport {supportsStyle} from './supportsStyle.ts';\n"
  },
  {
    "path": "packages/dom/src/utilities/type-guards/isDocument.ts",
    "content": "import {getWindow} from '../execution-context/getWindow.ts';\n\nexport function isDocument(node: Node): node is Document {\n  const {Document} = getWindow(node);\n\n  return (\n    node instanceof Document ||\n    ('nodeType' in node && node.nodeType === Node.DOCUMENT_NODE)\n  );\n}\n"
  },
  {
    "path": "packages/dom/src/utilities/type-guards/isElement.ts",
    "content": "import {getWindow} from '../execution-context/getWindow.ts';\nimport {isNode} from './isNode.ts';\n\nexport function isElement(target: EventTarget | null): target is Element {\n  if (!target) return false;\n\n  return (\n    target instanceof getWindow(target).Element ||\n    (isNode(target) && target.nodeType === Node.ELEMENT_NODE)\n  );\n}\n"
  },
  {
    "path": "packages/dom/src/utilities/type-guards/isHTMLElement.ts",
    "content": "import {getWindow} from '../execution-context/getWindow.ts';\n\nimport {isWindow} from './isWindow.ts';\n\nexport function isHTMLElement(\n  node: Node | Window | null | undefined\n): node is HTMLElement {\n  if (!node || isWindow(node)) return false;\n\n  return (\n    node instanceof getWindow(node).HTMLElement ||\n    ('namespaceURI' in node &&\n      typeof node.namespaceURI === 'string' &&\n      node.namespaceURI.endsWith('html'))\n  );\n}\n"
  },
  {
    "path": "packages/dom/src/utilities/type-guards/isHTMLTableRowElement.ts",
    "content": "export function isHTMLTableRowElement(\n  element: Element\n): element is HTMLTableRowElement {\n  return element.tagName === 'TR';\n}\n"
  },
  {
    "path": "packages/dom/src/utilities/type-guards/isKeyboardEvent.ts",
    "content": "import {getWindow} from '../execution-context/getWindow.ts';\n\nexport function isKeyboardEvent(\n  event: Event | null | undefined\n): event is KeyboardEvent {\n  if (!event) return false;\n\n  const {KeyboardEvent} = getWindow(event.target);\n\n  return event instanceof KeyboardEvent;\n}\n"
  },
  {
    "path": "packages/dom/src/utilities/type-guards/isKeyframeEffect.ts",
    "content": "export function isKeyframeEffect(\n  effect: AnimationEffect | null | undefined\n): effect is KeyframeEffect {\n  if (!effect) return false;\n\n  if (effect instanceof KeyframeEffect) return true;\n\n  return 'getKeyframes' in effect && typeof effect.getKeyframes === 'function';\n}\n"
  },
  {
    "path": "packages/dom/src/utilities/type-guards/isNode.ts",
    "content": "export function isNode(node: Object): node is Node {\n  return 'nodeType' in node;\n}\n"
  },
  {
    "path": "packages/dom/src/utilities/type-guards/isPointerEvent.ts",
    "content": "import {getWindow} from '../execution-context/getWindow.ts';\n\nexport function isPointerEvent(\n  event: Event | null | undefined\n): event is PointerEvent {\n  if (!event) return false;\n\n  const {PointerEvent} = getWindow(event.target);\n\n  return event instanceof PointerEvent;\n}\n"
  },
  {
    "path": "packages/dom/src/utilities/type-guards/isSVGElement.ts",
    "content": "import {getWindow} from '../execution-context/getWindow.ts';\n\nexport function isSVGElement(node: Node): node is SVGElement {\n  return (\n    node instanceof getWindow(node).SVGElement ||\n    ('namespaceURI' in node &&\n      typeof node.namespaceURI === 'string' &&\n      node.namespaceURI.endsWith('svg'))\n  );\n}\n"
  },
  {
    "path": "packages/dom/src/utilities/type-guards/isShadowRoot.ts",
    "content": "import {getWindow} from '../execution-context/getWindow.ts';\nimport {isNode} from './isNode.ts';\n\nexport function isShadowRoot(target: EventTarget | null): target is ShadowRoot {\n  if (!target || !isNode(target)) return false;\n  return target instanceof getWindow(target).ShadowRoot;\n}\n"
  },
  {
    "path": "packages/dom/src/utilities/type-guards/isTextInput.ts",
    "content": "import {isElement} from './isElement.js';\n\nexport function isTextInput(target: EventTarget | null) {\n  if (!isElement(target)) return false;\n\n  const {tagName} = target;\n\n  return (\n    tagName === 'INPUT' || tagName === 'TEXTAREA' || isContentEditable(target)\n  );\n}\n\nfunction isContentEditable(element: Element) {\n  return (\n    element.hasAttribute('contenteditable') &&\n    element.getAttribute('contenteditable') !== 'false'\n  );\n}\n"
  },
  {
    "path": "packages/dom/src/utilities/type-guards/isWindow.ts",
    "content": "export function isWindow(element: Object): element is typeof window {\n  const elementString = Object.prototype.toString.call(element);\n  return (\n    elementString === '[object Window]' ||\n    // In Electron context the Window object serializes to [object global]\n    elementString === '[object global]'\n  );\n}\n"
  },
  {
    "path": "packages/dom/src/utilities/type-guards/supportsStyle.ts",
    "content": "export function supportsStyle(\n  element: Element\n): element is Element & {style: CSSStyleDeclaration} {\n  return (\n    'style' in element &&\n    typeof element.style === 'object' &&\n    element.style !== null &&\n    'setProperty' in element.style &&\n    'removeProperty' in element.style &&\n    typeof element.style.setProperty === 'function' &&\n    typeof element.style.removeProperty === 'function'\n  );\n}\n"
  },
  {
    "path": "packages/dom/src/utilities/type-guards/supportsViewTransition.ts",
    "content": "interface ViewTransition {\n  ready: Promise<void>;\n  updateCallbackDone: Promise<void>;\n  finished: Promise<void>;\n  skipTransition(): void;\n}\n\nexport function supportsViewTransition(\n  document: Document\n): document is Document & {\n  startViewTransition(updateCallback: () => void): ViewTransition;\n} {\n  return 'startViewTransition' in document;\n}\n"
  },
  {
    "path": "packages/dom/tests/pointer-sensor.test.ts",
    "content": "import {describe, expect, it, jest} from 'bun:test';\nimport {ActivationController} from '@dnd-kit/abstract';\n\nimport {DelayConstraint} from '../src/core/sensors/pointer/DelayConstraint.ts';\n\nfunction createPointerEvent(\n  type: string,\n  options: Partial<PointerEvent> = {}\n): PointerEvent {\n  return {\n    type,\n    pointerId: 1,\n    clientX: 0,\n    clientY: 0,\n    ...options,\n  } as unknown as PointerEvent;\n}\n\ndescribe('ActivationController with DelayConstraint', () => {\n  it('should activate after the delay elapses', async () => {\n    const onActivate = jest.fn();\n    const constraint = new DelayConstraint({value: 50, tolerance: 5});\n    const controller = new ActivationController([constraint], onActivate);\n\n    controller.onEvent(createPointerEvent('pointerdown'));\n\n    expect(onActivate).not.toHaveBeenCalled();\n\n    await new Promise((resolve) => setTimeout(resolve, 80));\n\n    expect(onActivate).toHaveBeenCalledTimes(1);\n  });\n\n  it('should cancel pending activation when the controller is aborted', async () => {\n    const onActivate = jest.fn();\n    const constraint = new DelayConstraint({value: 50, tolerance: 5});\n    const controller = new ActivationController([constraint], onActivate);\n\n    controller.onEvent(createPointerEvent('pointerdown'));\n\n    expect(onActivate).not.toHaveBeenCalled();\n\n    controller.abort();\n\n    await new Promise((resolve) => setTimeout(resolve, 80));\n\n    expect(onActivate).not.toHaveBeenCalled();\n    expect(controller.signal.aborted).toBe(true);\n  });\n\n  it('should not activate if aborted just before the delay elapses', async () => {\n    const onActivate = jest.fn();\n    const constraint = new DelayConstraint({value: 50, tolerance: 5});\n    const controller = new ActivationController([constraint], onActivate);\n\n    controller.onEvent(createPointerEvent('pointerdown'));\n\n    await new Promise((resolve) => setTimeout(resolve, 40));\n\n    expect(onActivate).not.toHaveBeenCalled();\n\n    controller.abort();\n\n    await new Promise((resolve) => setTimeout(resolve, 30));\n\n    expect(onActivate).not.toHaveBeenCalled();\n  });\n\n  it('should cancel activation when pointerup arrives before the delay', async () => {\n    const onActivate = jest.fn();\n    const constraint = new DelayConstraint({value: 100, tolerance: 5});\n    const controller = new ActivationController([constraint], onActivate);\n\n    controller.onEvent(createPointerEvent('pointerdown'));\n    controller.onEvent(createPointerEvent('pointerup'));\n\n    await new Promise((resolve) => setTimeout(resolve, 150));\n\n    expect(onActivate).not.toHaveBeenCalled();\n  });\n});\n"
  },
  {
    "path": "packages/dom/tests/sortable-utilities.test.ts",
    "content": "import {describe, expect, it} from 'bun:test';\n\nimport {Draggable, Droppable} from '@dnd-kit/dom';\nimport {\n  Sortable,\n  SortableDraggable,\n  SortableDroppable,\n  isSortable,\n  isSortableOperation,\n} from '@dnd-kit/dom/sortable';\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction createSortable(id: string | number, index: number, group?: string) {\n  const sortable = new Sortable(\n    {id, index, group, plugins: [], transition: null},\n    undefined\n  );\n  return sortable;\n}\n\nfunction createDraggable(id: string | number) {\n  return new Draggable({id}, undefined);\n}\n\nfunction createDroppable(id: string | number) {\n  return new Droppable({id}, undefined);\n}\n\nfunction mockOperation(\n  source: any,\n  target: any\n): {source: any; target: any; canceled: boolean} {\n  return {source, target, canceled: false};\n}\n\n// ---------------------------------------------------------------------------\n// isSortable\n// ---------------------------------------------------------------------------\n\ndescribe('isSortable', () => {\n  it('should return true for a SortableDraggable', () => {\n    const sortable = createSortable('s1', 0);\n    expect(isSortable(sortable.draggable)).toBe(true);\n    expect(sortable.draggable).toBeInstanceOf(SortableDraggable);\n  });\n\n  it('should return true for a SortableDroppable', () => {\n    const sortable = createSortable('s1', 0);\n    expect(isSortable(sortable.droppable)).toBe(true);\n    expect(sortable.droppable).toBeInstanceOf(SortableDroppable);\n  });\n\n  it('should return false for a plain Draggable', () => {\n    const draggable = createDraggable('d1');\n    expect(isSortable(draggable)).toBe(false);\n  });\n\n  it('should return false for a plain Droppable', () => {\n    const droppable = createDroppable('d1');\n    expect(isSortable(droppable)).toBe(false);\n  });\n\n  it('should return false for null', () => {\n    expect(isSortable(null)).toBe(false);\n  });\n});\n\n// ---------------------------------------------------------------------------\n// isSortableOperation\n// ---------------------------------------------------------------------------\n\ndescribe('isSortableOperation', () => {\n  it('should return true when source and target are both sortable', () => {\n    const s1 = createSortable('s1', 0);\n    const s2 = createSortable('s2', 1);\n    const op = mockOperation(s1.draggable, s2.droppable);\n    expect(isSortableOperation(op)).toBe(true);\n  });\n\n  it('should return false when source is a plain Draggable', () => {\n    const draggable = createDraggable('d1');\n    const sortable = createSortable('s1', 0);\n    const op = mockOperation(draggable, sortable.droppable);\n    expect(isSortableOperation(op)).toBe(false);\n  });\n\n  it('should return false when target is a plain Droppable', () => {\n    const sortable = createSortable('s1', 0);\n    const droppable = createDroppable('d1');\n    const op = mockOperation(sortable.draggable, droppable);\n    expect(isSortableOperation(op)).toBe(false);\n  });\n\n  it('should return false when source is null', () => {\n    const sortable = createSortable('s1', 0);\n    const op = mockOperation(null, sortable.droppable);\n    expect(isSortableOperation(op)).toBe(false);\n  });\n\n  it('should return false when target is null', () => {\n    const sortable = createSortable('s1', 0);\n    const op = mockOperation(sortable.draggable, null);\n    expect(isSortableOperation(op)).toBe(false);\n  });\n\n  it('should return false when both are null', () => {\n    const op = mockOperation(null, null);\n    expect(isSortableOperation(op)).toBe(false);\n  });\n\n  it('should return false when both are plain (non-sortable)', () => {\n    const draggable = createDraggable('d1');\n    const droppable = createDroppable('d2');\n    const op = mockOperation(draggable, droppable);\n    expect(isSortableOperation(op)).toBe(false);\n  });\n\n  it('should narrow types to expose sortable properties on source', () => {\n    const s1 = createSortable('s1', 2, 'groupA');\n    const s2 = createSortable('s2', 5, 'groupA');\n    const op = mockOperation(s1.draggable, s2.droppable);\n\n    if (isSortableOperation(op)) {\n      expect(op.source!.index).toBe(2);\n      expect(op.source!.initialIndex).toBe(2);\n      expect(op.source!.group).toBe('groupA');\n      expect(op.source!.initialGroup).toBe('groupA');\n      expect(op.target!.index).toBe(5);\n      expect(op.target!.group).toBe('groupA');\n    } else {\n      throw new Error('Expected isSortableOperation to return true');\n    }\n  });\n});\n"
  },
  {
    "path": "packages/dom/tsconfig.json",
    "content": "{\n  \"extends\": \"../../config/typescript/vanilla.json\",\n  \"include\": [\"src/**/*\"],\n  \"exclude\": [\"dist\", \"build\", \"node_modules\"],\n}\n"
  },
  {
    "path": "packages/dom/tsup.config.ts",
    "content": "import {defineConfig} from 'tsup';\n\nexport default defineConfig((options) => ({\n  dts: true,\n  outDir: './',\n  external: [\n    '@dnd-kit/abstract',\n    '@dnd-kit/dom',\n    '@dnd-kit/state',\n    '@dnd-kit/geometry',\n    '@dnd-kit/collision',\n  ],\n  format: ['esm', 'cjs'],\n  loader: {\n    '.css': 'text',\n  },\n  sourcemap: true,\n  treeshake: !options.watch,\n}));\n"
  },
  {
    "path": "packages/eslint-config/README.md",
    "content": "# `@dnd-kit/eslint-config`\n\nCollection of internal eslint configurations.\n"
  },
  {
    "path": "packages/eslint-config/package.json",
    "content": "{\n  \"name\": \"@dnd-kit/eslint-config\",\n  \"version\": \"0.0.0\",\n  \"private\": true,\n  \"files\": [\n    \"vanilla.js\",\n    \"react.js\",\n    \"storybook.js\"\n  ],\n  \"devDependencies\": {\n    \"@vercel/style-guide\": \"^5.1.0\",\n    \"eslint-config-turbo\": \"^1.11.3\",\n    \"eslint-plugin-mdx\": \"^2.3.2\",\n    \"eslint-plugin-only-warn\": \"^1.1.0\",\n    \"eslint-plugin-storybook\": \"^0.6.15\"\n  }\n}\n"
  },
  {
    "path": "packages/geometry/CHANGELOG.md",
    "content": "# @dnd-kit/geometry\n\n## 0.3.2\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/state@0.3.2\n\n## 0.3.1\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/state@0.3.1\n\n## 0.3.0\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/state@0.3.0\n\n## 0.2.4\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/state@0.2.4\n\n## 0.2.3\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/state@0.2.3\n\n## 0.2.2\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/state@0.2.2\n\n## 0.2.1\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/state@0.2.1\n\n## 0.2.0\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/state@0.2.0\n\n## 0.1.21\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/state@0.1.21\n\n## 0.1.20\n\n### Patch Changes\n\n- Updated dependencies [[`98d4cd4`](https://github.com/clauderic/dnd-kit/commit/98d4cd4047c56589cdf21067526426717bba01c4), [`32448ff`](https://github.com/clauderic/dnd-kit/commit/32448ff11eb3e86a28fc8f6ef7a8a3761e092412)]:\n  - @dnd-kit/state@0.1.20\n\n## 0.1.19\n\n### Patch Changes\n\n- Updated dependencies [[`d848327`](https://github.com/clauderic/dnd-kit/commit/d848327b242c6714b36207071ad30e6b4183e865)]:\n  - @dnd-kit/state@0.1.19\n\n## 0.1.18\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/state@0.1.18\n\n## 0.1.17\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/state@0.1.17\n\n## 0.1.16\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/state@0.1.16\n\n## 0.1.15\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/state@0.1.15\n\n## 0.1.14\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/state@0.1.14\n\n## 0.1.13\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/state@0.1.13\n\n## 0.1.12\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/state@0.1.12\n\n## 0.1.11\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/state@0.1.11\n\n## 0.1.10\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/state@0.1.10\n\n## 0.1.9\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/state@0.1.9\n\n## 0.1.8\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/state@0.1.8\n\n## 0.1.7\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/state@0.1.7\n\n## 0.1.6\n\n### Patch Changes\n\n- Updated dependencies [[`299389b`](https://github.com/clauderic/dnd-kit/commit/299389befcc747fe8d79231ba32f73afae88615e)]:\n  - @dnd-kit/state@0.1.6\n\n## 0.1.5\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/state@0.1.5\n\n## 0.1.4\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/state@0.1.4\n\n## 0.1.3\n\n### Patch Changes\n\n- [#1663](https://github.com/clauderic/dnd-kit/pull/1663) [`2522836`](https://github.com/clauderic/dnd-kit/commit/2522836fdb80520913ea35d94c6558bf7784afc9) Thanks [@github-actions](https://github.com/apps/github-actions)! - **Position**: Changed `velocity` to no longer be reactive as it is derived.\n\n- Updated dependencies [[`8f91d91`](https://github.com/clauderic/dnd-kit/commit/8f91d9112608d2077c3b6c8fc939aa052606148c), [`9a0edf6`](https://github.com/clauderic/dnd-kit/commit/9a0edf64cbde1bd761f3650e043b6612e61a5fab), [`a9db4c7`](https://github.com/clauderic/dnd-kit/commit/a9db4c73467d9eda9f95fe5b582948c9fc735f57)]:\n  - @dnd-kit/state@0.1.3\n\n## 0.1.2\n\n### Patch Changes\n\n- [#1658](https://github.com/clauderic/dnd-kit/pull/1658) [`ee55f58`](https://github.com/clauderic/dnd-kit/commit/ee55f582f92dc42cc6eea9ad7492fc782ca6455a) Thanks [@github-actions](https://github.com/apps/github-actions)! - Add new state management features:\n\n  - Add `ValueHistory` class for tracking value changes over time\n  - Add `enumerable` decorator for controlling property enumeration\n  - Add `snapshot` utility for creating immutable copies of reactive objects\n  - Refactor `Position` class to extend `ValueHistory` for better state tracking\n\n- Updated dependencies [[`ee55f58`](https://github.com/clauderic/dnd-kit/commit/ee55f582f92dc42cc6eea9ad7492fc782ca6455a)]:\n  - @dnd-kit/state@0.1.2\n\n## 0.1.1\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/state@0.1.1\n\n## 0.1.0\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/state@0.1.0\n\n## 0.0.10\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/state@0.0.10\n\n## 0.0.9\n\n### Patch Changes\n\n- [#1600](https://github.com/clauderic/dnd-kit/pull/1600) [`60e7297`](https://github.com/clauderic/dnd-kit/commit/60e72979850bfe4cbb8e2b2e2b8e84bce9edc9f5) Thanks [@github-actions](https://github.com/apps/github-actions)! - Added `aspectRatio` property to `Shape` interface.\n\n- [#1600](https://github.com/clauderic/dnd-kit/pull/1600) [`8ae7014`](https://github.com/clauderic/dnd-kit/commit/8ae70143bc404bff7678fa8e8390a640c16f2579) Thanks [@github-actions](https://github.com/apps/github-actions)! - - Added `corners` getter to `Rectangle` instances to retrieve the coordinates of all four corners.\n  - Added `delta` static method to the `Rectangle` constructor which makes it easy to calculate the delta between a given reference point of both shapes.\n- Updated dependencies []:\n  - @dnd-kit/state@0.0.9\n\n## 0.0.8\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/state@0.0.8\n\n## 0.0.7\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/state@0.0.7\n\n## 0.0.6\n\n### Patch Changes\n\n- [#1567](https://github.com/clauderic/dnd-kit/pull/1567) [`081b7f2`](https://github.com/clauderic/dnd-kit/commit/081b7f2a11da2aad8ce3da7f0579974415d1fdf0) Thanks [@chrisvxd](https://github.com/chrisvxd)! - Add source maps to output.\n\n- [#1454](https://github.com/clauderic/dnd-kit/pull/1454) [`71dc39f`](https://github.com/clauderic/dnd-kit/commit/71dc39fb2ec21b9a680238a91be419c71ecabe86) Thanks [@github-actions](https://github.com/apps/github-actions)! - Added `velocity` property on `Position` interface to track the current velocity of position updates in the `x` and `y` axis.\n\n- Updated dependencies [[`081b7f2`](https://github.com/clauderic/dnd-kit/commit/081b7f2a11da2aad8ce3da7f0579974415d1fdf0), [`b750c05`](https://github.com/clauderic/dnd-kit/commit/b750c05b4b14f5d9817dc07d974d40b74470e904)]:\n  - @dnd-kit/state@0.0.6\n\n## 0.0.5\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/state@0.0.5\n\n## 0.0.4\n\n### Patch Changes\n\n- Updated dependencies [[`a4d9150`](https://github.com/clauderic/dnd-kit/commit/a4d91500124698abf58355592913f84d438faa3d)]:\n  - @dnd-kit/state@0.0.4\n\n## 0.0.3\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/state@0.0.3\n\n## 0.0.2\n\n### Patch Changes\n\n- Updated dependencies [[`6c84308`](https://github.com/clauderic/dnd-kit/commit/6c84308b45c55ca1324a5c752b0ec117235da9e2)]:\n  - @dnd-kit/state@0.0.2\n"
  },
  {
    "path": "packages/geometry/README.md",
    "content": "# @dnd-kit/geometry\n\n[![Stable release](https://img.shields.io/npm/v/@dnd-kit/geometry.svg)](https://npm.im/@dnd-kit/geometry)\n\nGeometry types and utilities for **@dnd-kit**. Provides the spatial primitives used by collision detection, shape tracking, and coordinate calculations.\n\n> **Note:** This is an internal package used by `@dnd-kit/abstract` and `@dnd-kit/dom`. You generally don't need to install or use it directly.\n\n## Overview\n\n### Types\n\n- `Shape`, `Rectangle`, `BoundingRectangle` — Geometric shapes\n- `Point`, `Position`, `Coordinates` — Spatial positioning\n- `Distance`, `Axis`, `Axes`, `Alignment` — Measurement and layout\n\n### Utilities\n\n- `exceedsDistance(delta, distance)` — Check if a movement vector exceeds a threshold distance\n"
  },
  {
    "path": "packages/geometry/package.json",
    "content": "{\n  \"name\": \"@dnd-kit/geometry\",\n  \"version\": \"0.3.2\",\n  \"main\": \"./dist/index.js\",\n  \"module\": \"./dist/index.mjs\",\n  \"types\": \"./dist/index.d.ts\",\n  \"sideEffects\": false,\n  \"license\": \"MIT\",\n  \"files\": [\n    \"dist/**\"\n  ],\n  \"scripts\": {\n    \"build\": \"tsup src/index.ts --format esm,cjs --dts --external react\",\n    \"dev\": \"tsup src/index.ts --format esm,cjs --watch --dts --external react\",\n    \"lint\": \"TIMING=1 eslint src/**/*.ts* --fix\",\n    \"clean\": \"rm -rf .turbo && rm -rf node_modules && rm -rf dist\"\n  },\n  \"dependencies\": {\n    \"@dnd-kit/state\": \"^0.3.2\",\n    \"tslib\": \"^2.6.2\"\n  },\n  \"devDependencies\": {\n    \"@dnd-kit/eslint-config\": \"*\",\n    \"eslint\": \"^8.38.0\",\n    \"tsup\": \"8.3.0\",\n    \"typescript\": \"^5.5.2\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/clauderic/dnd-kit\"\n  }\n}\n"
  },
  {
    "path": "packages/geometry/src/distance/distance.ts",
    "content": "import type {Coordinates} from '../types';\n\nimport type {Distance} from './types';\n\n/**\n * Returns true if a set of relative coordinates exceeds a given distance.\n */\nexport function exceedsDistance(\n  {x, y}: Coordinates,\n  distance: Distance\n): boolean {\n  const dx = Math.abs(x);\n  const dy = Math.abs(y);\n\n  if (typeof distance === 'number') {\n    return Math.sqrt(dx ** 2 + dy ** 2) > distance;\n  }\n\n  if ('x' in distance && 'y' in distance) {\n    return dx > distance.x && dy > distance.y;\n  }\n\n  if ('x' in distance) {\n    return dx > distance.x;\n  }\n\n  if ('y' in distance) {\n    return dy > distance.y;\n  }\n\n  return false;\n}\n"
  },
  {
    "path": "packages/geometry/src/distance/index.ts",
    "content": "export {exceedsDistance} from './distance';\n\nexport type {Distance} from './types';\n"
  },
  {
    "path": "packages/geometry/src/distance/types.ts",
    "content": "import type {Axis, Coordinates} from '../types';\n\nexport type Distance =\n  | number\n  | Coordinates\n  | Pick<Coordinates, Axis.Horizontal>\n  | Pick<Coordinates, Axis.Vertical>;\n"
  },
  {
    "path": "packages/geometry/src/index.ts",
    "content": "export type {Shape} from './shapes';\nexport {Rectangle} from './shapes';\n\nexport {Point} from './point';\n\nexport {Position} from './position';\n\nexport {exceedsDistance} from './distance';\nexport type {Distance} from './distance';\n\nexport {Axis, Axes} from './types';\nexport type {Alignment, Coordinates, BoundingRectangle} from './types';\n"
  },
  {
    "path": "packages/geometry/src/point/Point.ts",
    "content": "import type {Coordinates} from '../types';\n\n/**\n * A Point represents a location in a two-dimensional coordinate system.\n *\n */\nexport class Point implements Coordinates {\n  /**\n   * @param {number} Coordinate of the point on the horizontal axis\n   * @param {number} Coordinate of the point on the vertical axis\n   */\n  constructor(public x: number, public y: number) {}\n\n  /**\n   * Returns the delta between this point and another point.\n   *\n   * @param {Point} a - A point\n   * @param {Point} b - Another point\n   */\n  static delta(a: Point, b: Point): Point {\n    return new Point(a.x - b.x, a.y - b.y);\n  }\n\n  /**\n   * Returns the distance (hypotenuse) between this point and another point.\n   *\n   * @param {Point} a - A point\n   * @param {Point} b - Another point\n   */\n  static distance(a: Point, b: Point): number {\n    return Math.hypot(a.x - b.x, a.y - b.y);\n  }\n\n  /**\n   * Returns true if both points are equal.\n   *\n   * @param {Point} a - A point\n   * @param {Point} b - Another point\n   */\n  static equals(a: Point, b: Point): boolean {\n    return a.x === b.x && a.y === b.y;\n  }\n\n  static from({x, y}: Coordinates) {\n    return new Point(x, y);\n  }\n}\n"
  },
  {
    "path": "packages/geometry/src/point/index.ts",
    "content": "export {Point} from './Point';\n"
  },
  {
    "path": "packages/geometry/src/position/index.ts",
    "content": "export {Position} from './position';\n"
  },
  {
    "path": "packages/geometry/src/position/position.ts",
    "content": "import {batch, derived, ValueHistory} from '@dnd-kit/state';\n\nimport {Point} from '../point';\nimport type {Coordinates} from '../types';\n\nexport class Position extends ValueHistory<Point> {\n  constructor(initialValue: Coordinates) {\n    const point = Point.from(initialValue);\n\n    super(point, (a, b) => Point.equals(a, b));\n  }\n\n  #timestamp = 0;\n\n  public velocity: Point = {x: 0, y: 0};\n\n  @derived\n  public get delta() {\n    return Point.delta(this.current, this.initial);\n  }\n\n  @derived\n  public get direction() {\n    const {current, previous} = this;\n\n    if (!previous) return null;\n\n    const delta = {\n      x: current.x - previous.x,\n      y: current.y - previous.y,\n    };\n\n    if (!delta.x && !delta.y) {\n      return null;\n    }\n\n    if (Math.abs(delta.x) > Math.abs(delta.y)) {\n      return delta.x > 0 ? 'right' : 'left';\n    }\n\n    return delta.y > 0 ? 'down' : 'up';\n  }\n\n  public get current() {\n    return super.current;\n  }\n\n  public set current(coordinates: Coordinates) {\n    const {current} = this;\n    const point = Point.from(coordinates);\n\n    const delta = {\n      x: point.x - current.x,\n      y: point.y - current.y,\n    };\n    const timestamp = Date.now();\n    const timeDelta = timestamp - this.#timestamp;\n    const velocity = (delta: number) => Math.round((delta / timeDelta) * 100);\n\n    batch(() => {\n      this.#timestamp = timestamp;\n      this.velocity = {\n        x: velocity(delta.x),\n        y: velocity(delta.y),\n      };\n      super.current = point;\n    });\n  }\n\n  public reset(coordinates = this.defaultValue) {\n    super.reset(Point.from(coordinates));\n    this.velocity = {x: 0, y: 0};\n  }\n}\n"
  },
  {
    "path": "packages/geometry/src/shapes/Rectangle.ts",
    "content": "import {Point} from '../point';\nimport {Alignment, BoundingRectangle} from '../types';\n\nimport type {Shape} from './Shape';\n\nexport class Rectangle implements Shape {\n  constructor(\n    public left: number,\n    public top: number,\n    public width: number,\n    public height: number\n  ) {}\n\n  public scale = {\n    x: 1,\n    y: 1,\n  };\n\n  public get inverseScale() {\n    return {\n      x: 1 / this.scale.x,\n      y: 1 / this.scale.y,\n    };\n  }\n\n  public translate(x: number, y: number): Rectangle {\n    const {top, left, width, height, scale} = this;\n    const newShape = new Rectangle(left + x, top + y, width, height);\n    newShape.scale = {...scale};\n\n    return newShape;\n  }\n\n  public get boundingRectangle(): BoundingRectangle {\n    const {width, height, left, top, right, bottom} = this;\n\n    return {width, height, left, top, right, bottom};\n  }\n\n  public get center(): Point {\n    const {left, top, right, bottom} = this;\n\n    return new Point((left + right) / 2, (top + bottom) / 2);\n  }\n\n  public get area(): number {\n    const {width, height} = this;\n\n    return width * height;\n  }\n\n  public equals(shape: Shape): boolean {\n    if (!(shape instanceof Rectangle)) {\n      return false;\n    }\n\n    const {left, top, width, height} = this;\n\n    return (\n      left === shape.left &&\n      top === shape.top &&\n      width === shape.width &&\n      height === shape.height\n    );\n  }\n\n  public containsPoint(point: Point): boolean {\n    const {top, left, bottom, right} = this;\n\n    return (\n      top <= point.y && point.y <= bottom && left <= point.x && point.x <= right\n    );\n  }\n\n  public intersectionArea(shape: Shape): number {\n    if (shape instanceof Rectangle) {\n      return rectangleRectangleIntersection(this, shape);\n    }\n\n    return 0;\n  }\n\n  public intersectionRatio(shape: Shape): number {\n    const {area} = this;\n    const intersectionArea = this.intersectionArea(shape);\n    const intersectionRatio =\n      intersectionArea / (shape.area + area - intersectionArea);\n\n    return intersectionRatio;\n  }\n\n  public get bottom(): number {\n    const {top, height} = this;\n\n    return top + height;\n  }\n\n  public get right(): number {\n    const {left, width} = this;\n\n    return left + width;\n  }\n\n  public get aspectRatio(): number {\n    const {width, height} = this;\n\n    return width / height;\n  }\n\n  public get corners() {\n    return [\n      {x: this.left, y: this.top},\n      {x: this.right, y: this.top},\n      {x: this.left, y: this.bottom},\n      {x: this.right, y: this.bottom},\n    ];\n  }\n\n  static from({top, left, width, height}: BoundingRectangle) {\n    return new Rectangle(left, top, width, height);\n  }\n\n  static delta(\n    a: BoundingRectangle,\n    b: BoundingRectangle,\n    alignment: Alignment = {x: 'center', y: 'center'}\n  ): Point {\n    const getCoordinate = (rect: BoundingRectangle, axis: 'x' | 'y') => {\n      const align = alignment[axis];\n      const start = axis === 'x' ? rect.left : rect.top;\n      const size = axis === 'x' ? rect.width : rect.height;\n\n      if (align == 'start') return start;\n      if (align == 'end') return start + size;\n      return start + size / 2;\n    };\n\n    return Point.delta(\n      {x: getCoordinate(a, 'x'), y: getCoordinate(a, 'y')},\n      {x: getCoordinate(b, 'x'), y: getCoordinate(b, 'y')}\n    );\n  }\n\n  static intersectionRatio(a: BoundingRectangle, b: BoundingRectangle): number {\n    return Rectangle.from(a).intersectionRatio(Rectangle.from(b));\n  }\n}\n\nfunction rectangleRectangleIntersection(\n  a: BoundingRectangle,\n  b: BoundingRectangle\n): number {\n  const top = Math.max(b.top, a.top);\n  const left = Math.max(b.left, a.left);\n  const right = Math.min(b.left + b.width, a.left + a.width);\n  const bottom = Math.min(b.top + b.height, a.top + a.height);\n  const width = right - left;\n  const height = bottom - top;\n\n  // Rectangles overlap\n  if (left < right && top < bottom) {\n    const intersectionArea = width * height;\n\n    return intersectionArea;\n  }\n\n  // Rectangles do not overlap, or overlap has an area of zero (edge/corner overlap)\n  return 0;\n}\n"
  },
  {
    "path": "packages/geometry/src/shapes/Shape.ts",
    "content": "import type {Point} from '../point';\nimport type {BoundingRectangle} from '../types';\n\n/**\n * An abstract class representing a 2D geometric shape, such as\n * a polygon or circle. Shapes are used for collision detection\n * during drag and drop operations.\n */\nexport abstract class Shape {\n  /**\n   * Get the bounding rectangle of the 2D shape.\n   * @returns The bounding rectangle of the shape.\n   */\n  abstract get boundingRectangle(): BoundingRectangle;\n\n  /**\n   * Get the center point of the 2D shape.\n   * @returns The center point of the shape.\n   */\n  abstract get center(): Point;\n\n  /**\n   * Get the total space taken up by the 2D shape.\n   * @returns The area of the shape.\n   */\n  abstract get area(): number;\n\n  /**\n   * Get the scale transformation of the shape on the 2D plane.\n   * @returns The scale of the shape.\n   */\n  abstract get scale(): {x: number; y: number};\n\n  /**\n   * Get the inverse scale transformation of the shape on the 2D plane.\n   * @returns The inverse scale of the shape.\n   */\n  abstract get inverseScale(): {x: number; y: number};\n\n  /**\n   * Get the aspect ratio of the 2D shape.\n   * @returns The aspect ratio of the shape.\n   */\n  abstract get aspectRatio(): number;\n\n  /**\n   * Returns whether or not this shape is equal to another shape.\n   *\n   * @param shape The other shape to compare with.\n   * @returns Whether or not the two shapes are equal.\n   */\n  abstract equals(shape: Shape): boolean;\n\n  /**\n   * Returns the intersection area between this shape and another shape.\n   *\n   * @param shape The other shape to calculate the intersection area with.\n   * @returns The intersection area between the two shapes.\n   */\n  abstract intersectionArea(shape: Shape): number;\n\n  /**\n   * Test a point for containment within this shape.\n   *\n   * @param point A point in world coordinates.\n   */\n  abstract containsPoint(point: Point): boolean;\n}\n"
  },
  {
    "path": "packages/geometry/src/shapes/index.ts",
    "content": "export type {Shape} from './Shape';\n\nexport {Rectangle} from './Rectangle';\n"
  },
  {
    "path": "packages/geometry/src/types/alignment.ts",
    "content": "export type Align = 'center' | 'start' | 'end';\n\nexport interface Alignment {\n  x: Align;\n  y: Align;\n}\n"
  },
  {
    "path": "packages/geometry/src/types/axis.ts",
    "content": "export enum Axis {\n  Horizontal = 'x',\n  Vertical = 'y',\n}\n\nexport const Axes = Object.values(Axis);\n"
  },
  {
    "path": "packages/geometry/src/types/bounding-rectangle.ts",
    "content": "export interface BoundingRectangle {\n  width: number;\n  height: number;\n  left: number;\n  right: number;\n  top: number;\n  bottom: number;\n}\n"
  },
  {
    "path": "packages/geometry/src/types/coordinates.ts",
    "content": "import type {Axis} from './axis';\n\nexport type Coordinates = Record<Axis, number>;\n"
  },
  {
    "path": "packages/geometry/src/types/index.ts",
    "content": "export * from './axis';\nexport * from './alignment';\nexport * from './coordinates';\nexport * from './bounding-rectangle';\n"
  },
  {
    "path": "packages/geometry/tsconfig.json",
    "content": "{\n  \"extends\": \"../../config/typescript/vanilla.json\",\n  \"include\": [\"src/**/*\"],\n  \"exclude\": [\"dist\", \"build\", \"node_modules\"]\n}\n"
  },
  {
    "path": "packages/helpers/CHANGELOG.md",
    "content": "# @dnd-kit/helpers\n\n## 0.3.2\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/abstract@0.3.2\n\n## 0.3.1\n\n### Patch Changes\n\n- Updated dependencies [[`4341114`](https://github.com/clauderic/dnd-kit/commit/43411143063349caeded4f778923473624ce25cf)]:\n  - @dnd-kit/abstract@0.3.1\n\n## 0.3.0\n\n### Patch Changes\n\n- [`e8ae539`](https://github.com/clauderic/dnd-kit/commit/e8ae539abe05a1df41d45078b108167022ac9ef7) Thanks [@clauderic](https://github.com/clauderic)! - Fix the `move` and `swap` helpers to support computed sortable IDs and optimistic sorting reconciliation for grouped records.\n\n  When the ID-based lookup fails (e.g. when using computed IDs like `id={\\`sortable-${item.id}\\`}` that don't match data items), the helpers now fall back to sortable index properties (`initialIndex`, `index`, `group`, `initialGroup`) to determine the correct positions. Additionally, grouped records now support optimistic sorting reconciliation—when `source.id === target.id` after optimistic sorting, the helpers use the sortable indices to determine the intended move.\n\n  Added `initialIndex`, `group`, and `initialGroup` getters to `SortableDraggable`, and `index` and `group` getters to `SortableDroppable`, so these properties are accessible from the operation's `source` and `target` in drag events.\n\n- Updated dependencies [[`6a59647`](https://github.com/clauderic/dnd-kit/commit/6a59647ebba2114b2e423f282ab25bf2ea40318d)]:\n  - @dnd-kit/abstract@0.3.0\n\n## 0.2.4\n\n### Patch Changes\n\n- Updated dependencies [[`de27fbc`](https://github.com/clauderic/dnd-kit/commit/de27fbca9df12eece3cd53ccbbac34e0eaf113e1), [`be7cfe3`](https://github.com/clauderic/dnd-kit/commit/be7cfe3b6cf6a989aefd3e39fd145fe271942b3a)]:\n  - @dnd-kit/abstract@0.2.4\n\n## 0.2.3\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/abstract@0.2.3\n\n## 0.2.2\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/abstract@0.2.2\n\n## 0.2.1\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/abstract@0.2.1\n\n## 0.2.0\n\n### Patch Changes\n\n- Updated dependencies [[`e95a9c8`](https://github.com/clauderic/dnd-kit/commit/e95a9c8f448d6b339e0b6fd37546ac7cfdf18edb)]:\n  - @dnd-kit/abstract@0.2.0\n\n## 0.1.21\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/abstract@0.1.21\n\n## 0.1.20\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/abstract@0.1.20\n\n## 0.1.19\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/abstract@0.1.19\n\n## 0.1.18\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/abstract@0.1.18\n\n## 0.1.17\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/abstract@0.1.17\n\n## 0.1.16\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/abstract@0.1.16\n\n## 0.1.15\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/abstract@0.1.15\n\n## 0.1.14\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/abstract@0.1.14\n\n## 0.1.13\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/abstract@0.1.13\n\n## 0.1.12\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/abstract@0.1.12\n\n## 0.1.11\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/abstract@0.1.11\n\n## 0.1.10\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/abstract@0.1.10\n\n## 0.1.9\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/abstract@0.1.9\n\n## 0.1.8\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/abstract@0.1.8\n\n## 0.1.7\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/abstract@0.1.7\n\n## 0.1.6\n\n### Patch Changes\n\n- Updated dependencies [[`7ceb799`](https://github.com/clauderic/dnd-kit/commit/7ceb799c7d214bc8223ec845357a0040c28ae40e)]:\n  - @dnd-kit/abstract@0.1.6\n\n## 0.1.5\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/abstract@0.1.5\n\n## 0.1.4\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/abstract@0.1.4\n\n## 0.1.3\n\n### Patch Changes\n\n- Updated dependencies [[`6c9a9ea`](https://github.com/clauderic/dnd-kit/commit/6c9a9ea060095884c90c72cd5d6b73820467ec29), [`1bef872`](https://github.com/clauderic/dnd-kit/commit/1bef8722d515079f998dc0608084e1d853e74d3a)]:\n  - @dnd-kit/abstract@0.1.3\n\n## 0.1.2\n\n### Patch Changes\n\n- Updated dependencies [[`4682570`](https://github.com/clauderic/dnd-kit/commit/4682570a6b80868af0e51b1bbbf902430117df43), [`f8d69b0`](https://github.com/clauderic/dnd-kit/commit/f8d69b01f4cf53fc368ef1fca9188c313192928d), [`d04e9a2`](https://github.com/clauderic/dnd-kit/commit/d04e9a2879fb00f092c3f8280c8081a48eebf193), [`ee55f58`](https://github.com/clauderic/dnd-kit/commit/ee55f582f92dc42cc6eea9ad7492fc782ca6455a)]:\n  - @dnd-kit/abstract@0.1.2\n\n## 0.1.1\n\n### Patch Changes\n\n- Updated dependencies [[`f13cbc9`](https://github.com/clauderic/dnd-kit/commit/f13cbc978229844770d3c8aa03135e4352ee2532)]:\n  - @dnd-kit/abstract@0.1.1\n\n## 0.1.0\n\n### Patch Changes\n\n- Updated dependencies [[`00a33c9`](https://github.com/clauderic/dnd-kit/commit/00a33c99e777ab205a45309a4efc8b3560bafdaf)]:\n  - @dnd-kit/abstract@0.1.0\n\n## 0.0.10\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/abstract@0.0.10\n\n## 0.0.9\n\n### Patch Changes\n\n- Updated dependencies [[`e36d954`](https://github.com/clauderic/dnd-kit/commit/e36d95420148659ba78bdbefd3a0a24ec5d02b8f), [`b7f1cf8`](https://github.com/clauderic/dnd-kit/commit/b7f1cf8f9e15a285c45f896e092f61001335cdff), [`3e629cc`](https://github.com/clauderic/dnd-kit/commit/3e629cc81dbaf9d112c4f1d2c10c75eb6779cf4e), [`ce31da7`](https://github.com/clauderic/dnd-kit/commit/ce31da736ec5d4f48bab45430be7b57223d60ee7)]:\n  - @dnd-kit/abstract@0.0.9\n\n## 0.0.8\n\n### Patch Changes\n\n- Updated dependencies [[`c9716cf`](https://github.com/clauderic/dnd-kit/commit/c9716cf7b8b846faab451bd2f60c53c77d2d24ba), [`3ea0d31`](https://github.com/clauderic/dnd-kit/commit/3ea0d314649b186bfe0524d50145625da13a8787), [`3cf4db1`](https://github.com/clauderic/dnd-kit/commit/3cf4db126813ebe6ddfc025df5e42e9bfcfa9c38)]:\n  - @dnd-kit/abstract@0.0.8\n\n## 0.0.7\n\n### Patch Changes\n\n- [#1592](https://github.com/clauderic/dnd-kit/pull/1592) [`808f184`](https://github.com/clauderic/dnd-kit/commit/808f184439125cf7e66054b3e85ac087aa04f13b) Thanks [@github-actions](https://github.com/apps/github-actions)! - Fix reconciliation of optimistic updates in `move` helper.\n\n- Updated dependencies [[`c1dadef`](https://github.com/clauderic/dnd-kit/commit/c1dadef118f8f5f096d36dac314bfe317ea950ce), [`cef9b46`](https://github.com/clauderic/dnd-kit/commit/cef9b46c5ed017e6a601b1d0ee9d0f05b7bbd19f)]:\n  - @dnd-kit/abstract@0.0.7\n\n## 0.0.6\n\n### Patch Changes\n\n- [#1567](https://github.com/clauderic/dnd-kit/pull/1567) [`081b7f2`](https://github.com/clauderic/dnd-kit/commit/081b7f2a11da2aad8ce3da7f0579974415d1fdf0) Thanks [@chrisvxd](https://github.com/chrisvxd)! - Add source maps to output.\n\n- [#1454](https://github.com/clauderic/dnd-kit/pull/1454) [`d272e76`](https://github.com/clauderic/dnd-kit/commit/d272e76fef094d0e05c215bf6f5d37d56a29c251) Thanks [@github-actions](https://github.com/apps/github-actions)! - Fix a bug where the source would accidentally be moved below the target index due to rounding errors.\n\n- [#1454](https://github.com/clauderic/dnd-kit/pull/1454) [`1998c20`](https://github.com/clauderic/dnd-kit/commit/1998c20ecc26f0e2cb24f06077bc01e3dabcaf7c) Thanks [@github-actions](https://github.com/apps/github-actions)! - Updated the `move` helper to accept an `event` instead of `source` and `target`.\n\n- Updated dependencies [[`984b5ab`](https://github.com/clauderic/dnd-kit/commit/984b5ab7bec3145dedb9c9b3b560ffbf7e54b919), [`081b7f2`](https://github.com/clauderic/dnd-kit/commit/081b7f2a11da2aad8ce3da7f0579974415d1fdf0), [`a04d3f8`](https://github.com/clauderic/dnd-kit/commit/a04d3f88d380853b97585ab3b608561f7b02ce69), [`a8542de`](https://github.com/clauderic/dnd-kit/commit/a8542de56d39c3cd3b6ef981172a0782454295b2), [`f7458d9`](https://github.com/clauderic/dnd-kit/commit/f7458d9dc32824dbea3a6d5dfb29236f19a2c073), [`e70b29a`](https://github.com/clauderic/dnd-kit/commit/e70b29ae64837e424f7279c95112fb6e420c4dcc), [`4d1a030`](https://github.com/clauderic/dnd-kit/commit/4d1a0306c920ae064eb5b30c4c02961f50460c84), [`a5933d8`](https://github.com/clauderic/dnd-kit/commit/a5933d8607e63ed08818ffab43e858863cb35d47), [`a5a556a`](https://github.com/clauderic/dnd-kit/commit/a5a556abfeec1d78effb3e047f529555e444c020), [`96f28ef`](https://github.com/clauderic/dnd-kit/commit/96f28ef86adf95e77540732d39033c7f3fb0fd04)]:\n  - @dnd-kit/abstract@0.0.6\n\n## 0.0.5\n\n### Patch Changes\n\n- Updated dependencies [[`e9be505`](https://github.com/clauderic/dnd-kit/commit/e9be5051b5c99e522fb6efd028d425220b171890)]:\n  - @dnd-kit/abstract@0.0.5\n\n## 0.0.4\n\n### Patch Changes\n\n- Updated dependencies [[`2ccc27c`](https://github.com/clauderic/dnd-kit/commit/2ccc27c566b13d6de46719d0ad5978d655261177), [`e0d80f5`](https://github.com/clauderic/dnd-kit/commit/e0d80f59c733b3adcf1fc89d29aa80257e7edd98), [`794cf2f`](https://github.com/clauderic/dnd-kit/commit/794cf2f4bdeeb57a197effb1df654c7c44cf34a3)]:\n  - @dnd-kit/abstract@0.0.4\n\n## 0.0.3\n\n### Patch Changes\n\n- Updated dependencies [[`5ccd5e6`](https://github.com/clauderic/dnd-kit/commit/5ccd5e668fb8d736ec3c195116559cb5c5684e80), [`886de33`](https://github.com/clauderic/dnd-kit/commit/886de33d0df851ebdcb3fcf2915f9623069b06d1)]:\n  - @dnd-kit/abstract@0.0.3\n\n## 0.0.2\n\n### Patch Changes\n\n- Updated dependencies []:\n  - @dnd-kit/abstract@0.0.2\n"
  },
  {
    "path": "packages/helpers/README.md",
    "content": "# @dnd-kit/helpers\n\n[![Stable release](https://img.shields.io/npm/v/@dnd-kit/helpers.svg)](https://npm.im/@dnd-kit/helpers)\n\nFramework-agnostic helper functions for **@dnd-kit**. Provides utilities for common data transformations in drag and drop interactions.\n\n## Installation\n\n```bash\nnpm install @dnd-kit/helpers\n```\n\n## API\n\n| Function                     | Description                                                                   |\n| ---------------------------- | ----------------------------------------------------------------------------- |\n| `move(items, event)`         | Move an item from one position to another within a flat or grouped collection |\n| `swap(items, event)`         | Swap the positions of two items                                               |\n| `arrayMove(array, from, to)` | Move an item in an array from one index to another                            |\n| `arraySwap(array, from, to)` | Swap two items in an array by index                                           |\n\n### Example\n\n```ts\nimport {move} from '@dnd-kit/helpers';\n\nfunction onDragEnd(event) {\n  items = move(items, event);\n}\n```\n\n## Documentation\n\nVisit [dndkit.com](https://dndkit.com) for full documentation.\n"
  },
  {
    "path": "packages/helpers/package.json",
    "content": "{\n  \"name\": \"@dnd-kit/helpers\",\n  \"type\": \"module\",\n  \"version\": \"0.3.2\",\n  \"main\": \"./dist/index.cjs\",\n  \"module\": \"./dist/index.js\",\n  \"types\": \"./dist/index.d.ts\",\n  \"sideEffects\": false,\n  \"license\": \"MIT\",\n  \"files\": [\n    \"dist/**\"\n  ],\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/index.d.ts\",\n      \"import\": \"./dist/index.js\",\n      \"require\": \"./dist/index.cjs\"\n    }\n  },\n  \"scripts\": {\n    \"build\": \"tsup src/index.ts --format esm,cjs --dts --external react\",\n    \"dev\": \"tsup src/index.ts --format esm,cjs --watch --dts --external react\",\n    \"test\": \"bun test\",\n    \"lint\": \"TIMING=1 eslint src/**/*.ts* --fix\",\n    \"clean\": \"rm -rf .turbo && rm -rf node_modules && rm -rf dist\"\n  },\n  \"dependencies\": {\n    \"@dnd-kit/abstract\": \"^0.3.2\",\n    \"tslib\": \"^2.6.2\"\n  },\n  \"devDependencies\": {\n    \"@dnd-kit/eslint-config\": \"*\",\n    \"bun-types\": \"^1.2.15\",\n    \"eslint\": \"^8.38.0\",\n    \"tsup\": \"8.3.0\",\n    \"typescript\": \"^5.5.2\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/clauderic/dnd-kit\"\n  }\n}\n"
  },
  {
    "path": "packages/helpers/src/index.ts",
    "content": "export {move, swap, arrayMove, arraySwap} from './move.ts';\n"
  },
  {
    "path": "packages/helpers/src/move.ts",
    "content": "import type {\n  UniqueIdentifier,\n  Draggable,\n  Droppable,\n  DragDropManager,\n  DragDropEventMap,\n} from '@dnd-kit/abstract';\n\n/**\n * Move an array item to a different position. Returns a new array with the item moved to the new position.\n */\nexport function arrayMove<T extends any[]>(\n  array: T,\n  from: number,\n  to: number\n): T {\n  if (from === to) {\n    return array;\n  }\n\n  const newArray = array.slice() as T;\n  newArray.splice(to, 0, newArray.splice(from, 1)[0]);\n\n  return newArray;\n}\n\n/**\n * Move an array item to a different position. Returns a new array with the item moved to the new position.\n */\nexport function arraySwap<T extends any[]>(\n  array: T,\n  from: number,\n  to: number\n): T {\n  if (from === to) {\n    return array;\n  }\n\n  const newArray = array.slice() as T;\n  const item = newArray[from];\n\n  newArray[from] = newArray[to];\n  newArray[to] = item;\n\n  return newArray;\n}\n\ntype Items = UniqueIdentifier[] | {id: UniqueIdentifier}[];\n\n/**\n * Check if the source has sortable index properties via duck typing.\n * The `move` helper lives in `@dnd-kit/helpers` which has no dependency on `@dnd-kit/dom`,\n * so we discover sortable properties at runtime.\n */\nfunction hasSortableIndices(source: Draggable): source is Draggable & {\n  initialIndex: number;\n  index: number;\n  initialGroup: UniqueIdentifier | undefined;\n  group: UniqueIdentifier | undefined;\n} {\n  return (\n    'initialIndex' in source &&\n    typeof source.initialIndex === 'number' &&\n    'index' in source &&\n    typeof source.index === 'number'\n  );\n}\n\nfunction mutate<\n  T extends Items | Record<UniqueIdentifier, Items>,\n  U extends Draggable,\n  V extends Droppable,\n  W extends DragDropManager<U, V>,\n>(\n  items: T,\n  event: DragDropEventMap<U, V, W>['dragover'] | DragDropEventMap<U, V, W>['dragend'],\n  mutation: typeof arrayMove | typeof arraySwap\n): T {\n  const {source, target, canceled} = event.operation;\n\n  if (!source || !target || canceled) {\n    if ('preventDefault' in event) event.preventDefault();\n    return items;\n  }\n\n  const findIndex = (item: Items[0], id: UniqueIdentifier) =>\n    item === id || (typeof item === 'object' && 'id' in item && item.id === id);\n\n  if (Array.isArray(items)) {\n    const sourceIndex = items.findIndex((item) => findIndex(item, source.id));\n    const targetIndex = items.findIndex((item) => findIndex(item, target.id));\n\n    if (sourceIndex === -1 || targetIndex === -1) {\n      // Fallback: when the ID-based lookup fails (e.g. computed IDs that don't\n      // match data items), use the sortable index properties directly.\n      if (hasSortableIndices(source)) {\n        const from = source.initialIndex;\n        const to = source.index;\n\n        if (from === to || from < 0 || from >= items.length) {\n          if ('preventDefault' in event) event.preventDefault();\n          return items;\n        }\n\n        return mutation(items, from, to);\n      }\n\n      return items;\n    }\n\n    // Reconcile optimistic updates\n    if (!canceled && 'index' in source && typeof source.index === 'number') {\n      const projectedSourceIndex = source.index;\n\n      if (projectedSourceIndex !== sourceIndex) {\n        return mutation(items, sourceIndex, projectedSourceIndex);\n      }\n    }\n\n    return mutation(items, sourceIndex, targetIndex);\n  }\n\n  // Grouped/record case\n\n  const entries = Object.entries(items);\n\n  let sourceIndex = -1;\n  let sourceParent: UniqueIdentifier | undefined;\n  let targetIndex = -1;\n  let targetParent: UniqueIdentifier | undefined;\n\n  for (const [id, children] of entries) {\n    if (sourceIndex === -1) {\n      sourceIndex = children.findIndex((item) => findIndex(item, source.id));\n\n      if (sourceIndex !== -1) {\n        sourceParent = id;\n      }\n    }\n\n    if (targetIndex === -1) {\n      targetIndex = children.findIndex((item) => findIndex(item, target.id));\n\n      if (targetIndex !== -1) {\n        targetParent = id;\n      }\n    }\n\n    if (sourceIndex !== -1 && targetIndex !== -1) {\n      break;\n    }\n  }\n\n  // Fallback: when the ID-based lookup fails for the source (e.g. computed IDs),\n  // use the sortable index properties directly.\n  if (sourceIndex === -1 && hasSortableIndices(source)) {\n    const srcParent = source.initialGroup;\n    const srcIndex = source.initialIndex;\n    const tgtParent = source.group;\n    const tgtIndex = source.index;\n\n    if (\n      srcParent == null ||\n      tgtParent == null ||\n      !(srcParent in items) ||\n      !(tgtParent in items)\n    ) {\n      if ('preventDefault' in event) event.preventDefault();\n      return items;\n    }\n\n    if (srcParent === tgtParent && srcIndex === tgtIndex) {\n      if ('preventDefault' in event) event.preventDefault();\n      return items;\n    }\n\n    if (srcParent === tgtParent) {\n      return {\n        ...items,\n        [srcParent]: mutation(items[srcParent], srcIndex, tgtIndex),\n      };\n    }\n\n    // Cross-group transfer\n    const sourceItem = items[srcParent][srcIndex];\n\n    return {\n      ...items,\n      [srcParent]: [\n        ...items[srcParent].slice(0, srcIndex),\n        ...items[srcParent].slice(srcIndex + 1),\n      ],\n      [tgtParent]: [\n        ...items[tgtParent].slice(0, tgtIndex),\n        sourceItem,\n        ...items[tgtParent].slice(tgtIndex),\n      ],\n    };\n  }\n\n  if (!source.manager) return items;\n\n  const {dragOperation} = source.manager;\n  const position =\n    dragOperation.shape?.current.center ?? dragOperation.position.current;\n\n  if (targetParent == null) {\n    if (target.id in items) {\n      const insertionIndex =\n        target.shape && position.y > target.shape.center.y\n          ? items[target.id].length\n          : 0;\n\n      // The target does not have any matching children, but appears to be a valid target\n      targetParent = target.id;\n      targetIndex = insertionIndex;\n    }\n  }\n\n  if (\n    sourceParent == null ||\n    targetParent == null ||\n    (sourceParent === targetParent && sourceIndex === targetIndex)\n  ) {\n    // Reconcile optimistic sorting for grouped records.\n    // When the ID-based lookup finds source and target at the same position\n    // (e.g. source.id === target.id after optimistic sorting), check if the\n    // sortable indices indicate a different position.\n    if (\n      sourceParent != null &&\n      sourceParent === targetParent &&\n      sourceIndex === targetIndex &&\n      hasSortableIndices(source)\n    ) {\n      const hasGroupChanged =\n        source.group != null && source.group !== sourceParent;\n      const hasIndexChanged = source.index !== sourceIndex;\n\n      if (hasGroupChanged || hasIndexChanged) {\n        const reconciledTargetParent = source.group ?? sourceParent;\n\n        if (reconciledTargetParent in items) {\n          if (sourceParent === reconciledTargetParent) {\n            return {\n              ...items,\n              [sourceParent]: mutation(\n                items[sourceParent],\n                sourceIndex,\n                source.index\n              ),\n            };\n          }\n\n          // Cross-group transfer\n          const sourceItem = items[sourceParent][sourceIndex];\n          return {\n            ...items,\n            [sourceParent]: [\n              ...items[sourceParent].slice(0, sourceIndex),\n              ...items[sourceParent].slice(sourceIndex + 1),\n            ],\n            [reconciledTargetParent]: [\n              ...items[reconciledTargetParent].slice(0, source.index),\n              sourceItem,\n              ...items[reconciledTargetParent].slice(source.index),\n            ],\n          };\n        }\n      }\n    }\n\n    if ('preventDefault' in event) event.preventDefault();\n\n    return items;\n  }\n\n  if (sourceParent === targetParent) {\n    return {\n      ...items,\n      [sourceParent]: mutation(items[sourceParent], sourceIndex, targetIndex),\n    };\n  }\n\n  const isBelowTarget =\n    target.shape && Math.round(position.y) > Math.round(target.shape.center.y);\n  const modifier = isBelowTarget ? 1 : 0;\n  const sourceItem = items[sourceParent][sourceIndex];\n\n  return {\n    ...items,\n    [sourceParent]: [\n      ...items[sourceParent].slice(0, sourceIndex),\n      ...items[sourceParent].slice(sourceIndex + 1),\n    ],\n    [targetParent]: [\n      ...items[targetParent].slice(0, targetIndex + modifier),\n      sourceItem,\n      ...items[targetParent].slice(targetIndex + modifier),\n    ],\n  };\n}\n\nexport function move<\n  T extends Items | Record<UniqueIdentifier, Items>,\n  U extends Draggable,\n  V extends Droppable,\n  W extends DragDropManager<U, V>,\n>(\n  items: T,\n  event: DragDropEventMap<U, V, W>['dragover'] | DragDropEventMap<U, V, W>['dragend']\n) {\n  return mutate(items, event, arrayMove);\n}\n\nexport function swap<\n  T extends Items | Record<UniqueIdentifier, Items>,\n  U extends Draggable,\n  V extends Droppable,\n  W extends DragDropManager<U, V>,\n>(\n  items: T,\n  event: DragDropEventMap<U, V, W>['dragover'] | DragDropEventMap<U, V, W>['dragend']\n) {\n  return mutate(items, event, arraySwap);\n}\n"
  },
  {
    "path": "packages/helpers/tests/move.test.ts",
    "content": "import {describe, expect, it} from 'bun:test';\nimport {arrayMove, arraySwap, move, swap} from '../src/move.ts';\n\n// ---------------------------------------------------------------------------\n// Mock helpers\n// ---------------------------------------------------------------------------\n\n/** Minimal mock for a non-sortable source (plain Draggable). */\nfunction mockSource(id: string | number) {\n  return {id, manager: null} as any;\n}\n\n/** Minimal mock for a non-sortable target (plain Droppable). */\nfunction mockTarget(id: string | number) {\n  return {id} as any;\n}\n\n/**\n * Mock for a sortable source (SortableDraggable).\n * Has `index`, `initialIndex`, `group`, and `initialGroup`.\n */\nfunction mockSortableSource(opts: {\n  id: string | number;\n  index: number;\n  initialIndex: number;\n  group?: string | number;\n  initialGroup?: string | number;\n}) {\n  return {\n    id: opts.id,\n    index: opts.index,\n    initialIndex: opts.initialIndex,\n    group: opts.group,\n    initialGroup: opts.initialGroup,\n    manager: null,\n  } as any;\n}\n\n/** Build a preventable dragover-style event. */\nfunction dragOverEvent(source: any, target: any, canceled = false) {\n  let defaultPrevented = false;\n  return {\n    operation: {source, target, canceled},\n    cancelable: true,\n    get defaultPrevented() {\n      return defaultPrevented;\n    },\n    preventDefault() {\n      defaultPrevented = true;\n    },\n  } as any;\n}\n\n/** Build a dragend-style event (no preventDefault). */\nfunction dragEndEvent(source: any, target: any, canceled = false) {\n  return {\n    operation: {source, target, canceled},\n    canceled,\n  } as any;\n}\n\n// ===========================================================================\n// arrayMove / arraySwap\n// ===========================================================================\n\ndescribe('arrayMove', () => {\n  it('should move an item forward', () => {\n    expect(arrayMove(['a', 'b', 'c', 'd'], 0, 2)).toEqual(['b', 'c', 'a', 'd']);\n  });\n\n  it('should move an item backward', () => {\n    expect(arrayMove(['a', 'b', 'c', 'd'], 3, 1)).toEqual(['a', 'd', 'b', 'c']);\n  });\n\n  it('should return the same array reference when from === to', () => {\n    const arr = ['a', 'b', 'c'];\n    expect(arrayMove(arr, 1, 1)).toBe(arr);\n  });\n\n  it('should not mutate the original array', () => {\n    const arr = ['a', 'b', 'c'];\n    arrayMove(arr, 0, 2);\n    expect(arr).toEqual(['a', 'b', 'c']);\n  });\n});\n\ndescribe('arraySwap', () => {\n  it('should swap two items', () => {\n    expect(arraySwap(['a', 'b', 'c', 'd'], 0, 3)).toEqual(['d', 'b', 'c', 'a']);\n  });\n\n  it('should return the same array reference when from === to', () => {\n    const arr = ['a', 'b', 'c'];\n    expect(arraySwap(arr, 1, 1)).toBe(arr);\n  });\n\n  it('should not mutate the original array', () => {\n    const arr = ['a', 'b', 'c'];\n    arraySwap(arr, 0, 2);\n    expect(arr).toEqual(['a', 'b', 'c']);\n  });\n});\n\n// ===========================================================================\n// move – flat array, ID-based (non-sortable fallback)\n// ===========================================================================\n\ndescribe('move – flat array, ID-based fallback', () => {\n  it('should move with UniqueIdentifier[] items (strings)', () => {\n    const items = ['a', 'b', 'c', 'd'];\n    const event = dragOverEvent(mockSource('a'), mockTarget('c'));\n    expect(move(items, event)).toEqual(['b', 'c', 'a', 'd']);\n  });\n\n  it('should move with UniqueIdentifier[] items (numbers)', () => {\n    const items = [1, 2, 3, 4];\n    const event = dragOverEvent(mockSource(1), mockTarget(3));\n    expect(move(items, event)).toEqual([2, 3, 1, 4]);\n  });\n\n  it('should move with {id: UniqueIdentifier}[] items', () => {\n    const items = [{id: 'a'}, {id: 'b'}, {id: 'c'}];\n    const event = dragOverEvent(mockSource('a'), mockTarget('c'));\n    expect(move(items, event)).toEqual([{id: 'b'}, {id: 'c'}, {id: 'a'}]);\n  });\n\n  it('should return unchanged array when source not found', () => {\n    const items = ['a', 'b', 'c'];\n    const event = dragOverEvent(mockSource('z'), mockTarget('b'));\n    const result = move(items, event);\n    expect(result).toBe(items);\n  });\n\n  it('should return unchanged array when target not found', () => {\n    const items = ['a', 'b', 'c'];\n    const event = dragOverEvent(mockSource('a'), mockTarget('z'));\n    const result = move(items, event);\n    expect(result).toBe(items);\n  });\n\n  it('should return unchanged array and call preventDefault when canceled', () => {\n    const items = ['a', 'b', 'c'];\n    const event = dragOverEvent(mockSource('a'), mockTarget('c'), true);\n    const result = move(items, event);\n    expect(result).toBe(items);\n    expect(event.defaultPrevented).toBe(true);\n  });\n\n  it('should return unchanged array and call preventDefault when source is null', () => {\n    const items = ['a', 'b', 'c'];\n    const event = dragOverEvent(null, mockTarget('c'));\n    const result = move(items, event);\n    expect(result).toBe(items);\n    expect(event.defaultPrevented).toBe(true);\n  });\n\n  it('should return unchanged array and call preventDefault when target is null', () => {\n    const items = ['a', 'b', 'c'];\n    const event = dragOverEvent(mockSource('a'), null);\n    const result = move(items, event);\n    expect(result).toBe(items);\n    expect(event.defaultPrevented).toBe(true);\n  });\n});\n\n// ===========================================================================\n// move – flat array, optimistic reconciliation (source.id matches items)\n// ===========================================================================\n\ndescribe('move – flat array, optimistic reconciliation', () => {\n  it('should reconcile when source.index differs from ID-found position', () => {\n    // Simulates dragend after optimistic sorting:\n    // source.id === target.id, items not yet updated, source.index = optimistic position\n    const items = ['a', 'b', 'c', 'd'];\n    const source = mockSortableSource({\n      id: 'a',\n      initialIndex: 0,\n      index: 2,\n    });\n    // target.id === source.id (optimistic sorting sets drop target to source)\n    const event = dragOverEvent(source, mockTarget('a'));\n    // source found at 0 in items, source.index = 2, so reconcile: move(0, 2)\n    expect(move(items, event)).toEqual(['b', 'c', 'a', 'd']);\n  });\n\n  it('should not reconcile when source.index matches ID-found position', () => {\n    // After items have been updated, source position matches\n    const items = ['b', 'c', 'a', 'd'];\n    const source = mockSortableSource({\n      id: 'a',\n      initialIndex: 0,\n      index: 2,\n    });\n    const event = dragOverEvent(source, mockTarget('a'));\n    // source found at 2 in items, source.index = 2, no reconciliation needed\n    // mutation(items, 2, 2) returns the same array since from === to\n    const result = move(items, event);\n    expect(result).toBe(items);\n  });\n\n  it('should reconcile with dragend events', () => {\n    const items = ['a', 'b', 'c', 'd'];\n    const source = mockSortableSource({\n      id: 'a',\n      initialIndex: 0,\n      index: 3,\n    });\n    const event = dragEndEvent(source, mockTarget('a'));\n    expect(move(items, event)).toEqual(['b', 'c', 'd', 'a']);\n  });\n});\n\n// ===========================================================================\n// move – flat array, sortable fallback (computed IDs)\n// ===========================================================================\n\ndescribe('move – flat array, sortable fallback (computed IDs)', () => {\n  it('should use sortable indices when ID lookup fails', () => {\n    const items = ['apple', 'banana', 'cherry'];\n    const source = mockSortableSource({\n      id: 'sortable-0', // computed ID, does NOT match 'apple'\n      initialIndex: 0,\n      index: 2,\n    });\n    const event = dragOverEvent(source, mockTarget('sortable-0'));\n    expect(move(items, event)).toEqual(['banana', 'cherry', 'apple']);\n  });\n\n  it('should work with {id} object items and computed IDs', () => {\n    const items = [{id: 1}, {id: 2}, {id: 3}];\n    const source = mockSortableSource({\n      id: 'sortable-1', // does not match item.id\n      initialIndex: 0,\n      index: 2,\n    });\n    const event = dragOverEvent(source, mockTarget('sortable-1'));\n    expect(move(items, event)).toEqual([{id: 2}, {id: 3}, {id: 1}]);\n  });\n\n  it('should return unchanged when initialIndex === index (no movement)', () => {\n    const items = ['apple', 'banana', 'cherry'];\n    const source = mockSortableSource({\n      id: 'sortable-1',\n      initialIndex: 1,\n      index: 1,\n    });\n    const event = dragOverEvent(source, mockTarget('sortable-1'));\n    const result = move(items, event);\n    expect(result).toBe(items);\n    expect(event.defaultPrevented).toBe(true);\n  });\n\n  it('should return unchanged when initialIndex is out of bounds (negative)', () => {\n    const items = ['a', 'b', 'c'];\n    const source = mockSortableSource({\n      id: 'sortable-x',\n      initialIndex: -1,\n      index: 2,\n    });\n    const event = dragOverEvent(source, mockTarget('sortable-x'));\n    const result = move(items, event);\n    expect(result).toBe(items);\n    expect(event.defaultPrevented).toBe(true);\n  });\n\n  it('should return unchanged when initialIndex is out of bounds (too large)', () => {\n    const items = ['a', 'b', 'c'];\n    const source = mockSortableSource({\n      id: 'sortable-x',\n      initialIndex: 10,\n      index: 1,\n    });\n    const event = dragOverEvent(source, mockTarget('sortable-x'));\n    const result = move(items, event);\n    expect(result).toBe(items);\n    expect(event.defaultPrevented).toBe(true);\n  });\n\n  it('should work with dragend events', () => {\n    const items = ['apple', 'banana', 'cherry', 'date'];\n    const source = mockSortableSource({\n      id: 'sortable-0',\n      initialIndex: 0,\n      index: 3,\n    });\n    const event = dragEndEvent(source, mockTarget('sortable-0'));\n    expect(move(items, event)).toEqual(['banana', 'cherry', 'date', 'apple']);\n  });\n});\n\n// ===========================================================================\n// move – grouped record, ID-based fallback\n// ===========================================================================\n\ndescribe('move – grouped record, ID-based fallback', () => {\n  it('should reorder within the same group', () => {\n    const items = {\n      A: ['a1', 'a2', 'a3'],\n      B: ['b1', 'b2'],\n    };\n    const source = mockSource('a1');\n    source.manager = {\n      dragOperation: {\n        position: {current: {x: 0, y: 0}},\n        shape: null,\n      },\n    };\n    const event = dragOverEvent(source, mockTarget('a3'));\n    expect(move(items, event)).toEqual({\n      A: ['a2', 'a3', 'a1'],\n      B: ['b1', 'b2'],\n    });\n  });\n\n  it('should return unchanged when source not found in any group', () => {\n    const items = {\n      A: ['a1', 'a2'],\n      B: ['b1'],\n    };\n    const source = mockSource('z');\n    source.manager = {\n      dragOperation: {\n        position: {current: {x: 0, y: 0}},\n        shape: null,\n      },\n    };\n    const event = dragOverEvent(source, mockTarget('a1'));\n    const result = move(items, event);\n    expect(result).toBe(items);\n  });\n});\n\n// ===========================================================================\n// move – grouped record, optimistic reconciliation\n// ===========================================================================\n\ndescribe('move – grouped record, optimistic reconciliation', () => {\n  it('should reconcile same-group reorder when source.id === target.id', () => {\n    // Simulates dragend after optimistic sorting in a single group\n    const items = {\n      A: ['a1', 'a2', 'a3'],\n      B: ['b1', 'b2'],\n    };\n    const source = mockSortableSource({\n      id: 'a1',\n      initialIndex: 0,\n      index: 2,\n      initialGroup: 'A',\n      group: 'A',\n    });\n    source.manager = {\n      dragOperation: {\n        position: {current: {x: 0, y: 0}},\n        shape: null,\n      },\n    };\n    // source.id === target.id (optimistic sorting)\n    const event = dragOverEvent(source, mockTarget('a1'));\n    expect(move(items, event)).toEqual({\n      A: ['a2', 'a3', 'a1'],\n      B: ['b1', 'b2'],\n    });\n  });\n\n  it('should reconcile cross-group transfer when source.id === target.id', () => {\n    // Simulates dragend after optimistic cross-group sorting\n    const items = {\n      A: ['a1', 'a2', 'a3'],\n      B: ['b1', 'b2'],\n    };\n    const source = mockSortableSource({\n      id: 'a2',\n      initialIndex: 1,\n      index: 0,\n      initialGroup: 'A',\n      group: 'B',\n    });\n    source.manager = {\n      dragOperation: {\n        position: {current: {x: 0, y: 0}},\n        shape: null,\n      },\n    };\n    const event = dragOverEvent(source, mockTarget('a2'));\n    expect(move(items, event)).toEqual({\n      A: ['a1', 'a3'],\n      B: ['a2', 'b1', 'b2'],\n    });\n  });\n\n  it('should not reconcile when positions already match (items updated)', () => {\n    // After items have been updated, positions match\n    const items = {\n      A: ['a2', 'a3', 'a1'],\n      B: ['b1', 'b2'],\n    };\n    const source = mockSortableSource({\n      id: 'a1',\n      initialIndex: 0,\n      index: 2,\n      initialGroup: 'A',\n      group: 'A',\n    });\n    source.manager = {\n      dragOperation: {\n        position: {current: {x: 0, y: 0}},\n        shape: null,\n      },\n    };\n    // source.id === target.id, source found at index 2 in A, source.index = 2 → no reconciliation\n    const event = dragOverEvent(source, mockTarget('a1'));\n    const result = move(items, event);\n    expect(result).toBe(items);\n    expect(event.defaultPrevented).toBe(true);\n  });\n});\n\n// ===========================================================================\n// move – grouped record, sortable fallback (computed IDs)\n// ===========================================================================\n\ndescribe('move – grouped record, sortable fallback (computed IDs)', () => {\n  it('should reorder within the same group using sortable indices', () => {\n    const items = {\n      col1: [{id: 1}, {id: 2}, {id: 3}],\n      col2: [{id: 4}, {id: 5}],\n    };\n    const source = mockSortableSource({\n      id: 'sortable-1', // computed, does not match item.id\n      initialIndex: 0,\n      index: 2,\n      initialGroup: 'col1',\n      group: 'col1',\n    });\n    const event = dragOverEvent(source, mockTarget('sortable-1'));\n    expect(move(items, event)).toEqual({\n      col1: [{id: 2}, {id: 3}, {id: 1}],\n      col2: [{id: 4}, {id: 5}],\n    });\n  });\n\n  it('should transfer across groups using sortable indices', () => {\n    const items = {\n      col1: [{id: 1}, {id: 2}],\n      col2: [{id: 3}, {id: 4}],\n    };\n    const source = mockSortableSource({\n      id: 'sortable-1',\n      initialIndex: 0,\n      index: 1,\n      initialGroup: 'col1',\n      group: 'col2',\n    });\n    const event = dragOverEvent(source, mockTarget('sortable-1'));\n    expect(move(items, event)).toEqual({\n      col1: [{id: 2}],\n      col2: [{id: 3}, {id: 1}, {id: 4}],\n    });\n  });\n\n  it('should return unchanged when source and target index/group are the same', () => {\n    const items = {\n      A: ['a1', 'a2'],\n      B: ['b1'],\n    };\n    const source = mockSortableSource({\n      id: 'sortable-x',\n      initialIndex: 0,\n      index: 0,\n      initialGroup: 'A',\n      group: 'A',\n    });\n    const event = dragOverEvent(source, mockTarget('sortable-x'));\n    const result = move(items, event);\n    expect(result).toBe(items);\n    expect(event.defaultPrevented).toBe(true);\n  });\n\n  it('should return unchanged when initialGroup is not a valid record key', () => {\n    const items = {\n      A: ['a1', 'a2'],\n      B: ['b1'],\n    };\n    const source = mockSortableSource({\n      id: 'sortable-x',\n      initialIndex: 0,\n      index: 0,\n      initialGroup: 'INVALID',\n      group: 'A',\n    });\n    const event = dragOverEvent(source, mockTarget('sortable-x'));\n    const result = move(items, event);\n    expect(result).toBe(items);\n    expect(event.defaultPrevented).toBe(true);\n  });\n\n  it('should return unchanged when group is not a valid record key', () => {\n    const items = {\n      A: ['a1', 'a2'],\n      B: ['b1'],\n    };\n    const source = mockSortableSource({\n      id: 'sortable-x',\n      initialIndex: 0,\n      index: 0,\n      initialGroup: 'A',\n      group: 'INVALID',\n    });\n    const event = dragOverEvent(source, mockTarget('sortable-x'));\n    const result = move(items, event);\n    expect(result).toBe(items);\n    expect(event.defaultPrevented).toBe(true);\n  });\n\n  it('should return unchanged when initialGroup is undefined', () => {\n    const items = {\n      A: ['a1', 'a2'],\n      B: ['b1'],\n    };\n    const source = mockSortableSource({\n      id: 'sortable-x',\n      initialIndex: 0,\n      index: 1,\n      initialGroup: undefined,\n      group: 'A',\n    });\n    const event = dragOverEvent(source, mockTarget('sortable-x'));\n    const result = move(items, event);\n    expect(result).toBe(items);\n    expect(event.defaultPrevented).toBe(true);\n  });\n\n  it('should return unchanged when group is undefined', () => {\n    const items = {\n      A: ['a1', 'a2'],\n      B: ['b1'],\n    };\n    const source = mockSortableSource({\n      id: 'sortable-x',\n      initialIndex: 0,\n      index: 1,\n      initialGroup: 'A',\n      group: undefined,\n    });\n    const event = dragOverEvent(source, mockTarget('sortable-x'));\n    const result = move(items, event);\n    expect(result).toBe(items);\n    expect(event.defaultPrevented).toBe(true);\n  });\n});\n\n// ===========================================================================\n// swap – flat array\n// ===========================================================================\n\ndescribe('swap – flat array', () => {\n  it('should swap with ID-based fallback', () => {\n    const items = ['a', 'b', 'c', 'd'];\n    const event = dragOverEvent(mockSource('a'), mockTarget('d'));\n    expect(swap(items, event)).toEqual(['d', 'b', 'c', 'a']);\n  });\n\n  it('should swap using optimistic reconciliation', () => {\n    const items = ['a', 'b', 'c', 'd'];\n    const source = mockSortableSource({\n      id: 'a',\n      initialIndex: 0,\n      index: 3,\n    });\n    const event = dragOverEvent(source, mockTarget('a'));\n    expect(swap(items, event)).toEqual(['d', 'b', 'c', 'a']);\n  });\n\n  it('should swap with computed IDs (sortable fallback)', () => {\n    const items = ['apple', 'banana', 'cherry'];\n    const source = mockSortableSource({\n      id: 'sortable-0',\n      initialIndex: 0,\n      index: 2,\n    });\n    const event = dragOverEvent(source, mockTarget('sortable-0'));\n    expect(swap(items, event)).toEqual(['cherry', 'banana', 'apple']);\n  });\n});\n\n// ===========================================================================\n// swap – grouped record\n// ===========================================================================\n\ndescribe('swap – grouped record', () => {\n  it('should swap within the same group using optimistic reconciliation', () => {\n    const items = {\n      A: ['a1', 'a2', 'a3'],\n      B: ['b1'],\n    };\n    const source = mockSortableSource({\n      id: 'a1',\n      initialIndex: 0,\n      index: 2,\n      initialGroup: 'A',\n      group: 'A',\n    });\n    source.manager = {\n      dragOperation: {\n        position: {current: {x: 0, y: 0}},\n        shape: null,\n      },\n    };\n    const event = dragOverEvent(source, mockTarget('a1'));\n    expect(swap(items, event)).toEqual({\n      A: ['a3', 'a2', 'a1'],\n      B: ['b1'],\n    });\n  });\n\n  it('should swap with computed IDs (sortable fallback)', () => {\n    const items = {\n      A: ['a1', 'a2', 'a3'],\n      B: ['b1'],\n    };\n    const source = mockSortableSource({\n      id: 'sortable-a1',\n      initialIndex: 0,\n      index: 2,\n      initialGroup: 'A',\n      group: 'A',\n    });\n    const event = dragOverEvent(source, mockTarget('sortable-a1'));\n    expect(swap(items, event)).toEqual({\n      A: ['a3', 'a2', 'a1'],\n      B: ['b1'],\n    });\n  });\n\n  it('should do a move (not swap) for cross-group transfers', () => {\n    // Cross-group always does remove+insert regardless of move vs swap\n    const items = {\n      A: ['a1', 'a2'],\n      B: ['b1', 'b2'],\n    };\n    const source = mockSortableSource({\n      id: 'sortable-a1',\n      initialIndex: 0,\n      index: 1,\n      initialGroup: 'A',\n      group: 'B',\n    });\n    const event = dragOverEvent(source, mockTarget('sortable-a1'));\n    expect(swap(items, event)).toEqual({\n      A: ['a2'],\n      B: ['b1', 'a1', 'b2'],\n    });\n  });\n});\n\n// ===========================================================================\n// Edge cases\n// ===========================================================================\n\ndescribe('move – edge cases', () => {\n  it('should handle single-element flat array (no-op)', () => {\n    const items = ['a'];\n    const source = mockSortableSource({\n      id: 'sortable-a',\n      initialIndex: 0,\n      index: 0,\n    });\n    const event = dragOverEvent(source, mockTarget('sortable-a'));\n    const result = move(items, event);\n    expect(result).toBe(items);\n  });\n\n  it('should handle moving to the beginning of a flat array', () => {\n    const items = ['a', 'b', 'c'];\n    const source = mockSortableSource({\n      id: 'sortable-c',\n      initialIndex: 2,\n      index: 0,\n    });\n    const event = dragOverEvent(source, mockTarget('sortable-c'));\n    expect(move(items, event)).toEqual(['c', 'a', 'b']);\n  });\n\n  it('should handle moving to the end of a flat array', () => {\n    const items = ['a', 'b', 'c'];\n    const source = mockSortableSource({\n      id: 'sortable-a',\n      initialIndex: 0,\n      index: 2,\n    });\n    const event = dragOverEvent(source, mockTarget('sortable-a'));\n    expect(move(items, event)).toEqual(['b', 'c', 'a']);\n  });\n\n  it('should handle canceled dragend event with sortable source', () => {\n    const items = ['a', 'b', 'c'];\n    const source = mockSortableSource({\n      id: 'sortable-a',\n      initialIndex: 0,\n      index: 2,\n    });\n    // dragend events don't have preventDefault\n    const event = dragEndEvent(source, mockTarget('sortable-a'), true);\n    const result = move(items, event);\n    expect(result).toBe(items);\n  });\n\n  it('should handle adjacent item move', () => {\n    const items = ['a', 'b', 'c', 'd'];\n    const source = mockSortableSource({\n      id: 'sortable-b',\n      initialIndex: 1,\n      index: 2,\n    });\n    const event = dragOverEvent(source, mockTarget('sortable-b'));\n    expect(move(items, event)).toEqual(['a', 'c', 'b', 'd']);\n  });\n\n  it('should not mutate the original items array', () => {\n    const items = ['a', 'b', 'c'];\n    const source = mockSortableSource({\n      id: 'sortable-a',\n      initialIndex: 0,\n      index: 2,\n    });\n    const event = dragOverEvent(source, mockTarget('sortable-a'));\n    move(items, event);\n    expect(items).toEqual(['a', 'b', 'c']);\n  });\n\n  it('should not mutate the original items record', () => {\n    const items = {\n      A: ['a1', 'a2'],\n      B: ['b1'],\n    };\n    const source = mockSortableSource({\n      id: 'sortable-a1',\n      initialIndex: 0,\n      index: 0,\n      initialGroup: 'A',\n      group: 'B',\n    });\n    const event = dragOverEvent(source, mockTarget('sortable-a1'));\n    move(items, event);\n    expect(items).toEqual({\n      A: ['a1', 'a2'],\n      B: ['b1'],\n    });\n  });\n\n  it('should handle number IDs in grouped record with sortable fallback', () => {\n    const items = {\n      1: [10, 20, 30],\n      2: [40, 50],\n    };\n    const source = mockSortableSource({\n      id: 'sortable-10',\n      initialIndex: 0,\n      index: 1,\n      initialGroup: 1,\n      group: 2,\n    });\n    const event = dragOverEvent(source, mockTarget('sortable-10'));\n    expect(move(items, event)).toEqual({\n      1: [20, 30],\n      2: [40, 10, 50],\n    });\n  });\n\n  it('should use ID-based path when IDs match (even with sortable indices)', () => {\n    // When source.id matches items AND source.id !== target.id, use standard move\n    const items = ['a', 'b', 'c', 'd'];\n    const source = mockSortableSource({\n      id: 'b',\n      initialIndex: 1,\n      index: 1,\n    });\n    const event = dragOverEvent(source, mockTarget('d'));\n    // ID-based: sourceIndex=1, targetIndex=3 → move(1,3)\n    expect(move(items, event)).toEqual(['a', 'c', 'd', 'b']);\n  });\n});\n"
  },
  {
    "path": "packages/helpers/tsconfig.json",
    "content": "{\n  \"extends\": \"../../config/typescript/vanilla.json\",\n  \"include\": [\"src/**/*\"],\n  \"exclude\": [\"dist\", \"build\", \"node_modules\"]\n}\n"
  },
  {
    "path": "packages/react/CHANGELOG.md",
    "content": "# @dnd-kit/react\n\n## 0.3.2\n\n### Patch Changes\n\n- Updated dependencies [[`7260746`](https://github.com/clauderic/dnd-kit/commit/7260746b0930d51afb3098ef120bffd7d3aaea03)]:\n  - @dnd-kit/dom@0.3.2\n  - @dnd-kit/abstract@0.3.2\n  - @dnd-kit/state@0.3.2\n\n## 0.3.1\n\n### Patch Changes\n\n- Updated dependencies [[`4341114`](https://github.com/clauderic/dnd-kit/commit/43411143063349caeded4f778923473624ce25cf)]:\n  - @dnd-kit/abstract@0.3.1\n  - @dnd-kit/dom@0.3.1\n  - @dnd-kit/state@0.3.1\n\n## 0.3.0\n\n### Minor Changes\n\n- [`6a59647`](https://github.com/clauderic/dnd-kit/commit/6a59647ebba2114b2e423f282ab25bf2ea40318d) Thanks [@clauderic](https://github.com/clauderic)! - Allow `plugins`, `sensors`, and `modifiers` to accept a function that receives the defaults, making it easy to extend or configure them without replacing the entire array.\n\n  ```ts\n  // Add a plugin alongside the defaults\n  const manager = new DragDropManager({\n    plugins: (defaults) => [...defaults, MyPlugin],\n  });\n  ```\n\n  ```tsx\n  // Configure a default plugin in React\n  <DragDropProvider\n    plugins={(defaults) => [\n      ...defaults,\n      Feedback.configure({dropAnimation: null}),\n    ]}\n  />\n  ```\n\n  Previously, passing `plugins`, `sensors`, or `modifiers` would replace the defaults entirely, requiring consumers to import and spread `defaultPreset`. The function form receives the default values as an argument, so consumers can add, remove, or configure individual entries without needing to know or maintain the full default list.\n\n- [`68e44de`](https://github.com/clauderic/dnd-kit/commit/68e44deb6f824b38a58d9b4b1bd81e2efa9193f9) Thanks [@clauderic](https://github.com/clauderic)! - Add `isSortableOperation` type guard and export `SortableDraggable`/`SortableDroppable` types.\n\n  `isSortableOperation(operation)` narrows a `DragOperationSnapshot` so that `source` is typed as `SortableDraggable` and `target` as `SortableDroppable`, providing typed access to sortable-specific properties like `index`, `initialIndex`, `group`, and `initialGroup`.\n\n  Re-exported from all framework packages (`@dnd-kit/react/sortable`, `@dnd-kit/vue/sortable`, `@dnd-kit/svelte/sortable`, `@dnd-kit/solid/sortable`).\n\n### Patch Changes\n\n- [`5d64078`](https://github.com/clauderic/dnd-kit/commit/5d640782702b74da8be38cbd1e29271d04781854) Thanks [@clauderic](https://github.com/clauderic)! - Add `dropAnimation` prop to the `DragOverlay` component to allow consumers to disable or customize the drop animation that plays when a drag operation ends. Set to `null` to disable, pass `{duration, easing}` to customize timing, or provide a custom animation function for full control.\n\n- Updated dependencies [[`6a59647`](https://github.com/clauderic/dnd-kit/commit/6a59647ebba2114b2e423f282ab25bf2ea40318d), [`5d64078`](https://github.com/clauderic/dnd-kit/commit/5d640782702b74da8be38cbd1e29271d04781854), [`863ce2b`](https://github.com/clauderic/dnd-kit/commit/863ce2b74ec0f4d630f4b7036c363bc2e3d04f24), [`863ce2b`](https://github.com/clauderic/dnd-kit/commit/863ce2b74ec0f4d630f4b7036c363bc2e3d04f24), [`e8ae539`](https://github.com/clauderic/dnd-kit/commit/e8ae539abe05a1df41d45078b108167022ac9ef7), [`41d7e27`](https://github.com/clauderic/dnd-kit/commit/41d7e27edb30cea9940cd5c46c6fcc81f7b401a6), [`68e44de`](https://github.com/clauderic/dnd-kit/commit/68e44deb6f824b38a58d9b4b1bd81e2efa9193f9)]:\n  - @dnd-kit/abstract@0.3.0\n  - @dnd-kit/dom@0.3.0\n  - @dnd-kit/state@0.3.0\n\n## 0.2.4\n\n### Patch Changes\n\n- [#1874](https://github.com/clauderic/dnd-kit/pull/1874) [`de27fbc`](https://github.com/clauderic/dnd-kit/commit/de27fbca9df12eece3cd53ccbbac34e0eaf113e1) Thanks [@clauderic](https://github.com/clauderic)! - Expose ergonomic type aliases for drag and drop event handlers: `CollisionEvent`, `BeforeDragStartEvent`, `DragStartEvent`, `DragMoveEvent`, `DragOverEvent`, and `DragEndEvent`. These types are re-exported from `@dnd-kit/dom` and `@dnd-kit/react` for convenience.\n\n- Updated dependencies [[`de27fbc`](https://github.com/clauderic/dnd-kit/commit/de27fbca9df12eece3cd53ccbbac34e0eaf113e1), [`c2097c9`](https://github.com/clauderic/dnd-kit/commit/c2097c92df0af496e973cea6b9824f82d0aba92e), [`be7cfe3`](https://github.com/clauderic/dnd-kit/commit/be7cfe3b6cf6a989aefd3e39fd145fe271942b3a), [`6d80680`](https://github.com/clauderic/dnd-kit/commit/6d80680454001f42ab9ec4bd7ae3c764ca33287a), [`0923bc6`](https://github.com/clauderic/dnd-kit/commit/0923bc674273acffd5cf1c35e24f6ff505acc26e), [`5f1b19a`](https://github.com/clauderic/dnd-kit/commit/5f1b19a1f39d845618712bb34314c6133030d557)]:\n  - @dnd-kit/abstract@0.2.4\n  - @dnd-kit/dom@0.2.4\n  - @dnd-kit/state@0.2.4\n\n## 0.2.3\n\n### Patch Changes\n\n- Updated dependencies [[`f90571d`](https://github.com/clauderic/dnd-kit/commit/f90571db8b8a94d751d3eeb80d91b6cd34716f47)]:\n  - @dnd-kit/dom@0.2.3\n  - @dnd-kit/abstract@0.2.3\n  - @dnd-kit/state@0.2.3\n\n## 0.2.2\n\n### Patch Changes\n\n- Updated dependencies [[`5c80bcf`](https://github.com/clauderic/dnd-kit/commit/5c80bcf8affe6accb5b70df3e372f5e864f54b4a)]:\n  - @dnd-kit/dom@0.2.2\n  - @dnd-kit/abstract@0.2.2\n  - @dnd-kit/state@0.2.2\n\n## 0.2.1\n\n### Patch Changes\n\n- Updated dependencies [[`d7f4130`](https://github.com/clauderic/dnd-kit/commit/d7f413079b028feb826ca33243927e855619c0f2)]:\n  - @dnd-kit/dom@0.2.1\n  - @dnd-kit/abstract@0.2.1\n  - @dnd-kit/state@0.2.1\n\n## 0.2.0\n\n### Patch Changes\n\n- [#1823](https://github.com/clauderic/dnd-kit/pull/1823) [`3058ede`](https://github.com/clauderic/dnd-kit/commit/3058ede91dff4e1f5ff399d5c1d04c8681c411f6) Thanks [@github-actions](https://github.com/apps/github-actions)! - Simplified instance management of `manager` to fix a bug where the `manager` returned by `useDragDropManager` was `null` on first mount.\n\n- Updated dependencies [[`e95a9c8`](https://github.com/clauderic/dnd-kit/commit/e95a9c8f448d6b339e0b6fd37546ac7cfdf18edb), [`e95a9c8`](https://github.com/clauderic/dnd-kit/commit/e95a9c8f448d6b339e0b6fd37546ac7cfdf18edb), [`9849887`](https://github.com/clauderic/dnd-kit/commit/984988774a6ff2f19cae4a27612bbd50cfcfa574)]:\n  - @dnd-kit/abstract@0.2.0\n  - @dnd-kit/dom@0.2.0\n  - @dnd-kit/state@0.2.0\n\n## 0.1.21\n\n### Patch Changes\n\n- Updated dependencies [[`3d6219d`](https://github.com/clauderic/dnd-kit/commit/3d6219db072551945556fdac2788e738f77b92c7)]:\n  - @dnd-kit/dom@0.1.21\n  - @dnd-kit/abstract@0.1.21\n  - @dnd-kit/state@0.1.21\n\n## 0.1.20\n\n### Patch Changes\n\n- Updated dependencies [[`3ba5a90`](https://github.com/clauderic/dnd-kit/commit/3ba5a90854669e034a06146fc0268ed0de813257), [`98d4cd4`](https://github.com/clauderic/dnd-kit/commit/98d4cd4047c56589cdf21067526426717bba01c4), [`32448ff`](https://github.com/clauderic/dnd-kit/commit/32448ff11eb3e86a28fc8f6ef7a8a3761e092412)]:\n  - @dnd-kit/dom@0.1.20\n  - @dnd-kit/state@0.1.20\n  - @dnd-kit/abstract@0.1.20\n\n## 0.1.19\n\n### Patch Changes\n\n- Updated dependencies [[`cc7feac`](https://github.com/clauderic/dnd-kit/commit/cc7feacb003b95a744c81e7c75c2aa26d071971f), [`d848327`](https://github.com/clauderic/dnd-kit/commit/d848327b242c6714b36207071ad30e6b4183e865)]:\n  - @dnd-kit/dom@0.1.19\n  - @dnd-kit/state@0.1.19\n  - @dnd-kit/abstract@0.1.19\n\n## 0.1.18\n\n### Patch Changes\n\n- [#1715](https://github.com/clauderic/dnd-kit/pull/1715) [`e502979`](https://github.com/clauderic/dnd-kit/commit/e502979375b9211fef277b8d657d9411f84be96c) Thanks [@github-actions](https://github.com/apps/github-actions)! - Improved TypeScript generics for better type safety and flexibility\n\n  - Enhanced `DragDropManager` to accept generic type parameters with proper constraints, allowing for more flexible type usage while maintaining type safety\n  - Updated `DragDropProvider` to support custom generic types for draggable and droppable entities\n  - Modified React hooks (`useDragDropManager`, `useDragDropMonitor`, `useDragOperation`) to properly infer and return the correct generic types\n  - Changed from concrete `Draggable` and `Droppable` types to generic parameters constrained by `Data` type\n\n- [#1715](https://github.com/clauderic/dnd-kit/pull/1715) [`d6b5736`](https://github.com/clauderic/dnd-kit/commit/d6b57365dce694ecbc86f9c507dab42d0c698a99) Thanks [@github-actions](https://github.com/apps/github-actions)! - **<DragOverlay>**: Added `disabled` prop to temporarily disable `<DragOverlay>` without unmounting it. The `disabled` prop accepts either a `boolean` or function that receives the `source` as input and returns a `boolean`, which can be useful to disable the `<DragOverlay>` based on the `type` or `data` of the `source`.\n\n- [#1714](https://github.com/clauderic/dnd-kit/pull/1714) [`6a27d87`](https://github.com/clauderic/dnd-kit/commit/6a27d87402916b736f8bc1f58d9cb434d079ccef) Thanks [@clauderic](https://github.com/clauderic)! - Refactor renderer to better handle calls to `useOptimistic` to update state during transitions.\n\n- Updated dependencies [[`e502979`](https://github.com/clauderic/dnd-kit/commit/e502979375b9211fef277b8d657d9411f84be96c), [`88942be`](https://github.com/clauderic/dnd-kit/commit/88942be007a743673644ba531fd5c6b1a501bf2e), [`9326d43`](https://github.com/clauderic/dnd-kit/commit/9326d43ba0b9b682ee377011b96d4713711571a5), [`7af261f`](https://github.com/clauderic/dnd-kit/commit/7af261f4e3214a9ebef46d26df607221306eb697), [`b9b182e`](https://github.com/clauderic/dnd-kit/commit/b9b182ef39f7aa8bfe2d331cb20c696b1e9fc15a), [`bb790c9`](https://github.com/clauderic/dnd-kit/commit/bb790c928a9955bd5c7c4312875090e16d891c23)]:\n  - @dnd-kit/dom@0.1.18\n  - @dnd-kit/abstract@0.1.18\n  - @dnd-kit/state@0.1.18\n\n## 0.1.17\n\n### Patch Changes\n\n- Updated dependencies [[`cfb94d4`](https://github.com/clauderic/dnd-kit/commit/cfb94d4fef372059cb87cf0e63bc3ab87f5c8bd8)]:\n  - @dnd-kit/dom@0.1.17\n  - @dnd-kit/abstract@0.1.17\n  - @dnd-kit/state@0.1.17\n\n## 0.1.16\n\n### Patch Changes\n\n- Updated dependencies [[`93911cc`](https://github.com/clauderic/dnd-kit/commit/93911cca237bea302a12749476d4e18b74ac0fa2), [`0f68bb6`](https://github.com/clauderic/dnd-kit/commit/0f68bb6c95b1287d5988b1d5d4e94f1462fc36a5)]:\n  - @dnd-kit/dom@0.1.16\n  - @dnd-kit/abstract@0.1.16\n  - @dnd-kit/state@0.1.16\n\n## 0.1.15\n\n### Patch Changes\n\n- Updated dependencies [[`5539a5a`](https://github.com/clauderic/dnd-kit/commit/5539a5a2991ac86b217dba3ef70fc06331bd0260)]:\n  - @dnd-kit/dom@0.1.15\n  - @dnd-kit/abstract@0.1.15\n  - @dnd-kit/state@0.1.15\n\n## 0.1.14\n\n### Patch Changes\n\n- Updated dependencies [[`4c1e05d`](https://github.com/clauderic/dnd-kit/commit/4c1e05d531a1ffbf32b27d997ebd504532b9616a), [`a97b10c`](https://github.com/clauderic/dnd-kit/commit/a97b10c9d8467c14ef678d3776ea10a2a1e6e027), [`caa3273`](https://github.com/clauderic/dnd-kit/commit/caa3273af1fcee9b4e3b5f1e80e5573c84ab69e3), [`cb47da3`](https://github.com/clauderic/dnd-kit/commit/cb47da3dad7ec617fabb6e8c3b3432a19b354812), [`f295344`](https://github.com/clauderic/dnd-kit/commit/f2953444cbdb195e169fc615454d6be3170bf2a6)]:\n  - @dnd-kit/dom@0.1.14\n  - @dnd-kit/abstract@0.1.14\n  - @dnd-kit/state@0.1.14\n\n## 0.1.13\n\n### Patch Changes\n\n- Updated dependencies [[`c46415a`](https://github.com/clauderic/dnd-kit/commit/c46415a0733f5cbba49cdbd7b6786a0d9add6800), [`382f4e2`](https://github.com/clauderic/dnd-kit/commit/382f4e2f0800a3b85487a1a7a2cefef4484bee70), [`432a0dd`](https://github.com/clauderic/dnd-kit/commit/432a0dd8c67cfdebf0194205979b7249620e73a8), [`a3496c1`](https://github.com/clauderic/dnd-kit/commit/a3496c15c2dc07cc982608b2a4afb1c61b01dbb8), [`4a22b39`](https://github.com/clauderic/dnd-kit/commit/4a22b39267f1fa8d17a62b9c29ff8728733c1478)]:\n  - @dnd-kit/dom@0.1.13\n  - @dnd-kit/abstract@0.1.13\n  - @dnd-kit/state@0.1.13\n\n## 0.1.12\n\n### Patch Changes\n\n- Updated dependencies [[`2e0e2e2`](https://github.com/clauderic/dnd-kit/commit/2e0e2e256d2043831df6a245df9f618ac4b5ecc9), [`b86867b`](https://github.com/clauderic/dnd-kit/commit/b86867b1426525729357654a62f52fe0554f7f73), [`a913f5e`](https://github.com/clauderic/dnd-kit/commit/a913f5e68435c5c0a4a073a7437f265bcc0b5d1d)]:\n  - @dnd-kit/dom@0.1.12\n  - @dnd-kit/abstract@0.1.12\n  - @dnd-kit/state@0.1.12\n\n## 0.1.11\n\n### Patch Changes\n\n- Updated dependencies [[`2370665`](https://github.com/clauderic/dnd-kit/commit/237066598f7da6cd59d78120260788593371e820)]:\n  - @dnd-kit/dom@0.1.11\n  - @dnd-kit/abstract@0.1.11\n  - @dnd-kit/state@0.1.11\n\n## 0.1.10\n\n### Patch Changes\n\n- Updated dependencies [[`a0f5c44`](https://github.com/clauderic/dnd-kit/commit/a0f5c44985b634e8044415db342354493d201f3e)]:\n  - @dnd-kit/dom@0.1.10\n  - @dnd-kit/abstract@0.1.10\n  - @dnd-kit/state@0.1.10\n\n## 0.1.9\n\n### Patch Changes\n\n- Updated dependencies [[`ffdbf52`](https://github.com/clauderic/dnd-kit/commit/ffdbf52a93cbe0c1c785feca57622d4712175a3a)]:\n  - @dnd-kit/dom@0.1.9\n  - @dnd-kit/abstract@0.1.9\n  - @dnd-kit/state@0.1.9\n\n## 0.1.8\n\n### Patch Changes\n\n- Updated dependencies [[`14dc059`](https://github.com/clauderic/dnd-kit/commit/14dc05950ad31c50240ee864431112d7f1b70da0), [`fcd9bb5`](https://github.com/clauderic/dnd-kit/commit/fcd9bb56fafc5ec23ded219bfcd7fdfa31a0caff), [`93d3c7c`](https://github.com/clauderic/dnd-kit/commit/93d3c7c8b01d640b017cf8d2cddc69cc47c74ca5), [`3c625d6`](https://github.com/clauderic/dnd-kit/commit/3c625d61fc8bdba026d445333c2d1ca1d8489294)]:\n  - @dnd-kit/dom@0.1.8\n  - @dnd-kit/abstract@0.1.8\n  - @dnd-kit/state@0.1.8\n\n## 0.1.7\n\n### Patch Changes\n\n- Updated dependencies [[`0618852`](https://github.com/clauderic/dnd-kit/commit/0618852fdeb6948e85d1330febee73e48458e740)]:\n  - @dnd-kit/dom@0.1.7\n  - @dnd-kit/abstract@0.1.7\n  - @dnd-kit/state@0.1.7\n\n## 0.1.6\n\n### Patch Changes\n\n- [#1670](https://github.com/clauderic/dnd-kit/pull/1670) [`a69c390`](https://github.com/clauderic/dnd-kit/commit/a69c390d5b00c186e97913e0fbe32760e63f98b0) Thanks [@GuillaumeSalles](https://github.com/GuillaumeSalles)! - Fix useDroppable effects when inputs are updated\n\n- Updated dependencies [[`7ceb799`](https://github.com/clauderic/dnd-kit/commit/7ceb799c7d214bc8223ec845357a0040c28ae40e), [`299389b`](https://github.com/clauderic/dnd-kit/commit/299389befcc747fe8d79231ba32f73afae88615e), [`4f49d1b`](https://github.com/clauderic/dnd-kit/commit/4f49d1b1de317adaa05cc0b7adacbaffda4fd8c2), [`b18115f`](https://github.com/clauderic/dnd-kit/commit/b18115f4b19c45c76c827921b25e47aad16c91ce), [`ac13c92`](https://github.com/clauderic/dnd-kit/commit/ac13c9298cc8b4eb680039cf17fb10582ab8d023)]:\n  - @dnd-kit/abstract@0.1.6\n  - @dnd-kit/state@0.1.6\n  - @dnd-kit/dom@0.1.6\n\n## 0.1.5\n\n### Patch Changes\n\n- Updated dependencies [[`8fecc41`](https://github.com/clauderic/dnd-kit/commit/8fecc416fb8503fcb555563a44246cd177677b4e), [`a9c17df`](https://github.com/clauderic/dnd-kit/commit/a9c17df386697dc3236f3ba1b7e319cdf4c5a706), [`f31589a`](https://github.com/clauderic/dnd-kit/commit/f31589ae579f1ce574207d44e4016e30b82549e9), [`616db17`](https://github.com/clauderic/dnd-kit/commit/616db17cdded5974febf69718337db0604c613fc)]:\n  - @dnd-kit/dom@0.1.5\n  - @dnd-kit/abstract@0.1.5\n  - @dnd-kit/state@0.1.5\n\n## 0.1.4\n\n### Patch Changes\n\n- Updated dependencies [[`b1d798d`](https://github.com/clauderic/dnd-kit/commit/b1d798d9454bf1d4c47c4e13d11bfd092bdc668b)]:\n  - @dnd-kit/dom@0.1.4\n  - @dnd-kit/abstract@0.1.4\n  - @dnd-kit/state@0.1.4\n\n## 0.1.3\n\n### Patch Changes\n\n- Updated dependencies [[`6c9a9ea`](https://github.com/clauderic/dnd-kit/commit/6c9a9ea060095884c90c72cd5d6b73820467ec29), [`8f91d91`](https://github.com/clauderic/dnd-kit/commit/8f91d9112608d2077c3b6c8fc939aa052606148c), [`79c6519`](https://github.com/clauderic/dnd-kit/commit/79c65195483bee3909177c1b46d1c1073dd2c765), [`52c1ba3`](https://github.com/clauderic/dnd-kit/commit/52c1ba3924be32a9c856d74a3e5221fd05fd91c1), [`6c9a9ea`](https://github.com/clauderic/dnd-kit/commit/6c9a9ea060095884c90c72cd5d6b73820467ec29), [`1bef872`](https://github.com/clauderic/dnd-kit/commit/1bef8722d515079f998dc0608084e1d853e74d3a), [`9a0edf6`](https://github.com/clauderic/dnd-kit/commit/9a0edf64cbde1bd761f3650e043b6612e61a5fab), [`18a7998`](https://github.com/clauderic/dnd-kit/commit/18a7998858e6504f0e3c6f613bd174eb9f68e553), [`a9db4c7`](https://github.com/clauderic/dnd-kit/commit/a9db4c73467d9eda9f95fe5b582948c9fc735f57)]:\n  - @dnd-kit/dom@0.1.3\n  - @dnd-kit/state@0.1.3\n  - @dnd-kit/abstract@0.1.3\n\n## 0.1.2\n\n### Patch Changes\n\n- [#1658](https://github.com/clauderic/dnd-kit/pull/1658) [`42bec2c`](https://github.com/clauderic/dnd-kit/commit/42bec2c507adf5659d70a1d5fba33847b0efe016) Thanks [@github-actions](https://github.com/apps/github-actions)! - Add 'use client' directive to DragDropProvider component\n\n  This change ensures proper client-side rendering in Next.js applications by explicitly marking the DragDropProvider component as a client component.\n\n- [#1658](https://github.com/clauderic/dnd-kit/pull/1658) [`ee55f58`](https://github.com/clauderic/dnd-kit/commit/ee55f582f92dc42cc6eea9ad7492fc782ca6455a) Thanks [@github-actions](https://github.com/apps/github-actions)! - Refactor the drag operation system to improve code organization and maintainability:\n\n  - Split `dragOperation.ts` into multiple focused files:\n    - `operation.ts` - Core drag operation logic\n    - `status.ts` - Status management\n    - `actions.ts` - Drag actions\n  - Update imports and exports to reflect new file structure\n  - Improve type definitions and exports\n\n- Updated dependencies [[`ee55f58`](https://github.com/clauderic/dnd-kit/commit/ee55f582f92dc42cc6eea9ad7492fc782ca6455a), [`4682570`](https://github.com/clauderic/dnd-kit/commit/4682570a6b80868af0e51b1bbbf902430117df43), [`f8d69b0`](https://github.com/clauderic/dnd-kit/commit/f8d69b01f4cf53fc368ef1fca9188c313192928d), [`d04e9a2`](https://github.com/clauderic/dnd-kit/commit/d04e9a2879fb00f092c3f8280c8081a48eebf193), [`ee55f58`](https://github.com/clauderic/dnd-kit/commit/ee55f582f92dc42cc6eea9ad7492fc782ca6455a), [`374f81f`](https://github.com/clauderic/dnd-kit/commit/374f81f84c9401729e2e0ee48520c647a48e5afd)]:\n  - @dnd-kit/state@0.1.2\n  - @dnd-kit/abstract@0.1.2\n  - @dnd-kit/dom@0.1.2\n\n## 0.1.1\n\n### Patch Changes\n\n- [#1656](https://github.com/clauderic/dnd-kit/pull/1656) [`a4f5fc3`](https://github.com/clauderic/dnd-kit/commit/a4f5fc36a3993050eb8ccf693c65f1fffbe455c5) Thanks [@github-actions](https://github.com/apps/github-actions)! - - Update `DragDropEventHandlers` types to be non nullable.\n  - Export `DragDropEvents` and allow them to be generic\n  - Allow `DragDropProvider` to be passed `Data` as a generic\n- Updated dependencies [[`569b6e3`](https://github.com/clauderic/dnd-kit/commit/569b6e3a1d3b199328f7a2362a10b446e657726f), [`a176848`](https://github.com/clauderic/dnd-kit/commit/a1768481e3f7dc4d1176a7fcb363acd020f2c46c), [`f13cbc9`](https://github.com/clauderic/dnd-kit/commit/f13cbc978229844770d3c8aa03135e4352ee2532)]:\n  - @dnd-kit/dom@0.1.1\n  - @dnd-kit/abstract@0.1.1\n  - @dnd-kit/state@0.1.1\n\n## 0.1.0\n\n### Minor Changes\n\n- [#1650](https://github.com/clauderic/dnd-kit/pull/1650) [`23d694b`](https://github.com/clauderic/dnd-kit/commit/23d694b459d7aded0e5674d6da94652ee2f46faf) Thanks [@MateusJabour](https://github.com/MateusJabour)! - Exports sensors from `@dnd-kit/dom` through `@dnd-kit/react`\n\n### Patch Changes\n\n- [#1644](https://github.com/clauderic/dnd-kit/pull/1644) [`6cb931f`](https://github.com/clauderic/dnd-kit/commit/6cb931f43fc5e24e13644677c7939aca90f415fa) Thanks [@github-actions](https://github.com/apps/github-actions)! - Export `DragDropEventHandlers` type\n\n- Updated dependencies [[`00a33c9`](https://github.com/clauderic/dnd-kit/commit/00a33c99e777ab205a45309a4efc8b3560bafdaf), [`043c280`](https://github.com/clauderic/dnd-kit/commit/043c2807a7aa290ce9838a638422245b0bd89cf1), [`ee40aac`](https://github.com/clauderic/dnd-kit/commit/ee40aacda6c015b1f357182c461650fde4c6704e), [`635d94f`](https://github.com/clauderic/dnd-kit/commit/635d94f6e719bcdf50e0024b6d1f09b9bb46c8a5), [`0235cef`](https://github.com/clauderic/dnd-kit/commit/0235cefcf4942c86189e81fde4dc8f19ad420517), [`1ba8700`](https://github.com/clauderic/dnd-kit/commit/1ba8700fd03f3fdc8f4fabe90befbc8fd54d99f5), [`3080d2c`](https://github.com/clauderic/dnd-kit/commit/3080d2c8c122beabc41fb8d79beceb2188a01947)]:\n  - @dnd-kit/abstract@0.1.0\n  - @dnd-kit/dom@0.1.0\n  - @dnd-kit/state@0.1.0\n\n## 0.0.10\n\n### Patch Changes\n\n- [#1606](https://github.com/clauderic/dnd-kit/pull/1606) [`76d2d65`](https://github.com/clauderic/dnd-kit/commit/76d2d65d6555040dc64aa8f277f531808022000e) Thanks [@github-actions](https://github.com/apps/github-actions)! - Introduce the `useDragDropMonitor` hook to the `@dnd-kit/react` package. This hook allows you to monitor drag and drop events within a `DragDropProvider`.\n\n- [`349f0c0`](https://github.com/clauderic/dnd-kit/commit/349f0c0994cbc01f8f86372a938017362d767fe4) Thanks [@clauderic](https://github.com/clauderic)! - Fixed incorrect types for the `useDragDropMonitor` hook.\n\n- Updated dependencies [[`2c53eb9`](https://github.com/clauderic/dnd-kit/commit/2c53eb95a980d143b179af5b7f0a071cdedd9089), [`3155941`](https://github.com/clauderic/dnd-kit/commit/3155941608dbf16ed867e931381e7bb2c65a126d), [`082836e`](https://github.com/clauderic/dnd-kit/commit/082836e517252262b7984b142093ba6c81c43ba8)]:\n  - @dnd-kit/dom@0.0.10\n  - @dnd-kit/abstract@0.0.10\n  - @dnd-kit/state@0.0.10\n\n## 0.0.9\n\n### Patch Changes\n\n- [#1600](https://github.com/clauderic/dnd-kit/pull/1600) [`d86bbc7`](https://github.com/clauderic/dnd-kit/commit/d86bbc7e73ba16296c48f9af29f1893624157a0f) Thanks [@github-actions](https://github.com/apps/github-actions)! - Added `alignment` configuration option to draggable instances to let consumers decide how to align the draggable during the drop animation and while keyboard sorting. Defaults to the center of the target shape.\n\n- [#1600](https://github.com/clauderic/dnd-kit/pull/1600) [`2b76c19`](https://github.com/clauderic/dnd-kit/commit/2b76c19f7608c69b858eaa52b9b3410289ed543b) Thanks [@github-actions](https://github.com/apps/github-actions)! - Added `style` and `tag` props to `<DragOverlay>` component.\n\n- [#1600](https://github.com/clauderic/dnd-kit/pull/1600) [`b8898bc`](https://github.com/clauderic/dnd-kit/commit/b8898bc7718e26aa5d023e3756085a0cd6614f9e) Thanks [@github-actions](https://github.com/apps/github-actions)! - Re-export `isSortable` from `@dnd-kit/react/sortable` so React consumers don't have to import it from `@dnd-kit/dom/sortable`.\n\n- [#1600](https://github.com/clauderic/dnd-kit/pull/1600) [`c5f25c8`](https://github.com/clauderic/dnd-kit/commit/c5f25c8322ae8e2bdccd51f80352539b88a9e34a) Thanks [@github-actions](https://github.com/apps/github-actions)! - Force synchronous re-render when `isDragSource` property is updated from `true` to `false` to enable seamless transition into idle state after drop animation. Without this change, the drop animation can finish before React has had a chance to update the drag source styles back to its idle state, which can cause some flickering.\n\n- Updated dependencies [[`e36d954`](https://github.com/clauderic/dnd-kit/commit/e36d95420148659ba78bdbefd3a0a24ec5d02b8f), [`bb4abcd`](https://github.com/clauderic/dnd-kit/commit/bb4abcd1957f2562072059ad8b5e701893a0fede), [`d86bbc7`](https://github.com/clauderic/dnd-kit/commit/d86bbc7e73ba16296c48f9af29f1893624157a0f), [`f433fb2`](https://github.com/clauderic/dnd-kit/commit/f433fb21aa76c5b4badeec6423e3c930006c8d70), [`7dc0103`](https://github.com/clauderic/dnd-kit/commit/7dc0103c5e5281e9ee61bcd9c3ab493fc9307073), [`cff3c3c`](https://github.com/clauderic/dnd-kit/commit/cff3c3cbbe96a6f401cb3900a8cd5f727a974c2d), [`b7f1cf8`](https://github.com/clauderic/dnd-kit/commit/b7f1cf8f9e15a285c45f896e092f61001335cdff), [`f87d633`](https://github.com/clauderic/dnd-kit/commit/f87d63347529f5c9600bcffb14ad2d15ff6eb107), [`860759b`](https://github.com/clauderic/dnd-kit/commit/860759b15167616c465eef1738fd02c76aa53cb3), [`54e416f`](https://github.com/clauderic/dnd-kit/commit/54e416f6f0aaa19c11827f80b2df796bfe237ba0), [`3e629cc`](https://github.com/clauderic/dnd-kit/commit/3e629cc81dbaf9d112c4f1d2c10c75eb6779cf4e), [`c51778d`](https://github.com/clauderic/dnd-kit/commit/c51778dde5bcd614b1891c5f7659130769ddc9f8), [`86ed6c8`](https://github.com/clauderic/dnd-kit/commit/86ed6c8e203bb167d451c36605c2a0e0d33f0157), [`afedea9`](https://github.com/clauderic/dnd-kit/commit/afedea930bbfd1ea546c2bcbe5f42a3ea8b913fe), [`ce31da7`](https://github.com/clauderic/dnd-kit/commit/ce31da736ec5d4f48bab45430be7b57223d60ee7)]:\n  - @dnd-kit/abstract@0.0.9\n  - @dnd-kit/dom@0.0.9\n  - @dnd-kit/state@0.0.9\n\n## 0.0.8\n\n### Patch Changes\n\n- [#1598](https://github.com/clauderic/dnd-kit/pull/1598) [`426339d`](https://github.com/clauderic/dnd-kit/commit/426339df7bcfdfb08a2d3b9b2eb0abb8c02ed526) Thanks [@github-actions](https://github.com/apps/github-actions)! - Added the `<DragOverlay>` component to ease migration for consumers of `@dnd-kit/core` migrating to `@dnd-kit/react`\n\n- [#1598](https://github.com/clauderic/dnd-kit/pull/1598) [`3ea0d31`](https://github.com/clauderic/dnd-kit/commit/3ea0d314649b186bfe0524d50145625da13a8787) Thanks [@github-actions](https://github.com/apps/github-actions)! - Added optional `register` argument to instances of `Entity` to disable automatic registration of instances that have a manager supplied on initialization.\n\n- [#1598](https://github.com/clauderic/dnd-kit/pull/1598) [`e7fafec`](https://github.com/clauderic/dnd-kit/commit/e7fafec99cdcd44612a905cdb6ba560d42f1d786) Thanks [@github-actions](https://github.com/apps/github-actions)! - Prevent the `Feedback` element that has the popover attribute from being accidentally closed during the drag operation, which would take it out of the top layer.\n\n- [#1597](https://github.com/clauderic/dnd-kit/pull/1597) [`6978d81`](https://github.com/clauderic/dnd-kit/commit/6978d81311e5ac0d9c623b8ceb864740c693ca1d) Thanks [@clauderic](https://github.com/clauderic)! - Introduce `useDeepSignal` hook, which keeps track of which properties are read on an object and automatically re-renders the component when a read signal changes.\n\n- Updated dependencies [[`0de7456`](https://github.com/clauderic/dnd-kit/commit/0de7456ade17b9a0aa127b8adf13495e7fdf1558), [`c9716cf`](https://github.com/clauderic/dnd-kit/commit/c9716cf7b8b846faab451bd2f60c53c77d2d24ba), [`3ea0d31`](https://github.com/clauderic/dnd-kit/commit/3ea0d314649b186bfe0524d50145625da13a8787), [`3cf4db1`](https://github.com/clauderic/dnd-kit/commit/3cf4db126813ebe6ddfc025df5e42e9bfcfa9c38), [`74eedef`](https://github.com/clauderic/dnd-kit/commit/74eedef3441dc07d8fa8dd9337a6b2d748b0cdde), [`42e7256`](https://github.com/clauderic/dnd-kit/commit/42e7256e7fb9c11ed6295b77e30c41ebe66a15d1)]:\n  - @dnd-kit/dom@0.0.8\n  - @dnd-kit/abstract@0.0.8\n  - @dnd-kit/state@0.0.8\n\n## 0.0.7\n\n### Patch Changes\n\n- [#1592](https://github.com/clauderic/dnd-kit/pull/1592) [`cef9b46`](https://github.com/clauderic/dnd-kit/commit/cef9b46c5ed017e6a601b1d0ee9d0f05b7bbd19f) Thanks [@github-actions](https://github.com/apps/github-actions)! - Fix global modifiers set on `DragDropManager` / `<DragDropProvider>` being destroyed after the first drag operation.\n\n- [#1592](https://github.com/clauderic/dnd-kit/pull/1592) [`7c175e1`](https://github.com/clauderic/dnd-kit/commit/7c175e1694fc9c86b5882a5467f0f15fa954bd0a) Thanks [@github-actions](https://github.com/apps/github-actions)! - Fix element refs not being synchronized properly.\n\n- [#1592](https://github.com/clauderic/dnd-kit/pull/1592) [`280b7e2`](https://github.com/clauderic/dnd-kit/commit/280b7e229d5e6a5f067a66038e50c4fbb3b29dc0) Thanks [@github-actions](https://github.com/apps/github-actions)! - Fixed stale modifiers when using `useSortable`.\n\n- Updated dependencies [[`550a868`](https://github.com/clauderic/dnd-kit/commit/550a86870d7441a38a06b3e7c35aa0d7d89e32d1), [`c1dadef`](https://github.com/clauderic/dnd-kit/commit/c1dadef118f8f5f096d36dac314bfe317ea950ce), [`75e23b6`](https://github.com/clauderic/dnd-kit/commit/75e23b6fdfdeadeae1b9a4b2b9be7682f48c10e4), [`cef9b46`](https://github.com/clauderic/dnd-kit/commit/cef9b46c5ed017e6a601b1d0ee9d0f05b7bbd19f), [`730064b`](https://github.com/clauderic/dnd-kit/commit/730064b8b06bd25ebde335305a303fdf4c9a9c7f), [`808f184`](https://github.com/clauderic/dnd-kit/commit/808f184439125cf7e66054b3e85ac087aa04f13b), [`c4e7a7c`](https://github.com/clauderic/dnd-kit/commit/c4e7a7cd98ccaec99fa1037cb1020d3d05cea090), [`280b7e2`](https://github.com/clauderic/dnd-kit/commit/280b7e229d5e6a5f067a66038e50c4fbb3b29dc0), [`84b75fc`](https://github.com/clauderic/dnd-kit/commit/84b75fc3a7b7a555481dbeba533bc28128783e72)]:\n  - @dnd-kit/dom@0.0.7\n  - @dnd-kit/abstract@0.0.7\n  - @dnd-kit/state@0.0.7\n\n## 0.0.6\n\n### Patch Changes\n\n- [#1567](https://github.com/clauderic/dnd-kit/pull/1567) [`081b7f2`](https://github.com/clauderic/dnd-kit/commit/081b7f2a11da2aad8ce3da7f0579974415d1fdf0) Thanks [@chrisvxd](https://github.com/chrisvxd)! - Add source maps to output.\n\n- [#1554](https://github.com/clauderic/dnd-kit/pull/1554) [`7aeac23`](https://github.com/clauderic/dnd-kit/commit/7aeac233e4eae80c2c519b0ed2b90bf19e77f92f) Thanks [@chrisvxd](https://github.com/chrisvxd)! - fix: don't lockup in React strict mode when using DragDropManager with the default manager\n\n- [#1454](https://github.com/clauderic/dnd-kit/pull/1454) [`d26fafe`](https://github.com/clauderic/dnd-kit/commit/d26fafe02c0d3018df03ac3ff2bbd95602ed87ed) Thanks [@github-actions](https://github.com/apps/github-actions)! - Prevent un-necessary re-renders of unused `useSignal` values.\n\n- [#1454](https://github.com/clauderic/dnd-kit/pull/1454) [`d302511`](https://github.com/clauderic/dnd-kit/commit/d302511c96e11e30763361aa6a88d1eb6c6dc0f1) Thanks [@github-actions](https://github.com/apps/github-actions)! - Prevent unstable `ref` from being set to undefined during a drag operation on draggable sources during a drag operation.\n\n- [#1591](https://github.com/clauderic/dnd-kit/pull/1591) [`548f011`](https://github.com/clauderic/dnd-kit/commit/548f011a6b3e91f013ef5a4559197676e218d0e9) Thanks [@chrisvxd](https://github.com/chrisvxd)! - Address typo in React 19 peer dependency.\n\n- [#1590](https://github.com/clauderic/dnd-kit/pull/1590) [`5e55b89`](https://github.com/clauderic/dnd-kit/commit/5e55b8952b7d95e84d554a9b0c4051fd2a05d0bd) Thanks [@chrisvxd](https://github.com/chrisvxd)! - Add React 19 to list of supported peer dependencies.\n\n- [#1454](https://github.com/clauderic/dnd-kit/pull/1454) [`a5a556a`](https://github.com/clauderic/dnd-kit/commit/a5a556abfeec1d78effb3e047f529555e444c020) Thanks [@github-actions](https://github.com/apps/github-actions)! - Fixed React lifecycle regressions related to StrictMode.\n\n- [#1454](https://github.com/clauderic/dnd-kit/pull/1454) [`e2f5d93`](https://github.com/clauderic/dnd-kit/commit/e2f5d935cd21303c9877ce46f7642de7fc9b1ae8) Thanks [@github-actions](https://github.com/apps/github-actions)! - `useSortable`: Make sure `group` and `index` are updated at the same time.\n\n- [#1454](https://github.com/clauderic/dnd-kit/pull/1454) [`ff17c04`](https://github.com/clauderic/dnd-kit/commit/ff17c0497ba5604648319917ff327bd52518d426) Thanks [@github-actions](https://github.com/apps/github-actions)! - Allow dependencies to be passed to `useComputed` hook.\n\n- [#1454](https://github.com/clauderic/dnd-kit/pull/1454) [`3312dcf`](https://github.com/clauderic/dnd-kit/commit/3312dcf89428a65d134f1467597edd8bf0becc0d) Thanks [@github-actions](https://github.com/apps/github-actions)! - Use layout effect to register instances in the `useInstance` hook. This fixes issues with effects running after the browser has painted during drag operations, which can result in invalid shapes or flickering.\n\n- Updated dependencies [[`984b5ab`](https://github.com/clauderic/dnd-kit/commit/984b5ab7bec3145dedb9c9b3b560ffbf7e54b919), [`081b7f2`](https://github.com/clauderic/dnd-kit/commit/081b7f2a11da2aad8ce3da7f0579974415d1fdf0), [`d436037`](https://github.com/clauderic/dnd-kit/commit/d43603740a4d056e9fc7501e9b2117c173b1df4d), [`94920c8`](https://github.com/clauderic/dnd-kit/commit/94920c8a7a3a15accfb806b52e4935637b1a0781), [`a04d3f8`](https://github.com/clauderic/dnd-kit/commit/a04d3f88d380853b97585ab3b608561f7b02ce69), [`0676276`](https://github.com/clauderic/dnd-kit/commit/0676276f5423dbb4e0cad738ac3784937dc7504b), [`8053e4b`](https://github.com/clauderic/dnd-kit/commit/8053e4b4a727c6097b29fb559ce72362d7d6eb2a), [`f400106`](https://github.com/clauderic/dnd-kit/commit/f400106072d12a902f6c113b889c7de97f43e1ea), [`c597b3f`](https://github.com/clauderic/dnd-kit/commit/c597b3fe1514f10e227c287dc8ad875134e9b4cb), [`a8542de`](https://github.com/clauderic/dnd-kit/commit/a8542de56d39c3cd3b6ef981172a0782454295b2), [`a9798f4`](https://github.com/clauderic/dnd-kit/commit/a9798f43450e406e8cb235b7d5fba8bb809fd1d7), [`f7458d9`](https://github.com/clauderic/dnd-kit/commit/f7458d9dc32824dbea3a6d5dfb29236f19a2c073), [`b750c05`](https://github.com/clauderic/dnd-kit/commit/b750c05b4b14f5d9817dc07d974d40b74470e904), [`e70b29a`](https://github.com/clauderic/dnd-kit/commit/e70b29ae64837e424f7279c95112fb6e420c4dcc), [`3d0b00a`](https://github.com/clauderic/dnd-kit/commit/3d0b00a663b9dc38ccd7a46544c94a342694b626), [`e6a8e01`](https://github.com/clauderic/dnd-kit/commit/e6a8e018d2d7ad9a11e5b05f07774c7e3ac08da3), [`7ef9864`](https://github.com/clauderic/dnd-kit/commit/7ef98642207c8beac1ca7e2704ce8805767dc89d), [`4d1a030`](https://github.com/clauderic/dnd-kit/commit/4d1a0306c920ae064eb5b30c4c02961f50460c84), [`51be6df`](https://github.com/clauderic/dnd-kit/commit/51be6dfe1b8cb42f74df34c76098e197b9208f81), [`fe76033`](https://github.com/clauderic/dnd-kit/commit/fe7603330fb4b0a397c0e2af641df94fc2879c35), [`62a8118`](https://github.com/clauderic/dnd-kit/commit/62a81180c84f7782b14b69b56f891c810e7d0f69), [`a5933d8`](https://github.com/clauderic/dnd-kit/commit/a5933d8607e63ed08818ffab43e858863cb35d47), [`0c7bf85`](https://github.com/clauderic/dnd-kit/commit/0c7bf85897992dc48c3cf2f1deeaa896995bfcc3), [`f219549`](https://github.com/clauderic/dnd-kit/commit/f219549087d9100cee53ab0cf35d820fe256aa85), [`bfc8ab2`](https://github.com/clauderic/dnd-kit/commit/bfc8ab21cfd9c16a8d90ab250386e6d52d0a40a3), [`a5a556a`](https://github.com/clauderic/dnd-kit/commit/a5a556abfeec1d78effb3e047f529555e444c020), [`b5edff1`](https://github.com/clauderic/dnd-kit/commit/b5edff19279c07bbcd54ebc4579817b8a36cfff5), [`96f28ef`](https://github.com/clauderic/dnd-kit/commit/96f28ef86adf95e77540732d39033c7f3fb0fd04), [`3fb972e`](https://github.com/clauderic/dnd-kit/commit/3fb972e228aabfe07d662b77c642405f909fddb0), [`5b36f8f`](https://github.com/clauderic/dnd-kit/commit/5b36f8fb36f5a4468793b469425b5c0461426f56), [`69bfad7`](https://github.com/clauderic/dnd-kit/commit/69bfad7d795947987a4281f1a61f81b6a7839fe8), [`c42a11b`](https://github.com/clauderic/dnd-kit/commit/c42a11b60e950d50f8c243bdf8df4f32e1d47d23)]:\n  - @dnd-kit/abstract@0.0.6\n  - @dnd-kit/dom@0.0.6\n  - @dnd-kit/state@0.0.6\n\n## 0.0.5\n\n### Patch Changes\n\n- Updated dependencies [[`e9be505`](https://github.com/clauderic/dnd-kit/commit/e9be5051b5c99e522fb6efd028d425220b171890)]:\n  - @dnd-kit/abstract@0.0.5\n  - @dnd-kit/dom@0.0.5\n  - @dnd-kit/state@0.0.5\n\n## 0.0.4\n\n### Patch Changes\n\n- [#1443](https://github.com/clauderic/dnd-kit/pull/1443) [`2ccc27c`](https://github.com/clauderic/dnd-kit/commit/2ccc27c566b13d6de46719d0ad5978d655261177) Thanks [@clauderic](https://github.com/clauderic)! - Added `status` property to draggable instances to know the current status of a draggable instance. Useful to know if an instance is being dropped.\n\n- [#1443](https://github.com/clauderic/dnd-kit/pull/1443) [`e0d80f5`](https://github.com/clauderic/dnd-kit/commit/e0d80f59c733b3adcf1fc89d29aa80257e7edd98) Thanks [@clauderic](https://github.com/clauderic)! - Refactor the lifecycle to allow `manager` to be optional and provided later during the lifecycle of `draggable` / `droppable` / `sortable` instances.\n\n- [#1443](https://github.com/clauderic/dnd-kit/pull/1443) [`794cf2f`](https://github.com/clauderic/dnd-kit/commit/794cf2f4bdeeb57a197effb1df654c7c44cf34a3) Thanks [@clauderic](https://github.com/clauderic)! - Removed `options` and `options.register` from `Entity` base class. Passing an `undefined` manager when instantiating `Draggable` and `Droppable` now has the same effect.\n\n- Updated dependencies [[`2ccc27c`](https://github.com/clauderic/dnd-kit/commit/2ccc27c566b13d6de46719d0ad5978d655261177), [`1b9df29`](https://github.com/clauderic/dnd-kit/commit/1b9df29e03306c6d3fb3e8b2b321486f5c62847a), [`4dbcb1c`](https://github.com/clauderic/dnd-kit/commit/4dbcb1c87c34273fecf7257cd4cb5ac67b42d3a4), [`a4d9150`](https://github.com/clauderic/dnd-kit/commit/a4d91500124698abf58355592913f84d438faa3d), [`e0d80f5`](https://github.com/clauderic/dnd-kit/commit/e0d80f59c733b3adcf1fc89d29aa80257e7edd98), [`794cf2f`](https://github.com/clauderic/dnd-kit/commit/794cf2f4bdeeb57a197effb1df654c7c44cf34a3)]:\n  - @dnd-kit/abstract@0.0.4\n  - @dnd-kit/dom@0.0.4\n  - @dnd-kit/state@0.0.4\n\n## 0.0.3\n\n### Patch Changes\n\n- [`8530c12`](https://github.com/clauderic/dnd-kit/commit/8530c122c8db7723a8c13a207a11487b3354cb59) Thanks [@clauderic](https://github.com/clauderic)! - Fixed lifecycle related issues.\n\n- [#1440](https://github.com/clauderic/dnd-kit/pull/1440) [`86e5191`](https://github.com/clauderic/dnd-kit/commit/86e519187f0072761321e44cb11abf2f4797169e) Thanks [@clauderic](https://github.com/clauderic)! - Fixed a bug where `useDraggable`, `useDroppable` and `useSortable` would not un-register from the old manager and re-register themselves with the new manager when its reference changes.\n\n- [`8530c12`](https://github.com/clauderic/dnd-kit/commit/8530c122c8db7723a8c13a207a11487b3354cb59) Thanks [@clauderic](https://github.com/clauderic)! - Add lazy import for `DragDropProvider`.\n\n- [#1440](https://github.com/clauderic/dnd-kit/pull/1440) [`5ccd5e6`](https://github.com/clauderic/dnd-kit/commit/5ccd5e668fb8d736ec3c195116559cb5c5684e80) Thanks [@clauderic](https://github.com/clauderic)! - Update modifiers on the `Draggable` instances when `useDraggable` receives updated modifiers\n\n- [#1440](https://github.com/clauderic/dnd-kit/pull/1440) [`8f421ee`](https://github.com/clauderic/dnd-kit/commit/8f421ee00201435ead41ac4c45dae72bf030b5a5) Thanks [@clauderic](https://github.com/clauderic)! - Add `\"use client\"` hints to `@dnd-kit/react` exports.\n\n- Updated dependencies [[`8530c12`](https://github.com/clauderic/dnd-kit/commit/8530c122c8db7723a8c13a207a11487b3354cb59), [`8e45c2a`](https://github.com/clauderic/dnd-kit/commit/8e45c2a9d750283296b56b05a887be89fe7b0184), [`5ccd5e6`](https://github.com/clauderic/dnd-kit/commit/5ccd5e668fb8d736ec3c195116559cb5c5684e80), [`886de33`](https://github.com/clauderic/dnd-kit/commit/886de33d0df851ebdcb3fcf2915f9623069b06d1)]:\n  - @dnd-kit/dom@0.0.3\n  - @dnd-kit/abstract@0.0.3\n  - @dnd-kit/state@0.0.3\n\n## 0.0.2\n\n### Patch Changes\n\n- [#1430](https://github.com/clauderic/dnd-kit/pull/1430) [`6c84308`](https://github.com/clauderic/dnd-kit/commit/6c84308b45c55ca1324a5c752b0ec117235da9e2) Thanks [@clauderic](https://github.com/clauderic)! - - `useDraggable`: Fixed a bug where the `element` was not properly being set on initialization\n\n- [#1430](https://github.com/clauderic/dnd-kit/pull/1430) [`2c3ad5e`](https://github.com/clauderic/dnd-kit/commit/2c3ad5eab3aabfd0aaa5a3a299dae1e307e8edaf) Thanks [@clauderic](https://github.com/clauderic)! - - Fix issues with `<StrictMode>` in React\n\n- Updated dependencies [[`6c84308`](https://github.com/clauderic/dnd-kit/commit/6c84308b45c55ca1324a5c752b0ec117235da9e2), [`6c84308`](https://github.com/clauderic/dnd-kit/commit/6c84308b45c55ca1324a5c752b0ec117235da9e2), [`d273f70`](https://github.com/clauderic/dnd-kit/commit/d273f700c3f580cb781bd004ed025bbceee20c4e), [`34c6fdc`](https://github.com/clauderic/dnd-kit/commit/34c6fdc6fb20c092a9370e35f22bf55d8065130c), [`2c3ad5e`](https://github.com/clauderic/dnd-kit/commit/2c3ad5eab3aabfd0aaa5a3a299dae1e307e8edaf)]:\n  - @dnd-kit/dom@0.0.2\n  - @dnd-kit/state@0.0.2\n  - @dnd-kit/abstract@0.0.2\n"
  },
  {
    "path": "packages/react/README.md",
    "content": "# @dnd-kit/react\n\n[![Stable release](https://img.shields.io/npm/v/@dnd-kit/react.svg)](https://npm.im/@dnd-kit/react)\n\nThe React adapter for **@dnd-kit** — a lightweight, performant, and extensible drag and drop toolkit. Built on top of `@dnd-kit/dom`.\n\n## Installation\n\n```bash\nnpm install @dnd-kit/react\n```\n\n## Quick start\n\n```tsx\nimport {DragDropProvider, useDraggable, useDroppable} from '@dnd-kit/react';\n\nfunction App() {\n  const [parent, setParent] = useState(null);\n\n  return (\n    <DragDropProvider\n      onDragEnd={(event) => {\n        if (event.canceled) return;\n        setParent(event.operation.target?.id ?? null);\n      }}\n    >\n      {parent == null ? <Draggable /> : null}\n      <Droppable>{parent ? <Draggable /> : 'Drop here'}</Droppable>\n    </DragDropProvider>\n  );\n}\n```\n\n## Hooks\n\n| Hook           | Import                    | Description                        |\n| -------------- | ------------------------- | ---------------------------------- |\n| `useDraggable` | `@dnd-kit/react`          | Make an element draggable          |\n| `useDroppable` | `@dnd-kit/react`          | Create a drop target               |\n| `useSortable`  | `@dnd-kit/react/sortable` | Combine drag and drop with sorting |\n\n## Components\n\n- **`<DragDropProvider>`** — Wraps your drag and drop interface, manages sensors, plugins, and events.\n- **`<DragOverlay>`** — Renders a custom overlay element during drag operations.\n\n## Documentation\n\nVisit [dndkit.com](https://dndkit.com/react) for full documentation, guides, and interactive examples.\n"
  },
  {
    "path": "packages/react/package.json",
    "content": "{\n  \"name\": \"@dnd-kit/react\",\n  \"version\": \"0.3.2\",\n  \"main\": \"./index.cjs\",\n  \"module\": \"./index.js\",\n  \"type\": \"module\",\n  \"types\": \"./index.d.ts\",\n  \"sideEffects\": false,\n  \"license\": \"MIT\",\n  \"files\": [\n    \"LICENSE\",\n    \"README.md\",\n    \"index.js\",\n    \"index.d.ts\",\n    \"index.cjs\",\n    \"hooks.js\",\n    \"hooks.d.ts\",\n    \"hooks.cjs\",\n    \"sortable.js\",\n    \"sortable.d.ts\",\n    \"sortable.cjs\",\n    \"utilities.js\",\n    \"utilities.d.ts\",\n    \"utilities.cjs\"\n  ],\n  \"exports\": {\n    \".\": {\n      \"types\": \"./index.d.ts\",\n      \"import\": \"./index.js\",\n      \"require\": \"./index.cjs\"\n    },\n    \"./hooks\": {\n      \"types\": \"./hooks.d.ts\",\n      \"import\": \"./hooks.js\",\n      \"require\": \"./hooks.cjs\"\n    },\n    \"./sortable\": {\n      \"types\": \"./sortable.d.ts\",\n      \"import\": \"./sortable.js\",\n      \"require\": \"./sortable.cjs\"\n    },\n    \"./utilities\": {\n      \"types\": \"./utilities.d.ts\",\n      \"import\": \"./utilities.js\",\n      \"require\": \"./utilities.cjs\"\n    }\n  },\n  \"scripts\": {\n    \"build\": \"bun build:utilities && bun build:hooks && bun build:core && bun build:sortable\",\n    \"build:core\": \"tsup src/core/index.ts\",\n    \"build:hooks\": \"tsup --entry.hooks src/hooks/index.ts\",\n    \"build:sortable\": \"tsup --entry.sortable src/sortable/index.ts\",\n    \"build:utilities\": \"tsup --entry.utilities src/utilities/index.ts\",\n    \"dev\": \"bun build:utilities --watch & bun build:hooks --watch & bun build:core --watch & bun build:sortable --watch\",\n    \"lint\": \"TIMING=1 eslint src/**/*.ts* --fix\",\n    \"clean\": \"rm -rf .turbo && rm -rf node_modules && rm -rf dist\"\n  },\n  \"dependencies\": {\n    \"@dnd-kit/abstract\": \"^0.3.2\",\n    \"@dnd-kit/dom\": \"^0.3.2\",\n    \"@dnd-kit/state\": \"^0.3.2\",\n    \"tslib\": \"^2.6.2\"\n  },\n  \"peerDependencies\": {\n    \"react\": \"^18.0.0 || ^19.0.0\",\n    \"react-dom\": \"^18.0.0 || ^19.0.0\"\n  },\n  \"devDependencies\": {\n    \"@types/react\": \"^19.0.8\",\n    \"@types/react-dom\": \"^19.0.3\",\n    \"eslint\": \"^8.38.0\",\n    \"@dnd-kit/eslint-config\": \"*\",\n    \"react\": \"^19.0.0\",\n    \"tsup\": \"8.3.0\",\n    \"typescript\": \"^5.5.2\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/clauderic/dnd-kit\"\n  }\n}\n"
  },
  {
    "path": "packages/react/src/core/context/DragDropProvider.tsx",
    "content": "'use client';\n\nimport {\n  useEffect,\n  useRef,\n  useInsertionEffect,\n  type PropsWithChildren,\n} from 'react';\nimport type {Data, DragDropEventHandlers} from '@dnd-kit/abstract';\nimport {\n  DragDropManager,\n  defaultPreset,\n  resolveCustomizable,\n} from '@dnd-kit/dom';\nimport type {DragDropManagerInput, Draggable, Droppable} from '@dnd-kit/dom';\nimport {useLatest, useOnValueChange} from '@dnd-kit/react/hooks';\nimport {deepEqual} from '@dnd-kit/state';\n\nimport {DragDropContext} from './context.ts';\nimport {Renderer, type ReactRenderer} from './renderer.ts';\n\nexport type Events<\n  T extends Data = Data,\n  U extends Draggable<T> = Draggable<T>,\n  V extends Droppable<T> = Droppable<T>,\n  W extends DragDropManager<T, U, V> = DragDropManager<T, U, V>,\n> = DragDropEventHandlers<U, V, W>;\n\nexport interface Props<\n  T extends Data = Data,\n  U extends Draggable<T> = Draggable<T>,\n  V extends Droppable<T> = Droppable<T>,\n  W extends DragDropManager<T, U, V> = DragDropManager<T, U, V>,\n> extends DragDropManagerInput,\n    PropsWithChildren {\n  manager?: W;\n  onBeforeDragStart?: Events<T, U, V, W>['beforedragstart'];\n  onCollision?: Events<T, U, V, W>['collision'];\n  onDragStart?: Events<T, U, V, W>['dragstart'];\n  onDragMove?: Events<T, U, V, W>['dragmove'];\n  onDragOver?: Events<T, U, V, W>['dragover'];\n  onDragEnd?: Events<T, U, V, W>['dragend'];\n}\n\nconst options = [undefined, deepEqual] as const;\n\nexport function DragDropProvider<\n  T extends Data = Data,\n  U extends Draggable<T> = Draggable<T>,\n  V extends Droppable<T> = Droppable<T>,\n  W extends DragDropManager<T, U, V> = DragDropManager<T, U, V>,\n>({\n  children,\n  onCollision,\n  onBeforeDragStart,\n  onDragStart,\n  onDragMove,\n  onDragOver,\n  onDragEnd,\n  ...input\n}: Props<T, U, V, W>) {\n  const rendererRef = useRef<ReactRenderer | null>(null);\n  const {\n    plugins: pluginsInput,\n    modifiers: modifiersInput,\n    sensors: sensorsInput,\n  } = input;\n  const plugins = resolveCustomizable(pluginsInput, defaultPreset.plugins);\n  const sensors = resolveCustomizable(sensorsInput, defaultPreset.sensors);\n  const modifiers = resolveCustomizable(\n    modifiersInput,\n    defaultPreset.modifiers\n  );\n  const handleBeforeDragStart = useLatest(onBeforeDragStart);\n  const handleDragStart = useLatest(onDragStart);\n  const handleDragOver = useLatest(onDragOver);\n  const handleDragMove = useLatest(onDragMove);\n  const handleDragEnd = useLatest(onDragEnd);\n  const handleCollision = useLatest(onCollision);\n  const manager = useStableInstance<W>(() => {\n    return input.manager ?? (new DragDropManager<T, U, V>(input) as W);\n  });\n\n  useEffect(() => {\n    if (!rendererRef.current) throw new Error('Renderer not found');\n\n    const {renderer, trackRendering} = rendererRef.current;\n    const {monitor} = manager;\n\n    manager.renderer = renderer;\n\n    const listeners = [\n      monitor.addEventListener('beforedragstart', (event) => {\n        const callback = handleBeforeDragStart.current;\n\n        if (callback) {\n          trackRendering(() => callback(event, manager));\n        }\n      }),\n      monitor.addEventListener('dragstart', (event) =>\n        handleDragStart.current?.(event, manager)\n      ),\n      monitor.addEventListener('dragover', (event) => {\n        const callback = handleDragOver.current;\n\n        if (callback) {\n          trackRendering(() => callback(event, manager));\n        }\n      }),\n      monitor.addEventListener('dragmove', (event) => {\n        const callback = handleDragMove.current;\n\n        if (callback) {\n          trackRendering(() => callback(event, manager));\n        }\n      }),\n      monitor.addEventListener('dragend', (event) => {\n        const callback = handleDragEnd.current;\n\n        if (callback) {\n          trackRendering(() => callback(event, manager));\n        }\n      }),\n      monitor.addEventListener('collision', (event) =>\n        handleCollision.current?.(event, manager)\n      ),\n    ];\n\n    return () => listeners.forEach((dispose) => dispose());\n  }, [manager]);\n\n  useOnValueChange(\n    plugins,\n    () => manager && (manager.plugins = plugins),\n    ...options\n  );\n  useOnValueChange(\n    sensors,\n    () => manager && (manager.sensors = sensors),\n    ...options\n  );\n  useOnValueChange(\n    modifiers,\n    () => manager && (manager.modifiers = modifiers),\n    ...options\n  );\n\n  return (\n    <DragDropContext.Provider value={manager as any}>\n      <Renderer ref={rendererRef}>{children}</Renderer>\n      {children}\n    </DragDropContext.Provider>\n  );\n}\n\nfunction useStableInstance<T extends {destroy(): void}>(create: () => T): T {\n  const ref = useRef<T>(null);\n\n  if (!ref.current) {\n    ref.current = create();\n  }\n\n  useInsertionEffect(() => {\n    return () => ref.current?.destroy();\n  }, []);\n\n  return ref.current;\n}\n"
  },
  {
    "path": "packages/react/src/core/context/context.ts",
    "content": "'use client';\n\nimport {createContext} from 'react';\nimport {DragDropManager} from '@dnd-kit/dom';\n\nexport const defaultManager = new DragDropManager();\n\nexport const DragDropContext = createContext<DragDropManager | null>(\n  defaultManager\n);\n"
  },
  {
    "path": "packages/react/src/core/context/hooks.ts",
    "content": "import {useContext} from 'react';\n\nimport {DragDropContext} from './context.ts';\nimport {useComputed} from '../../hooks/useComputed.ts';\n\nexport function useDragDropManager() {\n  return useContext(DragDropContext);\n}\n\nexport function useDragOperation() {\n  const manager = useDragDropManager();\n\n  const source = useComputed(() => manager?.dragOperation.source);\n  const target = useComputed(() => manager?.dragOperation.target);\n\n  return {\n    get source() {\n      return source.value;\n    },\n    get target() {\n      return target.value;\n    },\n  };\n}\n"
  },
  {
    "path": "packages/react/src/core/context/renderer.ts",
    "content": "import {\n  forwardRef,\n  memo,\n  startTransition,\n  useImperativeHandle,\n  useState,\n  useRef,\n  useMemo,\n} from 'react';\nimport type {Renderer as AbstractRenderer} from '@dnd-kit/abstract';\nimport {useIsomorphicLayoutEffect} from '@dnd-kit/react/hooks';\n\nexport type ReactRenderer = {\n  renderer: AbstractRenderer;\n  trackRendering: (callback: () => void) => void;\n};\n\nexport const Renderer = memo(\n  forwardRef<ReactRenderer, {children: React.ReactNode}>(({children}, ref) => {\n    const [transitionCount, setTransitionCount] = useState(0);\n    const rendering = useRef<Promise<void>>(null);\n    const resolver = useRef<() => void>(null);\n    const renderer = useMemo<ReactRenderer>(\n      () => ({\n        renderer: {\n          get rendering() {\n            return rendering.current ?? Promise.resolve();\n          },\n        },\n        trackRendering(callback: () => void) {\n          if (!rendering.current) {\n            rendering.current = new Promise<void>((resolve) => {\n              resolver.current = resolve;\n            });\n          }\n\n          startTransition(() => {\n            callback();\n            setTransitionCount((count) => count + 1);\n          });\n        },\n      }),\n      []\n    );\n\n    useIsomorphicLayoutEffect(() => {\n      resolver.current?.();\n      rendering.current = null;\n    }, [children, transitionCount]);\n\n    useImperativeHandle(ref, () => renderer);\n\n    return null;\n  })\n);\n"
  },
  {
    "path": "packages/react/src/core/draggable/DragOverlay.tsx",
    "content": "import {createElement, useEffect, useMemo, useRef, type ReactNode} from 'react';\nimport {useComputed, useDeepSignal} from '@dnd-kit/react/hooks';\nimport {DragDropManager, Draggable, Feedback} from '@dnd-kit/dom';\nimport type {DropAnimation} from '@dnd-kit/dom';\nimport {Data} from '@dnd-kit/abstract';\n\nimport {useDragDropManager} from '../hooks/useDragDropManager.ts';\nimport {DragDropContext} from '../context/context.ts';\n\nexport interface Props<T extends Data, U extends Draggable<T>> {\n  className?: string;\n  children: ReactNode | ((source: U) => ReactNode);\n  /**\n   * Customize or disable the drop animation that plays when a drag operation ends.\n   *\n   * - `undefined` – use the default animation (250ms ease)\n   * - `null` – disable the drop animation entirely\n   * - `{duration, easing}` – customize the animation timing\n   * - `(context) => Promise<void> | void` – provide a fully custom animation function\n   */\n  dropAnimation?: DropAnimation | null;\n  style?: React.CSSProperties;\n  tag?: string;\n  disabled?: boolean | ((source: U | null) => boolean);\n}\n\nexport function DragOverlay<T extends Data, U extends Draggable<T>>({\n  children,\n  className,\n  dropAnimation,\n  style,\n  tag,\n  disabled,\n}: Props<T, U>) {\n  const ref = useRef<HTMLDivElement | null>(null);\n  const manager = useDragDropManager<T, U>();\n  const source =\n    useComputed(() => manager?.dragOperation.source, [manager]).value ?? null;\n  const isDisabled =\n    typeof disabled === 'function' ? disabled(source) : disabled;\n\n  useEffect(() => {\n    if (!ref.current || !manager || isDisabled) return;\n\n    const feedback = manager.plugins.find(\n      (plugin) => plugin instanceof Feedback\n    );\n\n    if (!feedback) return;\n\n    feedback.overlay = ref.current;\n\n    return () => {\n      feedback.overlay = undefined;\n    };\n  }, [manager, isDisabled]);\n\n  useEffect(() => {\n    if (!manager) return;\n\n    const feedback = manager.plugins.find(\n      (plugin) => plugin instanceof Feedback\n    );\n\n    if (!feedback) return;\n\n    feedback.dropAnimation = dropAnimation;\n\n    return () => {\n      feedback.dropAnimation = undefined;\n    };\n  }, [manager, dropAnimation]);\n\n  // Prevent children of the overlay from registering themselves as draggables or droppables\n  const patchedManager = useMemo(() => {\n    if (!manager) return null;\n\n    const patchedRegistry = new Proxy(manager.registry, {\n      get(target, property) {\n        if (property === 'register' || property === 'unregister') {\n          return noop;\n        }\n\n        return target[property as keyof typeof target];\n      },\n    });\n\n    return new Proxy(manager, {\n      get(target, property) {\n        if (property === 'registry') {\n          return patchedRegistry;\n        }\n\n        return target[property as keyof typeof target];\n      },\n    });\n  }, [manager]);\n\n  return (\n    <DragDropContext.Provider value={patchedManager as DragDropManager | null}>\n      {createElement(\n        tag || 'div',\n        {ref, className, style, 'data-dnd-overlay': true},\n\n        renderChildren()\n      )}\n    </DragDropContext.Provider>\n  );\n\n  function renderChildren() {\n    if (!source || isDisabled) return null;\n\n    if (typeof children === 'function') {\n      return <Children source={source}>{children}</Children>;\n    }\n\n    return children;\n  }\n}\n\nfunction noop() {\n  return () => {};\n}\n\nfunction Children<T extends Data, U extends Draggable<T>>({\n  children,\n  source,\n}: {\n  children: (source: U) => ReactNode;\n  source: U;\n}) {\n  return children(useDeepSignal(source));\n}\n"
  },
  {
    "path": "packages/react/src/core/draggable/useDraggable.ts",
    "content": "import {useCallback} from 'react';\nimport type {Data} from '@dnd-kit/abstract';\nimport {deepEqual} from '@dnd-kit/state';\nimport {Draggable} from '@dnd-kit/dom';\nimport type {DraggableInput} from '@dnd-kit/dom';\nimport {\n  useOnValueChange,\n  useOnElementChange,\n  useDeepSignal,\n} from '@dnd-kit/react/hooks';\nimport {currentValue, type RefOrValue} from '@dnd-kit/react/utilities';\n\nimport {useInstance} from '../hooks/useInstance.ts';\n\nexport interface UseDraggableInput<T extends Data = Data>\n  extends Omit<DraggableInput<T>, 'handle' | 'element'> {\n  handle?: RefOrValue<Element>;\n  element?: RefOrValue<Element>;\n}\n\nexport function useDraggable<T extends Data = Data>(\n  input: UseDraggableInput<T>\n) {\n  const {disabled, data, element, handle, id, modifiers, sensors, plugins} =\n    input;\n  const draggable = useInstance(\n    (manager) =>\n      new Draggable(\n        {\n          ...input,\n          register: false,\n          handle: currentValue(handle),\n          element: currentValue(element),\n        },\n        manager\n      )\n  );\n  const trackedDraggable = useDeepSignal(draggable, shouldUpdateSynchronously);\n\n  useOnValueChange(id, () => (draggable.id = id));\n  useOnElementChange(handle, (handle) => (draggable.handle = handle));\n  useOnElementChange(element, (element) => (draggable.element = element));\n  useOnValueChange(data, () => data && (draggable.data = data));\n  useOnValueChange(disabled, () => (draggable.disabled = disabled === true));\n  useOnValueChange(sensors, () => (draggable.sensors = sensors));\n  useOnValueChange(\n    modifiers,\n    () => (draggable.modifiers = modifiers),\n    undefined,\n    deepEqual\n  );\n  useOnValueChange(plugins, () => (draggable.plugins = plugins), undefined, deepEqual);\n  useOnValueChange(\n    input.alignment,\n    () => (draggable.alignment = input.alignment)\n  );\n\n  return {\n    draggable: trackedDraggable,\n    get isDragging() {\n      return trackedDraggable.isDragging;\n    },\n    get isDropping() {\n      return trackedDraggable.isDropping;\n    },\n    get isDragSource() {\n      return trackedDraggable.isDragSource;\n    },\n    handleRef: useCallback(\n      (element: Element | null) => {\n        draggable.handle = element ?? undefined;\n      },\n      [draggable]\n    ),\n    ref: useCallback(\n      (element: Element | null) => {\n        if (\n          !element &&\n          draggable.element?.isConnected &&\n          !draggable.manager?.dragOperation.status.idle\n        ) {\n          return;\n        }\n\n        draggable.element = element ?? undefined;\n      },\n      [draggable]\n    ),\n  };\n}\n\nfunction shouldUpdateSynchronously(key: string, oldValue: any, newValue: any) {\n  // Update synchronously after drop animation\n  if (key === 'isDragSource' && !newValue && oldValue) return true;\n\n  return false;\n}\n"
  },
  {
    "path": "packages/react/src/core/droppable/useDroppable.ts",
    "content": "import {useCallback} from 'react';\nimport type {Data} from '@dnd-kit/abstract';\nimport {Droppable} from '@dnd-kit/dom';\nimport {deepEqual} from '@dnd-kit/state';\nimport type {DroppableInput} from '@dnd-kit/dom';\nimport {\n  useComputed,\n  useOnValueChange,\n  useOnElementChange,\n  useDeepSignal,\n} from '@dnd-kit/react/hooks';\nimport {currentValue, type RefOrValue} from '@dnd-kit/react/utilities';\n\nimport {useInstance} from '../hooks/useInstance.ts';\nimport {defaultCollisionDetection} from '@dnd-kit/collision';\n\nexport interface UseDroppableInput<T extends Data = Data>\n  extends Omit<DroppableInput<T>, 'element'> {\n  element?: RefOrValue<Element>;\n}\n\nexport function useDroppable<T extends Data = Data>(\n  input: UseDroppableInput<T>\n) {\n  const {collisionDetector, data, disabled, element, id, accept, type} = input;\n  const droppable = useInstance(\n    (manager) =>\n      new Droppable(\n        {\n          ...input,\n          register: false,\n          element: currentValue(element),\n        },\n        manager\n      )\n  );\n  const trackedDroppalbe = useDeepSignal(droppable);\n\n  useOnValueChange(id, () => (droppable.id = id));\n  useOnElementChange(element, (element) => (droppable.element = element));\n  useOnValueChange(\n    accept,\n    () => (droppable.accept = accept),\n    undefined,\n    deepEqual\n  );\n  useOnValueChange(\n    collisionDetector,\n    () =>\n      (droppable.collisionDetector =\n        collisionDetector ?? defaultCollisionDetection)\n  );\n  useOnValueChange(data, () => data && (droppable.data = data));\n  useOnValueChange(disabled, () => (droppable.disabled = disabled === true));\n  useOnValueChange(type, () => (droppable.type = type));\n\n  return {\n    droppable: trackedDroppalbe,\n    get isDropTarget() {\n      return trackedDroppalbe.isDropTarget;\n    },\n    ref: useCallback(\n      (element: Element | null) => {\n        if (\n          !element &&\n          droppable.element?.isConnected &&\n          !droppable.manager?.dragOperation.status.idle\n        ) {\n          return;\n        }\n\n        droppable.element = element ?? undefined;\n      },\n      [droppable]\n    ),\n  };\n}\n"
  },
  {
    "path": "packages/react/src/core/hooks/useDragDropManager.ts",
    "content": "import {useContext} from 'react';\nimport type {Data} from '@dnd-kit/abstract';\nimport type {DragDropManager, Draggable, Droppable} from '@dnd-kit/dom';\n\nimport {DragDropContext} from '../context/context.ts';\n\nexport function useDragDropManager<\n  T extends Data = Data,\n  U extends Draggable<T> = Draggable<T>,\n  V extends Droppable<T> = Droppable<T>,\n  W extends DragDropManager<T, U, V> = DragDropManager<T, U, V>,\n>(): W | null {\n  return useContext(DragDropContext) as W | null;\n}\n"
  },
  {
    "path": "packages/react/src/core/hooks/useDragDropMonitor.ts",
    "content": "import {useEffect} from 'react';\nimport type {DragDropEventHandlers, Data} from '@dnd-kit/abstract';\nimport type {Draggable, Droppable, DragDropManager} from '@dnd-kit/dom';\n\nimport {useDragDropManager} from './useDragDropManager.js';\nimport {CleanupFunction} from '@dnd-kit/state';\n\ntype EventNameOverrides = {\n  beforedragstart: 'onBeforeDragStart';\n};\n\ntype EventHandlerName<T extends string> = T extends keyof EventNameOverrides\n  ? EventNameOverrides[T]\n  : T extends `drag${infer Second}${infer Rest}`\n    ? `onDrag${Uppercase<Second>}${Rest}`\n    : `on${Capitalize<T>}`;\n\n/**\n * Type for all possible event handlers\n */\ntype Events<\n  T extends Data,\n  U extends Draggable<T>,\n  V extends Droppable<T>,\n  W extends DragDropManager<T, U, V>,\n> = DragDropEventHandlers<U, V, W>;\n\nexport type EventHandlers<\n  T extends Data = Data,\n  U extends Draggable<T> = Draggable<T>,\n  V extends Droppable<T> = Droppable<T>,\n  W extends DragDropManager<T, U, V> = DragDropManager<T, U, V>,\n> = {\n  [K in keyof Events<T, U, V, W> as EventHandlerName<K>]: Events<T, U, V, W>[K];\n};\n\n/**\n * Hook to monitor drag and drop events anywhere within a DragDropProvider\n * @param handlers Object containing event handlers for drag and drop events\n */\nexport function useDragDropMonitor<\n  T extends Data = Data,\n  U extends Draggable<T> = Draggable<T>,\n  V extends Droppable<T> = Droppable<T>,\n  W extends DragDropManager<T, U, V> = DragDropManager<T, U, V>,\n>(handlers: Partial<EventHandlers<T, U, V, W>>): void {\n  const manager = useDragDropManager<T, U, V, W>();\n\n  useEffect(() => {\n    if (!manager) {\n      if (process.env.NODE_ENV !== 'production') {\n        console.warn(\n          'useDndMonitor hook was called outside of a DragDropProvider. ' +\n            'Make sure your app is wrapped in a DragDropProvider component.'\n        );\n      }\n      return;\n    }\n\n    const cleanupFns = Object.entries(handlers).reduce<CleanupFunction[]>(\n      (acc, [handlerName, handler]) => {\n        if (handler) {\n          // Convert handler name (e.g. 'onDragStart') to event name (e.g. 'dragstart')\n          const eventName = handlerName\n            .replace(/^on/, '')\n            .toLowerCase() as keyof Events<T, U, V, W>;\n\n          const unsubscribe = manager.monitor.addEventListener(\n            eventName,\n            handler as any\n          );\n\n          acc.push(unsubscribe);\n        }\n\n        return acc;\n      },\n      []\n    );\n\n    return () => cleanupFns.forEach((cleanup) => cleanup?.());\n  }, [manager, handlers]);\n}\n"
  },
  {
    "path": "packages/react/src/core/hooks/useDragOperation.ts",
    "content": "import type {Data} from '@dnd-kit/abstract';\nimport type {Draggable, Droppable, DragDropManager} from '@dnd-kit/dom';\nimport {useComputed} from '@dnd-kit/react/hooks';\n\nimport {useDragDropManager} from './useDragDropManager.ts';\n\nexport function useDragOperation<\n  T extends Data = Data,\n  U extends Draggable<T> = Draggable<T>,\n  V extends Droppable<T> = Droppable<T>,\n  W extends DragDropManager<T, U, V> = DragDropManager<T, U, V>,\n>() {\n  const manager = useDragDropManager<T, U, V, W>();\n  const source = useComputed(() => manager?.dragOperation.source, [manager]);\n  const target = useComputed(() => manager?.dragOperation.target, [manager]);\n\n  return {\n    get source() {\n      return source.value;\n    },\n    get target() {\n      return target.value;\n    },\n  };\n}\n"
  },
  {
    "path": "packages/react/src/core/hooks/useInstance.ts",
    "content": "import {useState} from 'react';\nimport type {DragDropManager} from '@dnd-kit/abstract';\nimport type {CleanupFunction} from '@dnd-kit/state';\nimport {useIsomorphicLayoutEffect} from '@dnd-kit/react/hooks';\n\nimport {useDragDropManager} from './useDragDropManager.ts';\n\nexport interface Instance<\n  T extends DragDropManager<any, any> = DragDropManager<any, any>,\n> {\n  manager: T | undefined;\n  register(): CleanupFunction | void;\n}\n\nexport function useInstance<T extends Instance>(\n  initializer: (manager: DragDropManager<any, any> | undefined) => T\n): T {\n  const manager = useDragDropManager() ?? undefined;\n  const [instance] = useState<T>(() => initializer(manager));\n\n  if (instance.manager !== manager) {\n    instance.manager = manager;\n  }\n\n  useIsomorphicLayoutEffect(instance.register, [manager, instance]);\n\n  return instance;\n}\n"
  },
  {
    "path": "packages/react/src/core/index.ts",
    "content": "'use client';\n\nexport {DragDropProvider} from './context/DragDropProvider.tsx';\n\nexport {\n  useDraggable,\n  type UseDraggableInput,\n} from './draggable/useDraggable.ts';\nexport {DragOverlay} from './draggable/DragOverlay.tsx';\n\nexport {\n  useDroppable,\n  type UseDroppableInput,\n} from './droppable/useDroppable.ts';\n\nexport {useDragDropManager} from './hooks/useDragDropManager.ts';\n\nexport {\n  useDragDropMonitor,\n  type EventHandlers as DragDropEventHandlers,\n} from './hooks/useDragDropMonitor.ts';\n\nexport {useDragOperation} from './hooks/useDragOperation.ts';\n\nexport {useInstance} from './hooks/useInstance.ts';\n\nexport {KeyboardSensor, PointerSensor} from '@dnd-kit/dom';\nexport type {\n  DragDropManager,\n  CollisionEvent,\n  BeforeDragStartEvent,\n  DragStartEvent,\n  DragMoveEvent,\n  DragOverEvent,\n  DragEndEvent,\n} from '@dnd-kit/dom';\n"
  },
  {
    "path": "packages/react/src/hooks/index.ts",
    "content": "'use client';\n\nexport {useConstant} from './useConstant.ts';\nexport {useComputed} from './useComputed.ts';\nexport {useDeepSignal} from './useDeepSignal.ts';\nexport {useImmediateEffect} from './useImmediateEffect.ts';\nexport {useIsomorphicLayoutEffect} from './useIsomorphicLayoutEffect.ts';\nexport {useLatest} from './useLatest.ts';\nexport {useOnValueChange} from './useOnValueChange.ts';\nexport {useOnElementChange} from './useOnElementChange.ts';\n"
  },
  {
    "path": "packages/react/src/hooks/useComputed.ts",
    "content": "import {useMemo, useRef} from 'react';\nimport {computed} from '@dnd-kit/state';\n\nimport {useSignal} from './useSignal.ts';\n\nexport function useComputed<T = any>(\n  compute: () => T,\n  dependencies: any[] = [],\n  sync = false\n) {\n  const $compute = useRef(compute);\n  $compute.current = compute;\n\n  return useSignal(\n    useMemo(() => computed(() => $compute.current()), dependencies),\n    sync\n  );\n}\n"
  },
  {
    "path": "packages/react/src/hooks/useConstant.ts",
    "content": "import {useRef} from 'react';\n\nexport function useConstant<T = any>(initializer: () => T) {\n  const ref = useRef<T>(null);\n\n  if (!ref.current) {\n    ref.current = initializer();\n  }\n\n  return ref.current;\n}\n"
  },
  {
    "path": "packages/react/src/hooks/useDeepSignal.ts",
    "content": "import {useMemo, useRef} from 'react';\nimport {flushSync} from 'react-dom';\nimport {effect, untracked} from '@dnd-kit/state';\n\nimport {useIsomorphicLayoutEffect} from './useIsomorphicLayoutEffect.ts';\nimport {useForceUpdate} from './useForceUpdate.ts';\n\n/** Trigger a re-render when reading signal properties of an object. */\nexport function useDeepSignal<T extends object | null | undefined>(\n  target: T,\n  synchronous?: (property: keyof T, oldValue: any, newValue: any) => boolean\n): T {\n  const tracked = useRef(new Map<string | symbol, any>());\n  const forceUpdate = useForceUpdate();\n\n  useIsomorphicLayoutEffect(() => {\n    if (!target) {\n      tracked.current.clear();\n      return;\n    }\n\n    return effect(() => {\n      let stale = false;\n      let sync = false;\n\n      for (const entry of tracked.current) {\n        const [key] = entry;\n        const value = untracked(() => entry[1]);\n        const latestValue = (target as any)[key];\n\n        if (value !== latestValue) {\n          stale = true;\n          tracked.current.set(key, latestValue);\n          sync = synchronous?.(key as keyof T, value, latestValue) ?? false;\n        }\n      }\n\n      if (stale) {\n        if (sync) {\n          // Defer flushSync to a microtask to avoid calling it from within\n          // a React lifecycle method (e.g. useEffect batch), which happens when\n          // signal updates are triggered synchronously from a React effect\n          queueMicrotask(() => flushSync(forceUpdate));\n        } else {\n          forceUpdate();\n        }\n      }\n    });\n  }, [target]);\n\n  return useMemo(\n    () =>\n      target\n        ? new Proxy(target, {\n            get(target, key) {\n              const value = (target as any)[key];\n\n              tracked.current.set(key, value);\n\n              return value;\n            },\n          })\n        : target,\n    [target]\n  );\n}\n"
  },
  {
    "path": "packages/react/src/hooks/useForceUpdate.ts",
    "content": "import {useCallback, useState} from 'react';\n\nexport function useForceUpdate() {\n  const setState = useState(0)[1];\n\n  return useCallback(() => {\n    setState((value) => value + 1);\n  }, [setState]);\n}\n"
  },
  {
    "path": "packages/react/src/hooks/useImmediateEffect.ts",
    "content": "import type {DependencyList, EffectCallback} from 'react';\n\nexport function useImmediateEffect(\n  callback: EffectCallback,\n  _?: DependencyList\n) {\n  callback();\n}\n"
  },
  {
    "path": "packages/react/src/hooks/useIsomorphicLayoutEffect.ts",
    "content": "import {useEffect, useLayoutEffect} from 'react';\n\n// https://github.com/facebook/react/blob/master/packages/shared/ExecutionEnvironment.js\nexport const canUseDOM =\n  typeof window !== 'undefined' &&\n  typeof window.document !== 'undefined' &&\n  typeof window.document.createElement !== 'undefined';\n\n/**\n * A hook that resolves to useEffect on the server and useLayoutEffect on the client\n * @param callback {function} Callback function that is invoked when the dependencies of the hook change\n */\nexport const useIsomorphicLayoutEffect = canUseDOM\n  ? useLayoutEffect\n  : useEffect;\n"
  },
  {
    "path": "packages/react/src/hooks/useLatest.ts",
    "content": "import {useRef} from 'react';\n\nimport {useIsomorphicLayoutEffect} from './useIsomorphicLayoutEffect.ts';\n\nexport function useLatest<T>(value: T) {\n  const valueRef = useRef<T | undefined>(value);\n\n  useIsomorphicLayoutEffect(() => {\n    valueRef.current = value;\n  }, [value]);\n\n  return valueRef;\n}\n"
  },
  {
    "path": "packages/react/src/hooks/useOnElementChange.ts",
    "content": "import {useRef} from 'react';\nimport {currentValue, type RefOrValue} from '@dnd-kit/react/utilities';\n\nimport {useIsomorphicLayoutEffect} from './useIsomorphicLayoutEffect.ts';\n\nexport function useOnElementChange(\n  value: RefOrValue<Element>,\n  onChange: (value: Element | undefined) => void\n) {\n  const previous = useRef(currentValue(value));\n\n  useIsomorphicLayoutEffect(() => {\n    const current = currentValue(value);\n\n    if (current !== previous.current) {\n      previous.current = current;\n      onChange(current);\n    }\n  });\n}\n"
  },
  {
    "path": "packages/react/src/hooks/useOnValueChange.ts",
    "content": "import {useRef, useEffect} from 'react';\n\nexport function useOnValueChange<T>(\n  value: T,\n  onChange: (value: T, oldValue: T) => void,\n  effect = useEffect,\n  compare = Object.is\n) {\n  const tracked = useRef<T>(value);\n\n  effect(() => {\n    const oldValue = tracked.current;\n\n    if (!compare(value, oldValue)) {\n      tracked.current = value;\n      onChange(value, oldValue);\n    }\n  }, [onChange, value]);\n}\n"
  },
  {
    "path": "packages/react/src/hooks/useSignal.ts",
    "content": "import {useRef, useState} from 'react';\nimport {flushSync} from 'react-dom';\nimport {effect, Signal} from '@dnd-kit/state';\n\nimport {useIsomorphicLayoutEffect} from './useIsomorphicLayoutEffect.ts';\nimport {useForceUpdate} from './useForceUpdate.ts';\n\n/** Trigger a re-render when reading a signal. */\nexport function useSignal<T = any>(signal: Signal<T>, sync = false) {\n  const previous = useRef(signal.peek());\n  const read = useRef(false);\n  const forceUpdate = useForceUpdate();\n\n  useIsomorphicLayoutEffect(\n    () =>\n      effect(() => {\n        const previousValue = previous.current;\n        const currentValue = signal.value;\n\n        if (previousValue !== currentValue) {\n          previous.current = currentValue;\n\n          if (!read.current) return;\n\n          if (sync) {\n            flushSync(forceUpdate);\n          } else {\n            forceUpdate();\n          }\n        }\n      }),\n    [signal, sync, forceUpdate]\n  );\n\n  return {\n    get value() {\n      read.current = true;\n\n      return signal.peek();\n    },\n  };\n}\n"
  },
  {
    "path": "packages/react/src/sortable/index.ts",
    "content": "'use client';\n\nexport {useSortable} from './useSortable.ts';\nexport type {UseSortableInput} from './useSortable.ts';\n\nexport {isSortable, isSortableOperation} from '@dnd-kit/dom/sortable';\n"
  },
  {
    "path": "packages/react/src/sortable/useSortable.ts",
    "content": "import {useCallback} from 'react';\nimport {batch, deepEqual} from '@dnd-kit/state';\nimport {type Data} from '@dnd-kit/abstract';\nimport {Sortable, defaultSortableTransition} from '@dnd-kit/dom/sortable';\nimport type {SortableInput} from '@dnd-kit/dom/sortable';\nimport {useInstance} from '@dnd-kit/react';\nimport {\n  useImmediateEffect as immediateEffect,\n  useIsomorphicLayoutEffect,\n  useOnValueChange,\n  useOnElementChange,\n  useDeepSignal,\n} from '@dnd-kit/react/hooks';\nimport {currentValue, type RefOrValue} from '@dnd-kit/react/utilities';\n\nexport interface UseSortableInput<T extends Data = Data>\n  extends Omit<SortableInput<T>, 'handle' | 'element' | 'target'> {\n  handle?: RefOrValue<Element>;\n  element?: RefOrValue<Element>;\n  target?: RefOrValue<Element>;\n}\n\nexport function useSortable<T extends Data = Data>(input: UseSortableInput<T>) {\n  const {\n    accept,\n    collisionDetector,\n    collisionPriority,\n    id,\n    data,\n    element,\n    handle,\n    index,\n    group,\n    disabled,\n    modifiers,\n    sensors,\n    target,\n    type,\n    plugins,\n  } = input;\n  const transition = {...defaultSortableTransition, ...input.transition};\n  const sortable = useInstance((manager) => {\n    return new Sortable(\n      {\n        ...input,\n        transition,\n        register: false,\n        handle: currentValue(handle),\n        element: currentValue(element),\n        target: currentValue(target),\n      },\n      manager\n    );\n  });\n\n  const trackedSortable = useDeepSignal(sortable, shouldUpdateSynchronously);\n\n  useOnValueChange(id, () => (sortable.id = id));\n\n  useIsomorphicLayoutEffect(() => {\n    batch(() => {\n      sortable.group = group;\n      sortable.index = index;\n    });\n  }, [sortable, group, index]);\n\n  useOnValueChange(type, () => (sortable.type = type));\n  useOnValueChange(\n    accept,\n    () => (sortable.accept = accept),\n    undefined,\n    deepEqual\n  );\n  useOnValueChange(data, () => data && (sortable.data = data));\n  useOnValueChange(\n    index,\n    () => {\n      if (sortable.manager?.dragOperation.status.idle && transition?.idle) {\n        sortable.refreshShape();\n      }\n    },\n    immediateEffect\n  );\n  useOnElementChange(handle, (handle) => (sortable.handle = handle));\n  useOnElementChange(element, (element) => (sortable.element = element));\n  useOnElementChange(target, (target) => (sortable.target = target));\n  useOnValueChange(disabled, () => (sortable.disabled = disabled === true));\n  useOnValueChange(sensors, () => (sortable.sensors = sensors));\n  useOnValueChange(\n    collisionDetector,\n    () => (sortable.collisionDetector = collisionDetector)\n  );\n  useOnValueChange(\n    collisionPriority,\n    () => (sortable.collisionPriority = collisionPriority)\n  );\n  useOnValueChange(plugins, () => (sortable.plugins = plugins), undefined, deepEqual);\n  useOnValueChange(\n    transition,\n    () => (sortable.transition = transition),\n    undefined,\n    deepEqual\n  );\n  useOnValueChange(\n    modifiers,\n    () => (sortable.modifiers = modifiers),\n    undefined,\n    deepEqual\n  );\n  useOnValueChange(\n    input.alignment,\n    () => (sortable.alignment = input.alignment)\n  );\n\n  return {\n    sortable: trackedSortable,\n    get isDragging() {\n      return trackedSortable.isDragging;\n    },\n    get isDropping() {\n      return trackedSortable.isDropping;\n    },\n    get isDragSource() {\n      return trackedSortable.isDragSource;\n    },\n    get isDropTarget() {\n      return trackedSortable.isDropTarget;\n    },\n    handleRef: useCallback(\n      (element: Element | null) => {\n        sortable.handle = element ?? undefined;\n      },\n      [sortable]\n    ),\n    ref: useCallback(\n      (element: Element | null) => {\n        if (\n          !element &&\n          sortable.element?.isConnected &&\n          !sortable.manager?.dragOperation.status.idle\n        ) {\n          return;\n        }\n\n        sortable.element = element ?? undefined;\n      },\n      [sortable]\n    ),\n    sourceRef: useCallback(\n      (element: Element | null) => {\n        if (\n          !element &&\n          sortable.source?.isConnected &&\n          !sortable.manager?.dragOperation.status.idle\n        ) {\n          return;\n        }\n\n        sortable.source = element ?? undefined;\n      },\n      [sortable]\n    ),\n    targetRef: useCallback(\n      (element: Element | null) => {\n        if (\n          !element &&\n          sortable.target?.isConnected &&\n          !sortable.manager?.dragOperation.status.idle\n        ) {\n          return;\n        }\n\n        sortable.target = element ?? undefined;\n      },\n      [sortable]\n    ),\n  };\n}\n\nfunction shouldUpdateSynchronously(key: string, oldValue: any, newValue: any) {\n  // Update synchronously after drop animation\n  if (key === 'isDragSource' && !newValue && oldValue) return true;\n\n  return false;\n}\n"
  },
  {
    "path": "packages/react/src/utilities/currentValue.ts",
    "content": "import type {RefObject, MutableRefObject} from 'react';\n\nexport type Ref<T> = RefObject<T | null | undefined> | MutableRefObject<T>;\n\nexport type RefOrValue<T> = T | Ref<T> | null | undefined;\n\nfunction isRef<T>(value: RefOrValue<T>): value is Ref<T> {\n  return value != null && typeof value === 'object' && 'current' in value;\n}\n\nexport function currentValue<T>(\n  value: RefOrValue<T>\n): NonNullable<T> | undefined {\n  if (value == null) {\n    return undefined;\n  }\n\n  if (isRef(value)) {\n    return value.current ?? undefined;\n  }\n\n  return value;\n}\n"
  },
  {
    "path": "packages/react/src/utilities/index.ts",
    "content": "export {currentValue, type RefOrValue} from './currentValue.ts';\n"
  },
  {
    "path": "packages/react/tsconfig.json",
    "content": "{\n  \"extends\": \"../../config/typescript/react.json\",\n  \"include\": [\"src/**/*\"],\n  \"exclude\": [\"dist\", \"build\", \"node_modules\"]\n}\n"
  },
  {
    "path": "packages/react/tsup.config.ts",
    "content": "import {defineConfig} from 'tsup';\n\nexport default defineConfig((options) => ({\n  dts: true,\n  outDir: './',\n  external: [\n    '@dnd-kit/abstract',\n    '@dnd-kit/react',\n    '@dnd-kit/dom',\n    '@dnd-kit/state',\n  ],\n  format: ['esm', 'cjs'],\n  sourcemap: true,\n  treeshake: !options.watch,\n}));\n"
  },
  {
    "path": "packages/solid/CHANGELOG.md",
    "content": "# @dnd-kit/solid\n\n## 0.3.2\n\n### Patch Changes\n\n- Updated dependencies [[`7260746`](https://github.com/clauderic/dnd-kit/commit/7260746b0930d51afb3098ef120bffd7d3aaea03)]:\n  - @dnd-kit/dom@0.3.2\n  - @dnd-kit/abstract@0.3.2\n  - @dnd-kit/state@0.3.2\n\n## 0.3.1\n\n### Patch Changes\n\n- Updated dependencies [[`4341114`](https://github.com/clauderic/dnd-kit/commit/43411143063349caeded4f778923473624ce25cf)]:\n  - @dnd-kit/abstract@0.3.1\n  - @dnd-kit/dom@0.3.1\n  - @dnd-kit/state@0.3.1\n\n## 0.3.0\n\n### Minor Changes\n\n- [`6a59647`](https://github.com/clauderic/dnd-kit/commit/6a59647ebba2114b2e423f282ab25bf2ea40318d) Thanks [@clauderic](https://github.com/clauderic)! - Allow `plugins`, `sensors`, and `modifiers` to accept a function that receives the defaults, making it easy to extend or configure them without replacing the entire array.\n\n  ```ts\n  // Add a plugin alongside the defaults\n  const manager = new DragDropManager({\n    plugins: (defaults) => [...defaults, MyPlugin],\n  });\n  ```\n\n  ```tsx\n  // Configure a default plugin in React\n  <DragDropProvider\n    plugins={(defaults) => [\n      ...defaults,\n      Feedback.configure({dropAnimation: null}),\n    ]}\n  />\n  ```\n\n  Previously, passing `plugins`, `sensors`, or `modifiers` would replace the defaults entirely, requiring consumers to import and spread `defaultPreset`. The function form receives the default values as an argument, so consumers can add, remove, or configure individual entries without needing to know or maintain the full default list.\n\n- [#1881](https://github.com/clauderic/dnd-kit/pull/1881) [`69f2772`](https://github.com/clauderic/dnd-kit/commit/69f27726efd3e2487eedc99606fc6f060ee0b92c) Thanks [@clauderic](https://github.com/clauderic)! - Add @dnd-kit/solid adapter package for SolidJS\n\n- [`68e44de`](https://github.com/clauderic/dnd-kit/commit/68e44deb6f824b38a58d9b4b1bd81e2efa9193f9) Thanks [@clauderic](https://github.com/clauderic)! - Add `isSortableOperation` type guard and export `SortableDraggable`/`SortableDroppable` types.\n\n  `isSortableOperation(operation)` narrows a `DragOperationSnapshot` so that `source` is typed as `SortableDraggable` and `target` as `SortableDroppable`, providing typed access to sortable-specific properties like `index`, `initialIndex`, `group`, and `initialGroup`.\n\n  Re-exported from all framework packages (`@dnd-kit/react/sortable`, `@dnd-kit/vue/sortable`, `@dnd-kit/svelte/sortable`, `@dnd-kit/solid/sortable`).\n\n### Patch Changes\n\n- [`5d64078`](https://github.com/clauderic/dnd-kit/commit/5d640782702b74da8be38cbd1e29271d04781854) Thanks [@clauderic](https://github.com/clauderic)! - Add `dropAnimation` prop to the `DragOverlay` component to allow consumers to disable or customize the drop animation that plays when a drag operation ends. Set to `null` to disable, pass `{duration, easing}` to customize timing, or provide a custom animation function for full control.\n\n- Updated dependencies [[`6a59647`](https://github.com/clauderic/dnd-kit/commit/6a59647ebba2114b2e423f282ab25bf2ea40318d), [`5d64078`](https://github.com/clauderic/dnd-kit/commit/5d640782702b74da8be38cbd1e29271d04781854), [`863ce2b`](https://github.com/clauderic/dnd-kit/commit/863ce2b74ec0f4d630f4b7036c363bc2e3d04f24), [`863ce2b`](https://github.com/clauderic/dnd-kit/commit/863ce2b74ec0f4d630f4b7036c363bc2e3d04f24), [`e8ae539`](https://github.com/clauderic/dnd-kit/commit/e8ae539abe05a1df41d45078b108167022ac9ef7), [`41d7e27`](https://github.com/clauderic/dnd-kit/commit/41d7e27edb30cea9940cd5c46c6fcc81f7b401a6), [`68e44de`](https://github.com/clauderic/dnd-kit/commit/68e44deb6f824b38a58d9b4b1bd81e2efa9193f9)]:\n  - @dnd-kit/abstract@0.3.0\n  - @dnd-kit/dom@0.3.0\n  - @dnd-kit/state@0.3.0\n"
  },
  {
    "path": "packages/solid/README.md",
    "content": "# @dnd-kit/solid\n\n[![Stable release](https://img.shields.io/npm/v/@dnd-kit/solid.svg)](https://npm.im/@dnd-kit/solid)\n\nThe SolidJS adapter for **@dnd-kit** — a lightweight, performant, and extensible drag and drop toolkit. Built on top of `@dnd-kit/dom`.\n\n## Installation\n\n```bash\nnpm install @dnd-kit/solid\n```\n\n## Quick start\n\n```tsx\nimport {createSignal} from 'solid-js';\nimport {DragDropProvider, useDraggable, useDroppable} from '@dnd-kit/solid';\n\nfunction Draggable() {\n  const {ref} = useDraggable({id: 'draggable'});\n  return <button ref={ref}>Drag me</button>;\n}\n\nfunction Droppable(props) {\n  const {ref} = useDroppable({id: 'droppable'});\n  return <div ref={ref}>{props.children}</div>;\n}\n\nfunction App() {\n  const [parent, setParent] = createSignal(null);\n\n  return (\n    <DragDropProvider\n      onDragEnd={(event) => {\n        if (event.canceled) return;\n        setParent(event.operation.target?.id ?? null);\n      }}\n    >\n      {parent() == null ? <Draggable /> : null}\n      <Droppable>{parent() ? <Draggable /> : 'Drop here'}</Droppable>\n    </DragDropProvider>\n  );\n}\n```\n\n## Hooks\n\n| Hook           | Import                    | Description                        |\n| -------------- | ------------------------- | ---------------------------------- |\n| `useDraggable` | `@dnd-kit/solid`          | Make an element draggable          |\n| `useDroppable` | `@dnd-kit/solid`          | Create a drop target               |\n| `useSortable`  | `@dnd-kit/solid/sortable` | Combine drag and drop with sorting |\n\n## Components\n\n- **`<DragDropProvider>`** — Wraps your drag and drop interface, manages sensors, plugins, and events.\n- **`<DragOverlay>`** — Renders a custom overlay element during drag operations.\n\n## Documentation\n\nVisit [dndkit.com](https://dndkit.com/solid) for full documentation, guides, and interactive examples.\n"
  },
  {
    "path": "packages/solid/package.json",
    "content": "{\n  \"name\": \"@dnd-kit/solid\",\n  \"version\": \"0.3.2\",\n  \"main\": \"./index.cjs\",\n  \"module\": \"./index.js\",\n  \"type\": \"module\",\n  \"types\": \"./index.d.ts\",\n  \"sideEffects\": false,\n  \"license\": \"MIT\",\n  \"files\": [\n    \"LICENSE\",\n    \"README.md\",\n    \"index.js\",\n    \"index.d.ts\",\n    \"index.cjs\",\n    \"hooks.js\",\n    \"hooks.d.ts\",\n    \"hooks.cjs\",\n    \"sortable.js\",\n    \"sortable.d.ts\",\n    \"sortable.cjs\",\n    \"utilities.js\",\n    \"utilities.d.ts\",\n    \"utilities.cjs\"\n  ],\n  \"exports\": {\n    \".\": {\n      \"types\": \"./index.d.ts\",\n      \"import\": \"./index.js\",\n      \"require\": \"./index.cjs\"\n    },\n    \"./hooks\": {\n      \"types\": \"./hooks.d.ts\",\n      \"import\": \"./hooks.js\",\n      \"require\": \"./hooks.cjs\"\n    },\n    \"./sortable\": {\n      \"types\": \"./sortable.d.ts\",\n      \"import\": \"./sortable.js\",\n      \"require\": \"./sortable.cjs\"\n    },\n    \"./utilities\": {\n      \"types\": \"./utilities.d.ts\",\n      \"import\": \"./utilities.js\",\n      \"require\": \"./utilities.cjs\"\n    }\n  },\n  \"scripts\": {\n    \"build\": \"bun build:utilities && bun build:hooks && bun build:core && bun build:sortable\",\n    \"build:core\": \"tsup src/core/index.ts\",\n    \"build:hooks\": \"tsup --entry.hooks src/hooks/index.ts\",\n    \"build:sortable\": \"tsup --entry.sortable src/sortable/index.ts\",\n    \"build:utilities\": \"tsup --entry.utilities src/utilities/index.ts\",\n    \"dev\": \"bun build:utilities --watch & bun build:hooks --watch & bun build:core --watch & bun build:sortable --watch\",\n    \"clean\": \"rm -rf .turbo && rm -rf node_modules && rm -rf dist\"\n  },\n  \"dependencies\": {\n    \"@dnd-kit/abstract\": \"^0.3.2\",\n    \"@dnd-kit/dom\": \"^0.3.2\",\n    \"@dnd-kit/state\": \"^0.3.2\",\n    \"tslib\": \"^2.6.2\"\n  },\n  \"peerDependencies\": {\n    \"solid-js\": \"^1.8.0\"\n  },\n  \"devDependencies\": {\n    \"esbuild-plugin-solid\": \"^0.6.0\",\n    \"tsup\": \"8.3.0\",\n    \"typescript\": \"^5.5.2\",\n    \"solid-js\": \"^1.9.0\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/clauderic/dnd-kit\"\n  }\n}\n"
  },
  {
    "path": "packages/solid/src/core/context/DragDropProvider.tsx",
    "content": "import {createEffect, createMemo, onCleanup} from 'solid-js';\nimport {DragDropManager, defaultPreset, resolveCustomizable} from '@dnd-kit/dom';\nimport {isSortable} from '@dnd-kit/dom/sortable';\n\nimport {DragDropContext} from './context.ts';\nimport {useRenderer} from './renderer.ts';\nimport {createSaveElementPosition} from '../../utilities/saveElementPosition.ts';\n\nimport type {DragDropEventHandlers} from '@dnd-kit/abstract';\nimport type {DragDropManagerInput, Draggable, Droppable} from '@dnd-kit/dom';\nimport type {ParentProps} from 'solid-js';\n\nexport type Events = DragDropEventHandlers<Draggable, Droppable, DragDropManager>;\n\nexport interface DragDropProviderProps\n  extends DragDropManagerInput,\n    ParentProps {\n  manager?: DragDropManager;\n  onBeforeDragStart?: Events['beforedragstart'];\n  onCollision?: Events['collision'];\n  onDragStart?: Events['dragstart'];\n  onDragMove?: Events['dragmove'];\n  onDragOver?: Events['dragover'];\n  onDragEnd?: Events['dragend'];\n}\n\nexport function DragDropProvider(props: DragDropProviderProps) {\n  const {savePosition, restorePosition, clearPosition} = createSaveElementPosition();\n  const {renderer, trackRendering} = useRenderer();\n  const manager = createMemo(\n    () => props.manager ?? new DragDropManager(props)\n  );\n\n  onCleanup(() => {\n    if (!props.manager) {\n      manager().destroy();\n    }\n  });\n\n  createEffect(() => {\n    const _manager = manager();\n\n    _manager.renderer = renderer;\n    _manager.plugins = resolveCustomizable(props.plugins, defaultPreset.plugins);\n    _manager.sensors = resolveCustomizable(props.sensors, defaultPreset.sensors);\n    _manager.modifiers = resolveCustomizable(props.modifiers, defaultPreset.modifiers);\n  });\n\n  createEffect(() => {\n    const disposers: (() => void)[] = [];\n    const monitor = manager().monitor;\n\n    disposers.push(\n      monitor.addEventListener('beforedragstart', (event, manager) => {\n        if (isSortable(event.operation.source)) {\n          savePosition(event.operation.source);\n        }\n\n        const callback = props.onBeforeDragStart;\n        if (callback) {\n          trackRendering(() => callback(event, manager));\n        }\n      }),\n      monitor.addEventListener('dragstart', (event, manager) => {\n        props.onDragStart?.(event, manager);\n      }),\n      monitor.addEventListener('dragover', (event, manager) => {\n        const callback = props.onDragOver;\n        if (callback) {\n          trackRendering(() => callback(event, manager));\n\n\n          // Update saved position to match what Solid just rendered.\n          if (isSortable(event.operation.source)) {\n            const source = event.operation.source;\n\n            queueMicrotask(() => savePosition(source));\n          }\n        }\n      }),\n      monitor.addEventListener('dragmove', (event, manager) => {\n        const callback = props.onDragMove;\n        if (callback) {\n          trackRendering(() => callback(event, manager));\n        }\n      }),\n      monitor.addEventListener('dragend', (event, manager) => {\n        if (isSortable(event.operation.source)) {\n          restorePosition(event.operation.source!.element!);\n        }\n\n        const callback = props.onDragEnd;\n        if (callback) {\n          trackRendering(() => callback(event, manager));\n        }\n\n        clearPosition();\n      }),\n      monitor.addEventListener('collision', (event, manager) => {\n        props.onCollision?.(event, manager);\n      })\n    );\n\n    onCleanup(() => {\n      disposers.forEach((cleanup) => cleanup());\n    });\n  });\n\n  return (\n    <DragDropContext.Provider value={manager()}>\n      {props.children}\n    </DragDropContext.Provider>\n  );\n}\n"
  },
  {
    "path": "packages/solid/src/core/context/context.ts",
    "content": "import {DragDropManager} from '@dnd-kit/dom';\nimport {createContext} from 'solid-js';\n\nexport const DragDropContext = createContext<DragDropManager | null>(null);\n"
  },
  {
    "path": "packages/solid/src/core/context/renderer.ts",
    "content": "import {batch, createEffect, createSignal, on} from 'solid-js';\n\nimport type {DragDropManager} from '@dnd-kit/dom';\n\ntype Renderer = DragDropManager['renderer'];\n\nexport function useRenderer(): {\n  renderer: Renderer;\n  trackRendering: (callback: () => void) => void;\n} {\n  const [transitionCount, setTransitionCount] = createSignal(0);\n  let rendering: Promise<void> | null = null;\n  let resolver: (() => void) | null = null;\n\n  createEffect(\n    on(transitionCount, () => {\n      resolver?.();\n      rendering = null;\n    })\n  );\n\n  return {\n    renderer: {\n      get rendering() {\n        return rendering ?? Promise.resolve();\n      },\n    },\n    trackRendering(callback: () => void) {\n      if (!rendering) {\n        rendering = new Promise<void>((resolve) => {\n          resolver = resolve;\n        });\n      }\n\n      batch(() => {\n        callback();\n        setTransitionCount((c) => c + 1);\n      });\n    },\n  };\n}\n"
  },
  {
    "path": "packages/solid/src/core/draggable/DragOverlay.tsx",
    "content": "import {Feedback} from '@dnd-kit/dom';\nimport {Show, createEffect, createMemo, createSignal, onCleanup} from 'solid-js';\nimport {Dynamic} from 'solid-js/web';\n\nimport {DragDropContext} from '../context/context.ts';\nimport {useDragDropManager} from '../hooks/useDragDropManager.ts';\nimport {useDragOperation} from '../hooks/useDragOperation.ts';\n\nimport type {DragDropManager, Draggable, Droppable, DropAnimation} from '@dnd-kit/dom';\nimport type {JSX, ValidComponent} from 'solid-js';\nimport type {Data} from '@dnd-kit/abstract';\n\nexport interface DragOverlayProps<\n  T extends Data,\n  U extends Draggable<T>,\n> {\n  class?: string;\n  children: JSX.Element | ((source: U) => JSX.Element);\n  /**\n   * Customize or disable the drop animation that plays when a drag operation ends.\n   *\n   * - `undefined` – use the default animation (250ms ease)\n   * - `null` – disable the drop animation entirely\n   * - `{duration, easing}` – customize the animation timing\n   * - `(context) => Promise<void> | void` – provide a fully custom animation function\n   */\n  dropAnimation?: DropAnimation | null;\n  style?: JSX.CSSProperties;\n  tag?: ValidComponent;\n  disabled?: boolean | ((source: U | null) => boolean);\n}\n\nexport function DragOverlay<T extends Data, U extends Draggable<T>>(\n  props: DragOverlayProps<T, U>\n) {\n  const [element, setElement] = createSignal<HTMLElement>();\n  const manager = useDragDropManager();\n  const patchedManager = createPatchedManager(() => manager);\n  const dragOperation = useDragOperation();\n\n  const source = () => dragOperation.source() as U | null;\n\n  const isDisabled = () => {\n    if (typeof props.disabled === 'function') {\n      return props.disabled(source());\n    }\n    return props.disabled ?? false;\n  };\n\n  createEffect(() => {\n    if (!source()) {\n      setElement(undefined);\n    }\n  });\n\n  createEffect(() => {\n    const _manager = manager;\n\n    if (!_manager || isDisabled()) return;\n\n    const feedback = _manager.plugins.find(\n      (plugin): plugin is Feedback => plugin instanceof Feedback\n    );\n\n    if (!feedback) return;\n\n    feedback.overlay = element();\n    feedback.dropAnimation = props.dropAnimation;\n\n    onCleanup(() => {\n      feedback.overlay = undefined;\n      feedback.dropAnimation = undefined;\n    });\n  });\n\n  return (\n    <DragDropContext.Provider value={patchedManager()}>\n      <Show when={!isDisabled() ? source() : undefined}>\n        {(src) => (\n          <Dynamic\n            component={props.tag || 'div'}\n            class={props.class}\n            style={props.style}\n            data-dnd-overlay\n            ref={setElement}\n          >\n            {typeof props.children === 'function'\n              ? props.children(src() as unknown as U)\n              : props.children}\n          </Dynamic>\n        )}\n      </Show>\n    </DragDropContext.Provider>\n  );\n}\n\nfunction createPatchedManager<\n  T extends Data,\n  U extends Draggable<T>,\n  V extends Droppable<T>,\n  W extends DragDropManager<T, U, V>,\n>(manager: () => W | null) {\n  return createMemo(() => {\n    const _manager = manager();\n\n    if (!_manager) return null;\n\n    const patchedRegistry = new Proxy(_manager.registry, {\n      get(target, property) {\n        if (property === 'register' || property === 'unregister') {\n          return noop;\n        }\n        return target[property as keyof typeof target];\n      },\n    });\n\n    return new Proxy(_manager, {\n      get(target, property) {\n        if (property === 'registry') {\n          return patchedRegistry;\n        }\n        return target[property as keyof typeof target];\n      },\n    });\n  });\n}\n\nfunction noop() {\n  return () => {};\n}\n"
  },
  {
    "path": "packages/solid/src/core/draggable/useDraggable.ts",
    "content": "import type {Data} from '@dnd-kit/abstract';\nimport type {DraggableInput} from '@dnd-kit/dom';\nimport {Draggable} from '@dnd-kit/dom';\nimport {createEffect, createSignal} from 'solid-js';\n\nimport {useDeepSignal} from '../../hooks/useDeepSignal.ts';\nimport {useInstance} from '../hooks/useInstance.ts';\n\nexport interface UseDraggableInput<T extends Data = Data>\n  extends Omit<DraggableInput<T>, 'handle' | 'element'> {\n  handle?: Element;\n  element?: Element;\n}\n\nexport function useDraggable<T extends Data = Data>(\n  input: UseDraggableInput<T>\n) {\n  const draggable = useInstance(\n    (manager) =>\n      new Draggable(\n        {\n          ...input,\n          register: false,\n          element: input.element,\n          handle: input.handle,\n        },\n        manager\n      )\n  );\n  const trackedDraggable = useDeepSignal(() => draggable);\n\n  const [element, setElement] = createSignal<Element | undefined>(\n    input.element\n  );\n  const [handle, setHandle] = createSignal<Element | undefined>(input.handle);\n\n  createEffect(() => {\n    const el = element();\n    if (el) draggable.element = el;\n\n    const h = handle();\n    if (h) draggable.handle = h;\n\n    draggable.id = input.id;\n    draggable.disabled = input.disabled ?? false;\n    draggable.alignment = input.alignment;\n    draggable.plugins = input.plugins;\n    draggable.modifiers = input.modifiers;\n    draggable.sensors = input.sensors;\n\n    if (input.data) {\n      draggable.data = input.data;\n    }\n  });\n\n  return {\n    get draggable() {\n      return draggable;\n    },\n    isDragging: () => trackedDraggable().isDragging,\n    isDropping: () => trackedDraggable().isDropping,\n    isDragSource: () => trackedDraggable().isDragSource,\n    ref: setElement,\n    handleRef: setHandle,\n  };\n}\n"
  },
  {
    "path": "packages/solid/src/core/droppable/useDroppable.ts",
    "content": "import type {Data} from '@dnd-kit/abstract';\nimport type {DroppableInput} from '@dnd-kit/dom';\nimport {Droppable} from '@dnd-kit/dom';\nimport {createEffect, createSignal} from 'solid-js';\n\nimport {useDeepSignal} from '../../hooks/useDeepSignal.ts';\nimport {useInstance} from '../hooks/useInstance.ts';\n\nexport interface UseDroppableInput<T extends Data = Data>\n  extends Omit<DroppableInput<T>, 'element'> {\n  element?: Element;\n}\n\nexport function useDroppable<T extends Data = Data>(\n  input: UseDroppableInput<T>\n) {\n  const droppable = useInstance(\n    (manager) =>\n      new Droppable(\n        {\n          ...input,\n          register: false,\n          element: input.element,\n        },\n        manager\n      )\n  );\n  const trackedDroppable = useDeepSignal(() => droppable);\n\n  const [element, setElement] = createSignal<Element | undefined>(\n    input.element\n  );\n\n  createEffect(() => {\n    const el = element();\n    if (el) droppable.element = el;\n\n    droppable.id = input.id;\n    droppable.accept = input.accept;\n    droppable.type = input.type;\n    droppable.disabled = input.disabled ?? false;\n\n    if (input.collisionDetector) {\n      droppable.collisionDetector = input.collisionDetector;\n    }\n\n    if (input.data) {\n      droppable.data = input.data;\n    }\n  });\n\n  return {\n    get droppable() {\n      return droppable;\n    },\n    isDropTarget: () => trackedDroppable().isDropTarget,\n    ref: setElement,\n  };\n}\n"
  },
  {
    "path": "packages/solid/src/core/hooks/useDragDropManager.ts",
    "content": "import {useContext} from 'solid-js';\n\nimport {DragDropContext} from '../context/context.ts';\n\nexport function useDragDropManager() {\n  return useContext(DragDropContext);\n}\n"
  },
  {
    "path": "packages/solid/src/core/hooks/useDragDropMonitor.ts",
    "content": "import type {DragDropEventHandlers, Data} from '@dnd-kit/abstract';\nimport type {Draggable, Droppable, DragDropManager} from '@dnd-kit/dom';\nimport {createEffect, onCleanup} from 'solid-js';\nimport type {CleanupFunction} from '@dnd-kit/state';\n\nimport {useDragDropManager} from './useDragDropManager.ts';\n\ntype EventNameOverrides = {\n  beforedragstart: 'onBeforeDragStart';\n};\n\ntype EventHandlerName<T extends string> = T extends keyof EventNameOverrides\n  ? EventNameOverrides[T]\n  : T extends `drag${infer Second}${infer Rest}`\n    ? `onDrag${Uppercase<Second>}${Rest}`\n    : `on${Capitalize<T>}`;\n\ntype Events<\n  T extends Data,\n  U extends Draggable<T>,\n  V extends Droppable<T>,\n  W extends DragDropManager<T, U, V>,\n> = DragDropEventHandlers<U, V, W>;\n\nexport type EventHandlers<\n  T extends Data = Data,\n  U extends Draggable<T> = Draggable<T>,\n  V extends Droppable<T> = Droppable<T>,\n  W extends DragDropManager<T, U, V> = DragDropManager<T, U, V>,\n> = {\n  [K in keyof Events<T, U, V, W> as EventHandlerName<K>]?: Events<\n    T,\n    U,\n    V,\n    W\n  >[K];\n};\n\nexport function useDragDropMonitor<\n  T extends Data = Data,\n  U extends Draggable<T> = Draggable<T>,\n  V extends Droppable<T> = Droppable<T>,\n  W extends DragDropManager<T, U, V> = DragDropManager<T, U, V>,\n>(handlers: EventHandlers<T, U, V, W>): void {\n  const manager = useDragDropManager();\n\n  createEffect(() => {\n    if (!manager) {\n      if (process.env.NODE_ENV !== 'production') {\n        console.warn(\n          'useDragDropMonitor hook was called outside of a DragDropProvider. ' +\n            'Make sure your app is wrapped in a DragDropProvider component.'\n        );\n      }\n      return;\n    }\n\n    const cleanupFns = Object.entries(handlers).reduce<CleanupFunction[]>(\n      (acc, [handlerName, handler]) => {\n        if (handler) {\n          const eventName = handlerName\n            .replace(/^on/, '')\n            .toLowerCase() as keyof Events<T, U, V, W>;\n\n          const unsubscribe = manager.monitor.addEventListener(\n            eventName,\n            handler as any\n          );\n\n          acc.push(unsubscribe);\n        }\n\n        return acc;\n      },\n      []\n    );\n\n    onCleanup(() => cleanupFns.forEach((cleanup) => cleanup()));\n  });\n}\n"
  },
  {
    "path": "packages/solid/src/core/hooks/useDragOperation.ts",
    "content": "import {useDeepSignal} from '../../hooks/useDeepSignal.ts';\nimport {useDragDropManager} from './useDragDropManager.ts';\n\nexport function useDragOperation() {\n  const manager = useDragDropManager();\n  const trackedDragOperation = useDeepSignal(\n    () => manager?.dragOperation\n  );\n\n  return {\n    source: () => trackedDragOperation()?.source,\n    target: () => trackedDragOperation()?.target,\n    status: () => trackedDragOperation()?.status,\n  };\n}\n"
  },
  {
    "path": "packages/solid/src/core/hooks/useInstance.ts",
    "content": "import type {DragDropManager} from '@dnd-kit/dom';\nimport type {CleanupFunction} from '@dnd-kit/state';\nimport {createEffect, onCleanup} from 'solid-js';\n\nimport {useDragDropManager} from './useDragDropManager.ts';\n\nexport interface Instance<T extends DragDropManager = DragDropManager> {\n  manager: T | undefined;\n  register(): CleanupFunction | void;\n}\n\nexport function useInstance<T extends Instance>(\n  initializer: (manager: DragDropManager | undefined) => T\n): T {\n  const manager = useDragDropManager() ?? undefined;\n  const instance = initializer(manager);\n\n  createEffect(() => {\n    instance.manager = manager;\n    const cleanup = instance.register();\n\n    onCleanup(() => cleanup?.());\n  });\n\n  return instance;\n}\n"
  },
  {
    "path": "packages/solid/src/core/index.ts",
    "content": "export {DragDropProvider} from './context/DragDropProvider.tsx';\nexport type {DragDropProviderProps} from './context/DragDropProvider.tsx';\n\nexport {\n  useDraggable,\n  type UseDraggableInput,\n} from './draggable/useDraggable.ts';\n\nexport {DragOverlay} from './draggable/DragOverlay.tsx';\n\nexport {\n  useDroppable,\n  type UseDroppableInput,\n} from './droppable/useDroppable.ts';\n\nexport {useDragDropManager} from './hooks/useDragDropManager.ts';\n\nexport {\n  useDragDropMonitor,\n  type EventHandlers as DragDropEventHandlers,\n} from './hooks/useDragDropMonitor.ts';\n\nexport {useDragOperation} from './hooks/useDragOperation.ts';\n\nexport {useInstance} from './hooks/useInstance.ts';\n\nexport {KeyboardSensor, PointerSensor} from '@dnd-kit/dom';\nexport type {DragDropManager} from '@dnd-kit/dom';\n"
  },
  {
    "path": "packages/solid/src/hooks/index.ts",
    "content": "export {useDeepSignal} from './useDeepSignal.ts';\n"
  },
  {
    "path": "packages/solid/src/hooks/useDeepSignal.ts",
    "content": "import {effect, untracked} from '@dnd-kit/state';\nimport {createEffect, createSignal, onCleanup, type Accessor} from 'solid-js';\n\n/** Trigger a re-render when reading signal properties of an object. */\nexport function useDeepSignal<T extends object | null | undefined>(\n  target: Accessor<T>\n): Accessor<T> {\n  const tracked = new Map<string | symbol, any>();\n  const [dirty, setDirty] = createSignal(0);\n\n  // Create the preact effect AFTER the first render,\n  // when tracked has been populated by Proxy getters.\n  createEffect(() => {\n    const _target = target();\n    if (!_target) {\n      tracked.clear();\n      return;\n    }\n\n    const dispose = effect(() => {\n      let stale = false;\n\n      for (const entry of tracked) {\n        const [key] = entry;\n        const value = untracked(() => entry[1]);\n        const latestValue = (_target as any)[key];\n\n        if (value !== latestValue) {\n          stale = true;\n          tracked.set(key, latestValue);\n        }\n      }\n\n      if (stale) {\n        setDirty((v) => v + 1);\n      }\n    });\n\n    onCleanup(dispose);\n  });\n\n  return () => {\n    const _target = target();\n\n    void dirty();\n\n    return _target\n      ? new Proxy(_target, {\n          get(target, key) {\n            const value = (target as any)[key];\n            tracked.set(key, value);\n            return value;\n          },\n        })\n      : _target;\n  };\n}\n"
  },
  {
    "path": "packages/solid/src/sortable/index.ts",
    "content": "export {useSortable} from './useSortable.ts';\nexport type {UseSortableInput} from './useSortable.ts';\n\nexport {isSortable, isSortableOperation} from '@dnd-kit/dom/sortable';\n"
  },
  {
    "path": "packages/solid/src/sortable/useSortable.ts",
    "content": "import {type Data} from '@dnd-kit/abstract';\nimport type {SortableInput} from '@dnd-kit/dom/sortable';\nimport {defaultSortableTransition, Sortable} from '@dnd-kit/dom/sortable';\nimport {batch} from '@dnd-kit/state';\nimport {createEffect, createSignal, on} from 'solid-js';\n\nimport {useDeepSignal} from '@dnd-kit/solid/hooks';\nimport {useInstance} from '@dnd-kit/solid';\n\nexport interface UseSortableInput<T extends Data = Data>\n  extends Omit<SortableInput<T>, 'handle' | 'element' | 'source' | 'target'> {\n  handle?: Element;\n  element?: Element;\n  source?: Element;\n  target?: Element;\n}\n\nexport function useSortable<T extends Data = Data>(\n  input: UseSortableInput<T>\n) {\n  const transition = {\n    ...defaultSortableTransition,\n    ...input.transition,\n  };\n\n  const sortable = useInstance((manager) => {\n    return new Sortable(\n      {\n        ...input,\n        register: false,\n        transition,\n        element: input.element,\n        handle: input.handle,\n        target: input.target,\n      },\n      manager\n    );\n  });\n  const trackedSortable = useDeepSignal(() => sortable);\n\n  const [element, setElement] = createSignal<Element | undefined>(\n    input.element\n  );\n  const [handle, setHandle] = createSignal<Element | undefined>(input.handle);\n  const [source, setSource] = createSignal<Element | undefined>(input.source);\n  const [target, setTarget] = createSignal<Element | undefined>(input.target);\n\n  createEffect(() => {\n    const el = element();\n    if (el) sortable.element = el;\n\n    const h = handle();\n    if (h) sortable.handle = h;\n\n    const s = source();\n    if (s) sortable.source = s;\n\n    const t = target();\n    if (t) sortable.target = t;\n\n    sortable.id = input.id;\n    sortable.disabled = input.disabled ?? false;\n    sortable.alignment = input.alignment;\n    sortable.plugins = input.plugins;\n    sortable.modifiers = input.modifiers;\n    sortable.sensors = input.sensors;\n    sortable.accept = input.accept;\n    sortable.type = input.type;\n    sortable.collisionPriority = input.collisionPriority;\n    sortable.transition = input.transition\n      ? {...defaultSortableTransition, ...input.transition}\n      : defaultSortableTransition;\n\n    if (input.collisionDetector) {\n      sortable.collisionDetector = input.collisionDetector;\n    }\n\n    if (input.data) {\n      sortable.data = input.data;\n    }\n  });\n\n  // Batch group + index updates\n  createEffect(\n    on(\n      () => [input.group, input.index],\n      () => {\n        batch(() => {\n          sortable.group = input.group;\n          sortable.index = input.index;\n        });\n      }\n    )\n  );\n\n  // Refresh shape when index changes while idle\n  createEffect(\n    on(\n      () => input.index,\n      () => {\n        if (\n          sortable.manager?.dragOperation.status.idle &&\n          sortable.transition?.idle\n        ) {\n          sortable.refreshShape();\n        }\n      }\n    )\n  );\n\n  return {\n    get sortable() {\n      return sortable;\n    },\n    isDragging: () => trackedSortable().isDragging,\n    isDropping: () => trackedSortable().isDropping,\n    isDragSource: () => trackedSortable().isDragSource,\n    isDropTarget: () => trackedSortable().isDropTarget,\n    ref: setElement,\n    handleRef: setHandle,\n    sourceRef: setSource,\n    targetRef: setTarget,\n  };\n}\n"
  },
  {
    "path": "packages/solid/src/utilities/index.ts",
    "content": "export {createSaveElementPosition} from './saveElementPosition.ts';\n"
  },
  {
    "path": "packages/solid/src/utilities/saveElementPosition.ts",
    "content": "import type {UniqueIdentifier} from '@dnd-kit/abstract';\nimport type {Draggable} from '@dnd-kit/dom';\n\n// Workaround for SolidJS issue:\n// https://github.com/solidjs/solid/issues/2515\nexport function createSaveElementPosition() {\n  let savedPosition: {\n    id: UniqueIdentifier | null;\n    element: Element;\n    prevElement: Element | null;\n    nextElement: Element | null;\n    parentElement: HTMLElement | null;\n  } | null = null;\n\n  const savePosition = (source: Draggable) => {\n    const element = source.element!;\n    const id = source.id;\n\n    const prevElement = element.previousElementSibling;\n    const nextElement = element.nextElementSibling;\n    const parentElement = element.parentElement;\n\n    savedPosition = {\n      id,\n      element,\n      prevElement: prevElement === element ? null : prevElement,\n      nextElement: nextElement === element ? null : nextElement,\n      parentElement,\n    };\n  };\n\n  const restorePosition = (element: Element) => {\n    if (!savedPosition) return;\n\n    const {prevElement, nextElement, parentElement} = savedPosition;\n\n    if (prevElement && element.previousElementSibling !== prevElement) {\n      prevElement.insertAdjacentElement('afterend', element);\n    } else if (nextElement && element.nextElementSibling !== nextElement) {\n      nextElement.insertAdjacentElement('beforebegin', element);\n    } else if (!prevElement && !nextElement && parentElement) {\n      parentElement.appendChild(element);\n    }\n  };\n\n  const clearPosition = () => {\n    savedPosition = null;\n  };\n\n  return {\n    savePosition,\n    clearPosition,\n    restorePosition,\n  };\n}\n"
  },
  {
    "path": "packages/solid/tsconfig.json",
    "content": "{\n  \"extends\": \"../../config/typescript/solid.json\",\n  \"include\": [\"src/**/*\"],\n  \"exclude\": [\"dist\", \"build\", \"node_modules\"]\n}\n"
  },
  {
    "path": "packages/solid/tsup.config.ts",
    "content": "import {defineConfig} from 'tsup';\nimport {solidPlugin} from 'esbuild-plugin-solid';\n\nexport default defineConfig((options) => ({\n  dts: true,\n  outDir: './',\n  external: [\n    '@dnd-kit/abstract',\n    '@dnd-kit/solid',\n    '@dnd-kit/dom',\n    '@dnd-kit/state',\n  ],\n  format: ['esm', 'cjs'],\n  sourcemap: true,\n  treeshake: !options.watch,\n  esbuildPlugins: [solidPlugin()],\n  esbuildOptions(esbuildOptions) {\n    esbuildOptions.jsx = 'preserve';\n    esbuildOptions.jsxImportSource = 'solid-js';\n  },\n}));\n"
  },
  {
    "path": "packages/state/CHANGELOG.md",
    "content": "# @dnd-kit/state\n\n## 0.3.2\n\n## 0.3.1\n\n## 0.3.0\n\n## 0.2.4\n\n## 0.2.3\n\n## 0.2.2\n\n## 0.2.1\n\n## 0.2.0\n\n## 0.1.21\n\n## 0.1.20\n\n### Patch Changes\n\n- [#1739](https://github.com/clauderic/dnd-kit/pull/1739) [`98d4cd4`](https://github.com/clauderic/dnd-kit/commit/98d4cd4047c56589cdf21067526426717bba01c4) Thanks [@clauderic](https://github.com/clauderic)! - Fixed a bug in the `deepEqual` comparator when comparing the keys of same length objects.\n\n- [#1737](https://github.com/clauderic/dnd-kit/pull/1737) [`32448ff`](https://github.com/clauderic/dnd-kit/commit/32448ff11eb3e86a28fc8f6ef7a8a3761e092412) Thanks [@github-actions](https://github.com/apps/github-actions)! - Bump `@preact/signals-core` to `1.10.0`\n\n## 0.1.19\n\n### Patch Changes\n\n- [#1724](https://github.com/clauderic/dnd-kit/pull/1724) [`d848327`](https://github.com/clauderic/dnd-kit/commit/d848327b242c6714b36207071ad30e6b4183e865) Thanks [@project42da](https://github.com/project42da)! - Replaced JSON.stringify() with a recursive comparison for plain objects.\n\n## 0.1.18\n\n## 0.1.17\n\n## 0.1.16\n\n## 0.1.15\n\n## 0.1.14\n\n## 0.1.13\n\n## 0.1.12\n\n## 0.1.11\n\n## 0.1.10\n\n## 0.1.9\n\n## 0.1.8\n\n## 0.1.7\n\n## 0.1.6\n\n### Patch Changes\n\n- [`299389b`](https://github.com/clauderic/dnd-kit/commit/299389befcc747fe8d79231ba32f73afae88615e) Thanks [@clauderic](https://github.com/clauderic)! - Fix cycle in `ValueHistory` setter for current\n\n## 0.1.5\n\n## 0.1.4\n\n## 0.1.3\n\n### Patch Changes\n\n- [#1663](https://github.com/clauderic/dnd-kit/pull/1663) [`8f91d91`](https://github.com/clauderic/dnd-kit/commit/8f91d9112608d2077c3b6c8fc939aa052606148c) Thanks [@github-actions](https://github.com/apps/github-actions)! - Remove `queueMicrotask` from constructor of `ValueHistory`.\n\n- [#1663](https://github.com/clauderic/dnd-kit/pull/1663) [`9a0edf6`](https://github.com/clauderic/dnd-kit/commit/9a0edf64cbde1bd761f3650e043b6612e61a5fab) Thanks [@github-actions](https://github.com/apps/github-actions)! - Refactor Sortable store implementation to use a new `WeakStore` class\n\n  - Add new `WeakStore` constructor in `@dnd-kit/state` package\n  - Replace Map-based store implementation in Sortable with new WeakStore utility\n\n- [#1663](https://github.com/clauderic/dnd-kit/pull/1663) [`a9db4c7`](https://github.com/clauderic/dnd-kit/commit/a9db4c73467d9eda9f95fe5b582948c9fc735f57) Thanks [@github-actions](https://github.com/apps/github-actions)! - Update `@preact/signals-core` from v1.6.0 to v1.8.0\n\n## 0.1.2\n\n### Patch Changes\n\n- [#1658](https://github.com/clauderic/dnd-kit/pull/1658) [`ee55f58`](https://github.com/clauderic/dnd-kit/commit/ee55f582f92dc42cc6eea9ad7492fc782ca6455a) Thanks [@github-actions](https://github.com/apps/github-actions)! - Add new state management features:\n\n  - Add `ValueHistory` class for tracking value changes over time\n  - Add `enumerable` decorator for controlling property enumeration\n  - Add `snapshot` utility for creating immutable copies of reactive objects\n  - Refactor `Position` class to extend `ValueHistory` for better state tracking\n\n## 0.1.1\n\n## 0.1.0\n\n## 0.0.10\n\n## 0.0.9\n\n## 0.0.8\n\n## 0.0.7\n\n## 0.0.6\n\n### Patch Changes\n\n- [#1567](https://github.com/clauderic/dnd-kit/pull/1567) [`081b7f2`](https://github.com/clauderic/dnd-kit/commit/081b7f2a11da2aad8ce3da7f0579974415d1fdf0) Thanks [@chrisvxd](https://github.com/chrisvxd)! - Add source maps to output.\n\n- [#1454](https://github.com/clauderic/dnd-kit/pull/1454) [`b750c05`](https://github.com/clauderic/dnd-kit/commit/b750c05b4b14f5d9817dc07d974d40b74470e904) Thanks [@github-actions](https://github.com/apps/github-actions)! - Fixed a bug with comparing functions incorrectly for equality in `deepEqual` utility.\n\n## 0.0.5\n\n## 0.0.4\n\n### Patch Changes\n\n- [#1443](https://github.com/clauderic/dnd-kit/pull/1443) [`a4d9150`](https://github.com/clauderic/dnd-kit/commit/a4d91500124698abf58355592913f84d438faa3d) Thanks [@clauderic](https://github.com/clauderic)! - Refactor decorators to use the [latest decorators API](https://devblogs.microsoft.com/typescript/announcing-typescript-5-0/#decorators) rather than the experimental API.\n\n## 0.0.3\n\n## 0.0.2\n\n### Patch Changes\n\n- [#1430](https://github.com/clauderic/dnd-kit/pull/1430) [`6c84308`](https://github.com/clauderic/dnd-kit/commit/6c84308b45c55ca1324a5c752b0ec117235da9e2) Thanks [@clauderic](https://github.com/clauderic)! - - `deepEqual`: Handle comparing `Set` instances\n"
  },
  {
    "path": "packages/state/README.md",
    "content": "# @dnd-kit/state\n\n[![Stable release](https://img.shields.io/npm/v/@dnd-kit/state.svg)](https://npm.im/@dnd-kit/state)\n\nInternal reactive state management library for **@dnd-kit**, built on [Preact Signals](https://preactjs.com/guide/v10/signals/).\n\n> **Note:** This is an internal package used by `@dnd-kit/abstract` and the framework adapters. You generally don't need to install or use it directly.\n\n## Overview\n\nProvides fine-grained reactivity primitives that power the core drag and drop state:\n\n- **Signals** — `signal`, `computed`, `ReadonlySignal`\n- **Effects** — `effect`, `effects`, `batch`, `untracked`\n- **Decorators** — `reactive`, `derived`, `enumerable` for class-based reactive properties\n- **Utilities** — `deepEqual`, `snapshot`, `WeakStore`, `ValueHistory`\n"
  },
  {
    "path": "packages/state/package.json",
    "content": "{\n  \"name\": \"@dnd-kit/state\",\n  \"version\": \"0.3.2\",\n  \"main\": \"./dist/index.js\",\n  \"module\": \"./dist/index.mjs\",\n  \"types\": \"./dist/index.d.ts\",\n  \"sideEffects\": false,\n  \"license\": \"MIT\",\n  \"files\": [\n    \"dist/**\"\n  ],\n  \"scripts\": {\n    \"build\": \"tsup src/index.ts --format esm,cjs --dts --external react\",\n    \"dev\": \"tsup src/index.ts --format esm,cjs --watch --dts --external react\",\n    \"test\": \"bun test\",\n    \"lint\": \"TIMING=1 eslint src/**/*.ts* --fix\",\n    \"clean\": \"rm -rf .turbo && rm -rf node_modules && rm -rf dist\"\n  },\n  \"dependencies\": {\n    \"@preact/signals-core\": \"^1.10.0\",\n    \"tslib\": \"^2.6.2\"\n  },\n  \"devDependencies\": {\n    \"@dnd-kit/eslint-config\": \"*\",\n    \"bun-types\": \"^1.2.15\",\n    \"eslint\": \"^8.38.0\",\n    \"tsup\": \"8.3.0\",\n    \"typescript\": \"^5.5.2\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/clauderic/dnd-kit\"\n  }\n}\n"
  },
  {
    "path": "packages/state/src/comparators.ts",
    "content": "export function deepEqual<T>(a: T, b: T): boolean {\n  if (Object.is(a, b)) {\n    return true;\n  }\n\n  if (a === null || b === null) return false;\n\n  if (typeof a === 'function' && typeof b === 'function') {\n    return a === b;\n  }\n\n  if (a instanceof Set && b instanceof Set) {\n    if (a.size !== b.size) {\n      return false;\n    }\n\n    for (const value of a) {\n      if (!b.has(value)) {\n        return false;\n      }\n    }\n\n    return true;\n  }\n\n  if (Array.isArray(a)) {\n    if (!Array.isArray(b) || a.length !== b.length) {\n      return false;\n    }\n\n    const hasDifferentValues = a.some(\n      (value, index) => !deepEqual(value, b[index])\n    );\n\n    return !hasDifferentValues;\n  }\n\n  if (typeof a === 'object' && typeof b === 'object') {\n    const aKeys = Object.keys(a);\n    const bKeys = Object.keys(b);\n    if (aKeys.length !== bKeys.length) return false;\n\n    const hasDifferentValues = aKeys.some(\n      (key) => !deepEqual(a[key as keyof T], b[key as keyof T])\n    );\n\n    return !hasDifferentValues;\n  }\n\n  return false;\n}\n"
  },
  {
    "path": "packages/state/src/computed.ts",
    "content": "import {\n  computed as computedSignal,\n  type ReadonlySignal,\n} from '@preact/signals-core';\n\nexport function computed<T>(\n  compute: () => T,\n  comparator?: (a: T, b: T) => boolean\n): ReadonlySignal<T> {\n  if (comparator) {\n    let previousValue: T | undefined;\n\n    return computedSignal(() => {\n      const value = compute();\n\n      if (value && previousValue && comparator(previousValue, value)) {\n        return previousValue;\n      }\n\n      previousValue = value;\n      return value;\n    });\n  }\n\n  return computedSignal<T>(compute);\n}\n"
  },
  {
    "path": "packages/state/src/decorators.ts",
    "content": "import {signal, type Signal} from '@preact/signals-core';\n\nimport {computed} from './computed';\n\nexport function reactive<This, Value>(\n  {get}: ClassAccessorDecoratorTarget<This, Value>,\n  _: ClassAccessorDecoratorContext<This, Value>\n): ClassAccessorDecoratorResult<This, Value> {\n  return {\n    init(value: Value) {\n      return signal(value) as Value;\n    },\n    get(): Value {\n      const current = get.call(this) as Signal<Value>;\n      return current.value;\n    },\n    set(newValue: Value) {\n      const current = get.call(this) as Signal<Value>;\n\n      if (current.peek() === newValue) {\n        return;\n      }\n\n      current.value = newValue;\n    },\n  };\n}\n\nexport function derived<This, Return>(\n  target: (this: This) => Return,\n  _: ClassGetterDecoratorContext<This, Return>\n) {\n  const map: WeakMap<any, Signal<Return>> = new WeakMap();\n\n  return function (this: This): Return {\n    let result = map.get(this);\n\n    if (!result) {\n      result = computed(target.bind(this));\n\n      map.set(this, result);\n    }\n\n    return result.value;\n  };\n}\n\n/**\n * Make a field enumerable (or non‑enumerable) on every instance.\n *\n *   @enumerable(true)  – enumerable\n *   @enumerable(false) – non‑enumerable\n */\nexport function enumerable(enumerable: boolean = true) {\n  return function (\n    _value: unknown,\n    context:\n      | ClassFieldDecoratorContext<any, any>\n      | ClassGetterDecoratorContext<any, any>\n      | ClassSetterDecoratorContext<any, any>\n      | ClassAccessorDecoratorContext<any, any>\n      | ClassMethodDecoratorContext<any, any>\n  ) {\n    context.addInitializer(function () {\n      const host =\n        context.kind === 'field' // own field  → instance\n          ? this\n          : context.static // static member → constructor\n            ? this\n            : Object.getPrototypeOf(this); // prototype member\n      const descriptor = Object.getOwnPropertyDescriptor(host, context.name);\n\n      if (descriptor) {\n        Object.defineProperty(host, context.name, {...descriptor, enumerable});\n      }\n    });\n  };\n}\n"
  },
  {
    "path": "packages/state/src/effects.ts",
    "content": "import {effect} from '@preact/signals-core';\n\nimport type {Effect, CleanupFunction} from './types';\n\nexport function effects(...entries: Effect[]): CleanupFunction {\n  const effects = entries.map((fn) => effect(fn));\n\n  return () => effects.forEach((cleanup) => cleanup());\n}\n"
  },
  {
    "path": "packages/state/src/history.ts",
    "content": "import {batch, untracked} from '@preact/signals-core';\n\nimport {enumerable, reactive} from './decorators.ts';\n\nexport type WithHistory<T> = {\n  current: T;\n  initial: T;\n  previous: T | undefined;\n};\n\nexport class ValueHistory<T> implements WithHistory<T> {\n  constructor(\n    protected readonly defaultValue: T,\n    protected readonly equals: (a: T, b: T) => boolean = Object.is\n  ) {\n    this.reset = this.reset.bind(this);\n    this.reset();\n  }\n\n  @reactive\n  // @ts-ignore\n  accessor #initial: T;\n\n  @reactive\n  // @ts-ignore\n  accessor #previous: T | undefined;\n\n  @reactive\n  // @ts-ignore\n  accessor #current: T;\n\n  /** Current value */\n  @enumerable()\n  public get current(): T {\n    return this.#current;\n  }\n\n  /** Initial value */\n  @enumerable()\n  public get initial(): T {\n    return this.#initial;\n  }\n\n  /** Previous value */\n  @enumerable()\n  public get previous(): T | undefined {\n    return this.#previous;\n  }\n\n  /** Set the current value */\n  public set current(value: T) {\n    const current = untracked(() => this.#current);\n\n    if (value && current && this.equals(current, value)) {\n      return;\n    }\n\n    batch(() => {\n      if (!this.#initial) {\n        this.#initial = value;\n      }\n\n      this.#previous = current;\n      this.#current = value;\n    });\n  }\n\n  /** Reset the state to the initial value */\n  public reset(value = this.defaultValue) {\n    batch(() => {\n      this.#previous = undefined;\n      this.#initial = value;\n      this.#current = value;\n    });\n  }\n}\n"
  },
  {
    "path": "packages/state/src/index.ts",
    "content": "export {\n  batch,\n  effect,\n  untracked,\n  signal,\n  Signal,\n  type ReadonlySignal,\n} from '@preact/signals-core';\n\nexport {computed} from './computed';\n\nexport {deepEqual} from './comparators';\n\nexport {derived, enumerable, reactive} from './decorators';\n\nexport {effects} from './effects';\n\nexport {ValueHistory, type WithHistory} from './history';\n\nexport {snapshot} from './snapshot';\n\nexport type {CleanupFunction, Effect} from './types';\n\nexport {WeakStore} from './store';\n"
  },
  {
    "path": "packages/state/src/snapshot.ts",
    "content": "import {untracked} from '@preact/signals-core';\n\nexport function snapshot<T extends object>(value: T): T {\n  return untracked(() => {\n    const output = {} as T;\n\n    for (const key in value) {\n      output[key] = value[key];\n    }\n\n    return output;\n  });\n}\n"
  },
  {
    "path": "packages/state/src/store.ts",
    "content": "export class WeakStore<\n  WeakKey extends object,\n  Key extends string | number | symbol,\n  Value extends Record<Key, any>,\n> {\n  #store = new WeakMap<WeakKey, Map<Key, Value>>();\n\n  get(key: WeakKey | undefined, id: Key) {\n    return key ? this.#store.get(key)?.get(id) : undefined;\n  }\n\n  set(key: WeakKey | undefined, id: Key, value: Value) {\n    if (!key) return;\n    if (!this.#store.has(key)) this.#store.set(key, new Map());\n\n    return this.#store.get(key)?.set(id, value);\n  }\n\n  clear(key: WeakKey | undefined) {\n    return key ? this.#store.get(key)?.clear() : undefined;\n  }\n}\n"
  },
  {
    "path": "packages/state/src/types.ts",
    "content": "import type {effect} from '@preact/signals-core';\n\nexport type CleanupFunction = () => void;\n\nexport type Effect = Parameters<typeof effect>[0];\n"
  },
  {
    "path": "packages/state/tests/comparators.test.ts",
    "content": "import {describe, expect, it} from 'bun:test';\nimport {deepEqual} from '../src/comparators';\n\ndescribe('deepEqual', () => {\n  it('should return true for same primitives', () => {\n    expect(deepEqual(1, 1)).toBe(true);\n    expect(deepEqual('a', 'a')).toBe(true);\n    expect(deepEqual(true, true)).toBe(true);\n    expect(deepEqual(null, null)).toBe(true);\n    expect(deepEqual(undefined, undefined)).toBe(true);\n  });\n\n  it('should return false for different primitives', () => {\n    expect(deepEqual(1, 2)).toBe(false);\n    expect(deepEqual('a', 'b')).toBe(false);\n  });\n\n  it('should compare functions by reference', () => {\n    const fn1 = () => {};\n    const fn2 = () => {};\n    expect(deepEqual(fn1, fn1)).toBe(true);\n    expect(deepEqual(fn1, fn2)).toBe(false);\n  });\n\n  it('should compare arrays deeply', () => {\n    expect(deepEqual([1, 2, 3], [1, 2, 3])).toBe(true);\n    expect(deepEqual([1, [2, 3]], [1, [2, 3]])).toBe(true);\n    expect(deepEqual([1, 2], [2, 1])).toBe(false);\n  });\n\n  it('should compare sets', () => {\n    expect(deepEqual(new Set([1, 2]), new Set([2, 1]))).toBe(true);\n    expect(deepEqual(new Set([1, 2]), new Set([1, 2, 3]))).toBe(false);\n  });\n\n  it('should compare plain objects', () => {\n    expect(deepEqual({a: 1}, {a: 1})).toBe(true);\n    expect(deepEqual({a: 1, b: 2}, {b: 2, a: 1})).toBe(true);\n    expect(deepEqual({a: 1}, {a: 2})).toBe(false);\n  });\n\n  it('should detect differing values when only some keys match', () => {\n    expect(deepEqual({a: 1, b: 1}, {a: 1, b: 2})).toBe(false);\n  });\n});\n"
  },
  {
    "path": "packages/state/tsconfig.json",
    "content": "{\n  \"extends\": \"../../config/typescript/vanilla.json\",\n  \"include\": [\"src/**/*\", \"tests/**/*\"],\n  \"exclude\": [\"dist\", \"build\", \"node_modules\"],\n  \"compilerOptions\": {\n    \"types\": [\"bun-types\"]\n  }\n}\n"
  },
  {
    "path": "packages/storybook-addon-codesandbox/package.json",
    "content": "{\n  \"name\": \"@dnd-kit/storybook-addon-codesandbox\",\n  \"version\": \"0.0.0\",\n  \"private\": true,\n  \"type\": \"module\",\n  \"exports\": {\n    \".\": {\n      \"import\": \"./src/index.ts\"\n    },\n    \"./manager\": \"./src/manager.tsx\",\n    \"./preset\": \"./src/preset.ts\",\n    \"./decorator\": \"./src/preview/decorator.tsx\",\n    \"./decorator-dom\": \"./src/preview/decorator-dom.ts\",\n    \"./package.json\": \"./package.json\"\n  },\n  \"dependencies\": {\n    \"storybook\": \"^9.0.15\"\n  }\n}\n"
  },
  {
    "path": "packages/storybook-addon-codesandbox/src/collect-files.ts",
    "content": "import type {CodeSandboxParameters, SandboxFile} from './types.ts';\n\n/**\n * Normalizes a file entry to a SandboxFile object.\n */\nfunction normalizeFile(file: string | SandboxFile): SandboxFile {\n  if (typeof file === 'string') {\n    return {content: file};\n  }\n\n  return file;\n}\n\n/**\n * Generates the package.json content for the sandbox.\n */\nfunction generatePackageJson(\n  dependencies: Record<string, string>,\n  devDependencies: Record<string, string>,\n  main: string\n): SandboxFile {\n  return {\n    content: JSON.stringify(\n      {\n        name: 'dnd-kit-sandbox',\n        main,\n        dependencies,\n        devDependencies,\n      },\n      null,\n      2\n    ),\n  };\n}\n\n/**\n * Generates a default index file that imports the main app file.\n */\nfunction generateIndexFile(mainFile: string, entryFile: string): string {\n  // Compute the import path relative to the entry file's directory\n  const entryDir = entryFile.substring(0, entryFile.lastIndexOf('/') + 1);\n  let relativePath = mainFile;\n\n  if (entryDir && mainFile.startsWith(entryDir)) {\n    relativePath = mainFile.substring(entryDir.length);\n  }\n\n  // Ensure the import path is relative\n  const importPath = relativePath.startsWith('./')\n    ? relativePath\n    : `./${relativePath}`;\n\n  // Strip extension for import\n  const importPathNoExt = importPath.replace(/\\.\\w+$/, '');\n\n  return [\n    `import App from '${importPathNoExt}';`,\n    '',\n  ].join('\\n');\n}\n\nexport interface CollectFilesOptions {\n  /** Global parameters from preview config */\n  globalParams: CodeSandboxParameters;\n  /** Per-story parameters */\n  storyParams: CodeSandboxParameters;\n  /** The story's source code */\n  storySource: string;\n}\n\n/**\n * Collects and merges all files needed for the sandbox.\n *\n * Priority (highest wins on conflict):\n * 1. Generated files (package.json, index)\n * 2. Per-story files\n * 3. Global files\n */\nexport function collectFiles(options: CollectFilesOptions): Record<string, SandboxFile> {\n  const {globalParams, storyParams, storySource} = options;\n  const files: Record<string, SandboxFile> = {};\n\n  // 1. Add global files\n  if (globalParams.files) {\n    for (const [path, file] of Object.entries(globalParams.files)) {\n      files[path] = normalizeFile(file);\n    }\n  }\n\n  // 2. Add per-story files (overrides global)\n  if (storyParams.files) {\n    for (const [path, file] of Object.entries(storyParams.files)) {\n      files[path] = normalizeFile(file);\n    }\n  }\n\n  // 3. Add the story source as the main file\n  const mainFile = storyParams.mainFile ?? globalParams.mainFile ?? 'src/App.jsx';\n  files[mainFile] = {content: storySource};\n\n  // 4. Add index entry if not provided\n  const indexFiles = ['src/index.js', 'src/index.tsx', 'index.js', 'index.tsx'];\n  let entryFile = indexFiles.find((f) => files[f]);\n\n  if (!entryFile) {\n    entryFile = 'src/index.js';\n    const entry = storyParams.entry ?? globalParams.entry;\n\n    if (entry) {\n      files[entryFile] = {content: entry};\n    } else {\n      files[entryFile] = {content: generateIndexFile(mainFile, entryFile)};\n    }\n  }\n\n  // 5. Merge dependencies and generate package.json (skip if explicitly provided)\n  if (!files['package.json']) {\n    const dependencies = {\n      ...globalParams.dependencies,\n      ...storyParams.dependencies,\n    };\n    const devDependencies = {\n      ...globalParams.devDependencies,\n      ...storyParams.devDependencies,\n    };\n\n    files['package.json'] = generatePackageJson(\n      dependencies,\n      devDependencies,\n      `/${entryFile}`\n    );\n  }\n\n  return files;\n}\n"
  },
  {
    "path": "packages/storybook-addon-codesandbox/src/constants.ts",
    "content": "export const ADDON_ID = 'dnd-kit/codesandbox';\nexport const TOOL_ID = `${ADDON_ID}/tool`;\n\nexport const CODESANDBOX_DEFINE_URL =\n  'https://codesandbox.io/api/v1/sandboxes/define';\n"
  },
  {
    "path": "packages/storybook-addon-codesandbox/src/define.ts",
    "content": "import {CODESANDBOX_DEFINE_URL} from './constants.ts';\nimport type {SandboxFile} from './types.ts';\n\ninterface DefineRequest {\n  files: Record<string, SandboxFile>;\n  template?: string;\n}\n\ninterface DefineResponse {\n  sandbox_id: string;\n}\n\n/**\n * Creates a sandbox on CodeSandbox using the public define API.\n * No authentication required -- the sandbox is created anonymously\n * and the visitor can fork it into their own account.\n */\nexport async function createSandbox(\n  files: Record<string, SandboxFile>,\n  template?: string\n): Promise<string> {\n  const body: DefineRequest = {files};\n\n  if (template) {\n    body.template = template;\n  }\n\n  const response = await fetch(`${CODESANDBOX_DEFINE_URL}?json=1`, {\n    method: 'POST',\n    headers: {'Content-Type': 'application/json'},\n    body: JSON.stringify(body),\n  });\n\n  if (!response.ok) {\n    throw new Error(\n      `Failed to create sandbox: ${response.status} ${response.statusText}`\n    );\n  }\n\n  const data: DefineResponse = await response.json();\n\n  return data.sandbox_id;\n}\n\n/**\n * Opens a CodeSandbox in a new tab.\n */\nexport function openSandbox(sandboxId: string, mainFile?: string): void {\n  const params = new URLSearchParams();\n\n  if (mainFile) {\n    params.set('file', `/${mainFile}`);\n  }\n\n  const query = params.toString();\n  const url = `https://codesandbox.io/s/${sandboxId}${query ? `?${query}` : ''}`;\n\n  window.open(url, '_blank', 'noopener,noreferrer');\n}\n\n/**\n * Opens a project in StackBlitz via a form POST.\n *\n * No API call or SDK needed — the files are encoded as hidden form\n * fields and submitted directly to StackBlitz, which opens the\n * project in a new tab.\n */\nexport function openStackBlitz(\n  files: Record<string, SandboxFile>,\n  options?: {title?: string; template?: string; openFile?: string}\n): void {\n  const form = document.createElement('form');\n  form.method = 'POST';\n  form.action = 'https://stackblitz.com/run';\n  form.target = '_blank';\n\n  function addField(name: string, value: string) {\n    const input = document.createElement('input');\n    input.type = 'hidden';\n    input.name = name;\n    input.value = value;\n    form.appendChild(input);\n  }\n\n  for (const [path, file] of Object.entries(files)) {\n    addField(`project[files][${path}]`, file.content);\n  }\n\n  addField('project[template]', options?.template ?? 'node');\n\n  if (options?.title) {\n    addField('project[title]', options.title);\n  }\n\n  if (options?.openFile) {\n    addField('project[settings][compile][trigger]', 'auto');\n    addField('project[settings][compile][clearConsole]', 'false');\n  }\n\n  document.body.appendChild(form);\n  form.submit();\n  document.body.removeChild(form);\n}\n"
  },
  {
    "path": "packages/storybook-addon-codesandbox/src/index.ts",
    "content": "export type {CodeSandboxParameters} from './types.ts';\n"
  },
  {
    "path": "packages/storybook-addon-codesandbox/src/manager.tsx",
    "content": "import React, {useCallback, useState} from 'react';\nimport {addons, types} from 'storybook/manager-api';\nimport {IconButton} from 'storybook/internal/components';\nimport {\n  useStorybookApi,\n  useParameter,\n  useStorybookState,\n} from 'storybook/manager-api';\n\nimport {ADDON_ID, TOOL_ID} from './constants.ts';\nimport {collectFiles} from './collect-files.ts';\nimport {createSandbox, openSandbox, openStackBlitz} from './define.ts';\nimport type {CodeSandboxParameters} from './types.ts';\n\nfunction CodeSandboxIcon() {\n  return (\n    <svg\n      width=\"14\"\n      height=\"14\"\n      viewBox=\"0 0 24 24\"\n      fill=\"none\"\n      stroke=\"currentColor\"\n      strokeWidth=\"2\"\n      strokeLinecap=\"round\"\n      strokeLinejoin=\"round\"\n    >\n      <path d=\"M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z\" />\n      <polyline points=\"7.5 4.21 12 6.81 16.5 4.21\" />\n      <polyline points=\"7.5 19.79 7.5 14.6 3 12\" />\n      <polyline points=\"21 12 16.5 14.6 16.5 19.79\" />\n      <line x1=\"3.27\" y1=\"6.96\" x2=\"12\" y2=\"12.01\" />\n      <line x1=\"12\" y1=\"12.01\" x2=\"20.73\" y2=\"6.96\" />\n      <line x1=\"12\" y1=\"22.08\" x2=\"12\" y2=\"12\" />\n    </svg>\n  );\n}\n\ntype ExportState = 'idle' | 'loading' | 'success' | 'error';\n\nfunction CodeSandboxTool() {\n  const [state, setState] = useState<ExportState>('idle');\n  const api = useStorybookApi();\n  const storybookState = useStorybookState();\n\n  // Get the codesandbox parameters (merged from global + story level by Storybook)\n  const storyParams = useParameter<CodeSandboxParameters>('codesandbox') ?? {};\n\n  const handleClick = useCallback(async () => {\n    if (state === 'loading') return;\n\n    setState('loading');\n\n    try {\n      // Get the current story data\n      const storyId = storybookState.storyId;\n\n      if (!storyId) {\n        throw new Error('No story selected');\n      }\n\n      const storyData = api.getData(storyId);\n\n      if (!storyData) {\n        throw new Error('Could not retrieve story data');\n      }\n\n      // Extract story source from parameters\n      const storySource =\n        storyParams.files?.[storyParams.mainFile ?? 'src/App.jsx'];\n\n      if (!storySource) {\n        throw new Error(\n          'No story source found. Add source code to the `codesandbox.files` parameter on your story.'\n        );\n      }\n\n      const sourceContent =\n        typeof storySource === 'string' ? storySource : storySource.content;\n\n      // Get global parameters from the store\n      // Storybook merges parameters, so storyParams already contains the merged result.\n      // We pass storyParams as both global and story since Storybook handles the merge.\n      const files = collectFiles({\n        globalParams: {},\n        storyParams,\n        storySource: sourceContent,\n      });\n\n      if (storyParams.provider === 'stackblitz') {\n        openStackBlitz(files, {\n          title: 'dnd-kit sandbox',\n          template: storyParams.template ?? 'node',\n          openFile: storyParams.mainFile,\n        });\n      } else {\n        const sandboxId = await createSandbox(files, storyParams.template);\n        openSandbox(sandboxId, storyParams.mainFile);\n      }\n\n      setState('success');\n      setTimeout(() => setState('idle'), 2000);\n    } catch (error) {\n      console.error('[CodeSandbox Addon]', error);\n      setState('error');\n      setTimeout(() => setState('idle'), 3000);\n    }\n  }, [api, state, storyParams, storybookState.storyId]);\n\n  // Only show the button if the story has a sandbox source file defined\n  const mainFile = storyParams.mainFile ?? 'src/App.jsx';\n  const hasSource = storyParams.files?.[mainFile] != null;\n\n  if (!hasSource) {\n    return null;\n  }\n\n  const title =\n    state === 'loading'\n      ? 'Creating sandbox...'\n      : state === 'success'\n        ? 'Sandbox created!'\n        : state === 'error'\n          ? 'Failed to create sandbox'\n          : 'Open Sandbox';\n\n  return (\n    <IconButton\n      key={TOOL_ID}\n      title={title}\n      onClick={handleClick}\n      disabled={state === 'loading'}\n      style={{\n        opacity: state === 'loading' ? 0.5 : 1,\n        color:\n          state === 'success'\n            ? '#1eb99d'\n            : state === 'error'\n              ? '#e53e3e'\n              : undefined,\n      }}\n    >\n      <CodeSandboxIcon />\n    </IconButton>\n  );\n}\n\naddons.register(ADDON_ID, () => {\n  addons.add(TOOL_ID, {\n    type: types.TOOL,\n    title: 'Open Sandbox',\n    match: ({viewMode}) => viewMode === 'story',\n    render: () => <CodeSandboxTool />,\n  });\n});\n"
  },
  {
    "path": "packages/storybook-addon-codesandbox/src/preset.ts",
    "content": "export const managerEntries = [\n  new URL('./manager.tsx', import.meta.url).pathname,\n];\n"
  },
  {
    "path": "packages/storybook-addon-codesandbox/src/preview/CodeSandboxButton.tsx",
    "content": "import React, {useCallback, useEffect, useState} from 'react';\n\nimport {collectFiles} from '../collect-files.ts';\nimport {createSandbox, openSandbox, openStackBlitz} from '../define.ts';\nimport type {CodeSandboxParameters} from '../types.ts';\n\ntype ExportState = 'idle' | 'loading' | 'success' | 'error';\n\nfunction CodeSandboxIcon({size = 14}: {size?: number}) {\n  return (\n    <svg\n      width={size}\n      height={size}\n      viewBox=\"0 0 24 24\"\n      fill=\"none\"\n      stroke=\"currentColor\"\n      strokeWidth=\"2\"\n      strokeLinecap=\"round\"\n      strokeLinejoin=\"round\"\n    >\n      <path d=\"M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z\" />\n      <polyline points=\"7.5 4.21 12 6.81 16.5 4.21\" />\n      <polyline points=\"7.5 19.79 7.5 14.6 3 12\" />\n      <polyline points=\"21 12 16.5 14.6 16.5 19.79\" />\n      <line x1=\"3.27\" y1=\"6.96\" x2=\"12\" y2=\"12.01\" />\n      <line x1=\"12\" y1=\"12.01\" x2=\"20.73\" y2=\"6.96\" />\n      <line x1=\"12\" y1=\"22.08\" x2=\"12\" y2=\"12\" />\n    </svg>\n  );\n}\n\nconst themes = {\n  light: {\n    color: 'rgba(60, 70, 90, 0.5)',\n    colorHover: 'rgba(50, 60, 100, 0.75)',\n    bg: 'rgba(236, 238, 243, 0.25)',\n    bgHover: 'rgba(210, 218, 235, 0.5)',\n    border: 'rgba(180, 190, 210, 0.3)',\n    borderHover: 'rgba(160, 175, 210, 0.45)',\n  },\n  dark: {\n    color: 'rgba(180, 190, 210, 0.5)',\n    colorHover: 'rgba(210, 218, 235, 0.8)',\n    bg: 'rgba(255, 255, 255, 0.06)',\n    bgHover: 'rgba(255, 255, 255, 0.12)',\n    border: 'rgba(255, 255, 255, 0.08)',\n    borderHover: 'rgba(255, 255, 255, 0.16)',\n  },\n};\n\nfunction useDarkMode() {\n  const [dark, setDark] = useState(() =>\n    document.body.classList.contains('dark')\n  );\n\n  useEffect(() => {\n    const observer = new MutationObserver(() => {\n      setDark(document.body.classList.contains('dark'));\n    });\n    observer.observe(document.body, {\n      attributes: true,\n      attributeFilter: ['class'],\n    });\n    return () => observer.disconnect();\n  }, []);\n\n  return dark;\n}\n\nconst baseStyles: React.CSSProperties = {\n  position: 'fixed',\n  bottom: 12,\n  right: 12,\n  display: 'inline-flex',\n  alignItems: 'center',\n  gap: 6,\n  padding: '10px 14px',\n  fontSize: 12,\n  fontWeight: 500,\n  fontFamily: 'system-ui, sans-serif',\n  borderRadius: 6,\n  cursor: 'pointer',\n  zIndex: 9999,\n  backdropFilter: 'blur(8px)',\n  WebkitBackdropFilter: 'blur(8px)',\n  transition:\n    'opacity 200ms ease, color 200ms ease, background-color 200ms ease, border-color 200ms ease',\n  opacity: 0.85,\n};\n\ninterface Props {\n  params: CodeSandboxParameters;\n}\n\nexport function CodeSandboxButton({params}: Props) {\n  const [state, setState] = useState<ExportState>('idle');\n  const isDark = useDarkMode();\n  const t = isDark ? themes.dark : themes.light;\n\n  const handleClick = useCallback(async () => {\n    if (state === 'loading') return;\n\n    setState('loading');\n\n    try {\n      const mainFile = params.mainFile ?? 'src/App.jsx';\n      const storySource = params.files?.[mainFile];\n\n      if (!storySource) {\n        throw new Error('No story source found.');\n      }\n\n      const sourceContent =\n        typeof storySource === 'string' ? storySource : storySource.content;\n\n      const files = collectFiles({\n        globalParams: {},\n        storyParams: params,\n        storySource: sourceContent,\n      });\n\n      if (params.provider === 'stackblitz') {\n        openStackBlitz(files, {\n          title: 'dnd-kit sandbox',\n          template: params.template ?? 'node',\n          openFile: params.mainFile,\n        });\n      } else {\n        const sandboxId = await createSandbox(files, params.template);\n        openSandbox(sandboxId, params.mainFile);\n      }\n\n      setState('success');\n      setTimeout(() => setState('idle'), 2000);\n    } catch (error) {\n      console.error('[CodeSandbox Addon]', error);\n      setState('error');\n      setTimeout(() => setState('idle'), 3000);\n    }\n  }, [params, state]);\n\n  const label =\n    state === 'loading'\n      ? 'Creating...'\n      : state === 'success'\n        ? 'Opened!'\n        : state === 'error'\n          ? 'Failed'\n          : 'Open Sandbox';\n\n  const isActive = state !== 'idle';\n  const statusColor =\n    state === 'success' ? '#1eb99d' : state === 'error' ? '#e53e3e' : undefined;\n\n  return (\n    <button\n      onClick={handleClick}\n      disabled={state === 'loading'}\n      style={{\n        ...baseStyles,\n        color: statusColor ?? t.color,\n        backgroundColor: t.bg,\n        borderWidth: 1,\n        borderStyle: 'solid',\n        borderColor: statusColor ? `${statusColor}33` : t.border,\n        opacity: isActive ? 0.9 : baseStyles.opacity,\n      }}\n      onMouseEnter={(e) => {\n        e.currentTarget.style.opacity = '1';\n        e.currentTarget.style.color = statusColor ?? t.colorHover;\n        e.currentTarget.style.backgroundColor = t.bgHover;\n        e.currentTarget.style.borderColor = statusColor\n          ? `${statusColor}55`\n          : t.borderHover;\n      }}\n      onMouseLeave={(e) => {\n        if (!isActive) {\n          e.currentTarget.style.opacity = String(baseStyles.opacity);\n          e.currentTarget.style.color = statusColor ?? t.color;\n          e.currentTarget.style.backgroundColor = t.bg;\n          e.currentTarget.style.borderColor = statusColor\n            ? `${statusColor}33`\n            : t.border;\n        }\n      }}\n    >\n      <CodeSandboxIcon size={14} />\n      {label}\n    </button>\n  );\n}\n"
  },
  {
    "path": "packages/storybook-addon-codesandbox/src/preview/codesandbox-button-dom.ts",
    "content": "import {collectFiles} from '../collect-files.ts';\nimport {createSandbox, openSandbox, openStackBlitz} from '../define.ts';\nimport type {CodeSandboxParameters} from '../types.ts';\n\nconst BUTTON_ID = '__csb-addon-open-btn';\n\ntype ExportState = 'idle' | 'loading' | 'success' | 'error';\n\nconst SVG_ICON = [\n  '<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">',\n  '<path d=\"M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z\"/>',\n  '<polyline points=\"7.5 4.21 12 6.81 16.5 4.21\"/>',\n  '<polyline points=\"7.5 19.79 7.5 14.6 3 12\"/>',\n  '<polyline points=\"21 12 16.5 14.6 16.5 19.79\"/>',\n  '<line x1=\"3.27\" y1=\"6.96\" x2=\"12\" y2=\"12.01\"/>',\n  '<line x1=\"12\" y1=\"12.01\" x2=\"20.73\" y2=\"6.96\"/>',\n  '<line x1=\"12\" y1=\"22.08\" x2=\"12\" y2=\"12\"/>',\n  '</svg>',\n].join('');\n\nconst themes = {\n  light: {\n    color: 'rgba(60, 70, 90, 0.5)',\n    colorHover: 'rgba(50, 60, 100, 0.75)',\n    bg: 'rgba(236, 238, 243, 0.25)',\n    bgHover: 'rgba(210, 218, 235, 0.5)',\n    border: 'rgba(180, 190, 210, 0.3)',\n    borderHover: 'rgba(160, 175, 210, 0.45)',\n  },\n  dark: {\n    color: 'rgba(180, 190, 210, 0.5)',\n    colorHover: 'rgba(210, 218, 235, 0.8)',\n    bg: 'rgba(255, 255, 255, 0.06)',\n    bgHover: 'rgba(255, 255, 255, 0.12)',\n    border: 'rgba(255, 255, 255, 0.08)',\n    borderHover: 'rgba(255, 255, 255, 0.16)',\n  },\n};\n\nfunction isDarkMode(): boolean {\n  return document.body.classList.contains('dark');\n}\n\nfunction getTheme() {\n  return isDarkMode() ? themes.dark : themes.light;\n}\n\nexport function removeCodeSandboxButton(): void {\n  const existing = document.getElementById(BUTTON_ID);\n\n  if (existing) {\n    existing.remove();\n  }\n}\n\nexport function createCodeSandboxButton(\n  params: CodeSandboxParameters\n): HTMLButtonElement {\n  let state: ExportState = 'idle';\n\n  const btn = document.createElement('button');\n  btn.id = BUTTON_ID;\n\n  // Icon\n  const iconSpan = document.createElement('span');\n  iconSpan.innerHTML = SVG_ICON;\n  iconSpan.style.display = 'inline-flex';\n  iconSpan.style.alignItems = 'center';\n\n  // Label\n  const labelSpan = document.createElement('span');\n  labelSpan.textContent = 'Open Sandbox';\n\n  btn.appendChild(iconSpan);\n  btn.appendChild(labelSpan);\n\n  // Base styles\n  Object.assign(btn.style, {\n    position: 'fixed',\n    bottom: '12px',\n    right: '12px',\n    display: 'inline-flex',\n    alignItems: 'center',\n    gap: '6px',\n    padding: '10px 14px',\n    fontSize: '12px',\n    fontWeight: '500',\n    fontFamily: 'system-ui, sans-serif',\n    borderRadius: '6px',\n    cursor: 'pointer',\n    zIndex: '9999',\n    backdropFilter: 'blur(8px)',\n    WebkitBackdropFilter: 'blur(8px)',\n    transition:\n      'opacity 200ms ease, color 200ms ease, background-color 200ms ease, border-color 200ms ease',\n    opacity: '0.85',\n    borderWidth: '1px',\n    borderStyle: 'solid',\n    outline: 'none',\n  });\n\n  function getStatusColor(): string | undefined {\n    return state === 'success'\n      ? '#1eb99d'\n      : state === 'error'\n        ? '#e53e3e'\n        : undefined;\n  }\n\n  function applyTheme() {\n    const t = getTheme();\n    const statusColor = getStatusColor();\n\n    btn.style.color = statusColor ?? t.color;\n    btn.style.backgroundColor = t.bg;\n    btn.style.borderColor = statusColor ? `${statusColor}33` : t.border;\n  }\n\n  applyTheme();\n\n  // Watch for dark mode class changes on <body>\n  const observer = new MutationObserver(applyTheme);\n  observer.observe(document.body, {\n    attributes: true,\n    attributeFilter: ['class'],\n  });\n\n  function updateState(newState: ExportState) {\n    state = newState;\n\n    const t = getTheme();\n    const statusColor = getStatusColor();\n\n    btn.style.color = statusColor ?? t.color;\n    btn.style.borderColor = statusColor ? `${statusColor}33` : t.border;\n    btn.style.opacity = state !== 'idle' ? '0.9' : '0.85';\n    btn.disabled = state === 'loading';\n\n    labelSpan.textContent =\n      state === 'loading'\n        ? 'Creating...'\n        : state === 'success'\n          ? 'Opened!'\n          : state === 'error'\n            ? 'Failed'\n            : 'Open Sandbox';\n  }\n\n  // Hover effects\n  btn.addEventListener('mouseenter', () => {\n    const t = getTheme();\n    const statusColor = getStatusColor();\n\n    btn.style.opacity = '1';\n    btn.style.color = statusColor ?? t.colorHover;\n    btn.style.backgroundColor = t.bgHover;\n    btn.style.borderColor = statusColor ? `${statusColor}55` : t.borderHover;\n  });\n\n  btn.addEventListener('mouseleave', () => {\n    const t = getTheme();\n    const statusColor = getStatusColor();\n\n    if (state === 'idle') {\n      btn.style.opacity = '0.85';\n    }\n\n    btn.style.color = statusColor ?? t.color;\n    btn.style.backgroundColor = t.bg;\n    btn.style.borderColor = statusColor ? `${statusColor}33` : t.border;\n  });\n\n  // Click handler\n  btn.addEventListener('click', async () => {\n    if (state === 'loading') return;\n\n    updateState('loading');\n\n    try {\n      const mainFile = params.mainFile ?? 'src/App.jsx';\n      const storySource = params.files?.[mainFile];\n\n      if (!storySource) {\n        throw new Error('No story source found.');\n      }\n\n      const sourceContent =\n        typeof storySource === 'string' ? storySource : storySource.content;\n\n      const files = collectFiles({\n        globalParams: {},\n        storyParams: params,\n        storySource: sourceContent,\n      });\n\n      if (params.provider === 'stackblitz') {\n        openStackBlitz(files, {\n          title: 'dnd-kit sandbox',\n          template: params.template ?? 'node',\n          openFile: params.mainFile,\n        });\n      } else {\n        const sandboxId = await createSandbox(files, params.template);\n        openSandbox(sandboxId, params.mainFile);\n      }\n\n      updateState('success');\n      setTimeout(() => updateState('idle'), 2000);\n    } catch (error) {\n      console.error('[CodeSandbox Addon]', error);\n      updateState('error');\n      setTimeout(() => updateState('idle'), 3000);\n    }\n  });\n\n  return btn;\n}\n"
  },
  {
    "path": "packages/storybook-addon-codesandbox/src/preview/decorator-dom.ts",
    "content": "import {\n  createCodeSandboxButton,\n  removeCodeSandboxButton,\n} from './codesandbox-button-dom.ts';\nimport type {CodeSandboxParameters} from '../types.ts';\n\n/**\n * Framework-agnostic Storybook decorator that adds a floating\n * \"Open Sandbox\" button using plain DOM APIs.\n *\n * Works with any Storybook renderer (HTML, Vue, Solid, etc.).\n * For React stories, prefer the React-based decorator from\n * `@dnd-kit/storybook-addon-codesandbox/decorator` instead.\n *\n * Usage in .storybook/preview.ts:\n *\n *   import {withCodeSandbox} from '@dnd-kit/storybook-addon-codesandbox/decorator-dom';\n *\n *   export default {\n *     decorators: [withCodeSandbox],\n *   };\n */\nexport function withCodeSandbox(storyFn: any, context: any) {\n  removeCodeSandboxButton();\n\n  if (context.viewMode === 'docs') {\n    return storyFn();\n  }\n\n  const params: CodeSandboxParameters | undefined =\n    context.parameters?.codesandbox;\n  const mainFile = params?.mainFile ?? 'src/App.jsx';\n  const hasSource = params?.files?.[mainFile] != null;\n\n  const result = storyFn();\n\n  if (hasSource && params) {\n    requestAnimationFrame(() => {\n      removeCodeSandboxButton();\n      document.body.appendChild(createCodeSandboxButton(params));\n    });\n  }\n\n  return result;\n}\n"
  },
  {
    "path": "packages/storybook-addon-codesandbox/src/preview/decorator.tsx",
    "content": "import React from 'react';\n\nimport {CodeSandboxButton} from './CodeSandboxButton.tsx';\nimport type {CodeSandboxParameters} from '../types.ts';\n\n/**\n * Storybook decorator that adds a floating \"Open Sandbox\" button\n * to the bottom-right corner of stories that have sandbox source defined.\n *\n * Usage in .storybook/preview.tsx:\n *\n *   import {withCodeSandbox} from '@dnd-kit/storybook-addon-codesandbox/decorator';\n *\n *   export default {\n *     decorators: [withCodeSandbox],\n *   };\n */\nexport function withCodeSandbox(Story: React.ComponentType, context: any) {\n  if (context.viewMode === 'docs') {\n    return <Story />;\n  }\n\n  const params: CodeSandboxParameters | undefined =\n    context.parameters?.codesandbox;\n\n  const mainFile = params?.mainFile ?? 'src/App.jsx';\n  const hasSource = params?.files?.[mainFile] != null;\n\n  if (!hasSource) {\n    return <Story />;\n  }\n\n  return (\n    <>\n      <Story />\n      <CodeSandboxButton params={params!} />\n    </>\n  );\n}\n"
  },
  {
    "path": "packages/storybook-addon-codesandbox/src/types.ts",
    "content": "export interface SandboxFile {\n  content: string;\n  isBinary?: boolean;\n}\n\nexport type SandboxProvider = 'codesandbox' | 'stackblitz';\n\nexport interface CodeSandboxParameters {\n  /**\n   * Files to include in every sandbox created from this Storybook.\n   * Merged with per-story files (per-story wins on conflict).\n   */\n  files?: Record<string, string | SandboxFile>;\n\n  /**\n   * NPM dependencies to include in every sandbox.\n   * Merged with per-story dependencies (per-story wins on conflict).\n   */\n  dependencies?: Record<string, string>;\n\n  /**\n   * NPM devDependencies to include in every sandbox.\n   */\n  devDependencies?: Record<string, string>;\n\n  /**\n   * The file path within the sandbox that should be opened by default.\n   * @default 'src/App.jsx'\n   */\n  mainFile?: string;\n\n  /**\n   * The sandbox template to use.\n   * @default 'node'\n   */\n  template?: string;\n\n  /**\n   * The entry file content. If not provided, a default index file\n   * will be generated that imports the main file.\n   */\n  entry?: string;\n\n  /**\n   * Which sandbox provider to use.\n   * - 'codesandbox': Uses the CodeSandbox define API (default).\n   * - 'stackblitz': Uses StackBlitz via form POST. Better for\n   *   frameworks that need a full Node.js runtime (e.g. Svelte 5).\n   * @default 'codesandbox'\n   */\n  provider?: SandboxProvider;\n}\n"
  },
  {
    "path": "packages/svelte/CHANGELOG.md",
    "content": "# @dnd-kit/svelte\n\n## 0.3.2\n\n### Patch Changes\n\n- Updated dependencies [[`7260746`](https://github.com/clauderic/dnd-kit/commit/7260746b0930d51afb3098ef120bffd7d3aaea03)]:\n  - @dnd-kit/dom@0.3.2\n  - @dnd-kit/abstract@0.3.2\n  - @dnd-kit/state@0.3.2\n\n## 0.3.1\n\n### Patch Changes\n\n- Updated dependencies [[`4341114`](https://github.com/clauderic/dnd-kit/commit/43411143063349caeded4f778923473624ce25cf)]:\n  - @dnd-kit/abstract@0.3.1\n  - @dnd-kit/dom@0.3.1\n  - @dnd-kit/state@0.3.1\n\n## 0.3.0\n\n### Minor Changes\n\n- [`6a59647`](https://github.com/clauderic/dnd-kit/commit/6a59647ebba2114b2e423f282ab25bf2ea40318d) Thanks [@clauderic](https://github.com/clauderic)! - Allow `plugins`, `sensors`, and `modifiers` to accept a function that receives the defaults, making it easy to extend or configure them without replacing the entire array.\n\n  ```ts\n  // Add a plugin alongside the defaults\n  const manager = new DragDropManager({\n    plugins: (defaults) => [...defaults, MyPlugin],\n  });\n  ```\n\n  ```tsx\n  // Configure a default plugin in React\n  <DragDropProvider\n    plugins={(defaults) => [\n      ...defaults,\n      Feedback.configure({dropAnimation: null}),\n    ]}\n  />\n  ```\n\n  Previously, passing `plugins`, `sensors`, or `modifiers` would replace the defaults entirely, requiring consumers to import and spread `defaultPreset`. The function form receives the default values as an argument, so consumers can add, remove, or configure individual entries without needing to know or maintain the full default list.\n\n- [`68e44de`](https://github.com/clauderic/dnd-kit/commit/68e44deb6f824b38a58d9b4b1bd81e2efa9193f9) Thanks [@clauderic](https://github.com/clauderic)! - Add `isSortableOperation` type guard and export `SortableDraggable`/`SortableDroppable` types.\n\n  `isSortableOperation(operation)` narrows a `DragOperationSnapshot` so that `source` is typed as `SortableDraggable` and `target` as `SortableDroppable`, providing typed access to sortable-specific properties like `index`, `initialIndex`, `group`, and `initialGroup`.\n\n  Re-exported from all framework packages (`@dnd-kit/react/sortable`, `@dnd-kit/vue/sortable`, `@dnd-kit/svelte/sortable`, `@dnd-kit/solid/sortable`).\n\n- [`e630ec0`](https://github.com/clauderic/dnd-kit/commit/e630ec02f3819c1c5e3a4fcd05d0c65850ffaa0b) Thanks [@clauderic](https://github.com/clauderic)! - Initial release of @dnd-kit/svelte – a Svelte 5 adapter for dnd kit. Provides `DragDropProvider`, `DragOverlay`, `createDraggable`, `createDroppable`, and `createSortable` using Svelte 5 runes and attachments (`{@attach}`).\n\n### Patch Changes\n\n- Updated dependencies [[`6a59647`](https://github.com/clauderic/dnd-kit/commit/6a59647ebba2114b2e423f282ab25bf2ea40318d), [`5d64078`](https://github.com/clauderic/dnd-kit/commit/5d640782702b74da8be38cbd1e29271d04781854), [`863ce2b`](https://github.com/clauderic/dnd-kit/commit/863ce2b74ec0f4d630f4b7036c363bc2e3d04f24), [`863ce2b`](https://github.com/clauderic/dnd-kit/commit/863ce2b74ec0f4d630f4b7036c363bc2e3d04f24), [`e8ae539`](https://github.com/clauderic/dnd-kit/commit/e8ae539abe05a1df41d45078b108167022ac9ef7), [`41d7e27`](https://github.com/clauderic/dnd-kit/commit/41d7e27edb30cea9940cd5c46c6fcc81f7b401a6), [`68e44de`](https://github.com/clauderic/dnd-kit/commit/68e44deb6f824b38a58d9b4b1bd81e2efa9193f9)]:\n  - @dnd-kit/abstract@0.3.0\n  - @dnd-kit/dom@0.3.0\n  - @dnd-kit/state@0.3.0\n"
  },
  {
    "path": "packages/svelte/README.md",
    "content": "# @dnd-kit/svelte\n\n[![Stable release](https://img.shields.io/npm/v/@dnd-kit/svelte.svg)](https://npm.im/@dnd-kit/svelte)\n\nThe Svelte adapter for **@dnd-kit** — a lightweight, performant, and extensible drag and drop toolkit. Built on top of `@dnd-kit/dom`, it provides idiomatic Svelte 5 primitives using runes and [attachments](https://svelte.dev/docs/svelte/@attach).\n\n## Requirements\n\n- Svelte **5.29** or later\n\n## Installation\n\n```bash\nnpm install @dnd-kit/svelte\n```\n\n## Quick start\n\n```svelte\n<script>\n  import {DragDropProvider, createDraggable, createDroppable} from '@dnd-kit/svelte';\n\n  let droppedIn = $state(false);\n\n  const draggable = createDraggable({id: 'draggable'});\n  const droppable = createDroppable({id: 'droppable'});\n\n  function onDragEnd(event) {\n    if (event.canceled) return;\n    droppedIn = event.operation.target?.id === 'droppable';\n  }\n</script>\n\n<DragDropProvider {onDragEnd}>\n  {#if !droppedIn}\n    <button {@attach draggable.attach}>Drag me</button>\n  {/if}\n\n  <div {@attach droppable.attach}>\n    {#if droppedIn}\n      <button {@attach draggable.attach}>Dropped!</button>\n    {/if}\n  </div>\n</DragDropProvider>\n```\n\n## Primitives\n\n| Primitive         | Import                     | Description                        |\n| ----------------- | -------------------------- | ---------------------------------- |\n| `createDraggable` | `@dnd-kit/svelte`          | Make an element draggable          |\n| `createDroppable` | `@dnd-kit/svelte`          | Create a drop target               |\n| `createSortable`  | `@dnd-kit/svelte/sortable` | Combine drag and drop with sorting |\n\nEach primitive returns an object with reactive state (e.g. `isDragging`, `isDropTarget`) and `attach` / `attachHandle` functions for use with the `{@attach}` directive.\n\n## Components\n\n- **`<DragDropProvider>`** — Wraps your drag and drop interface, manages sensors, plugins, and events.\n- **`<DragOverlay>`** — Renders a custom overlay element during drag operations.\n\n## Documentation\n\nVisit [dndkit.com](https://dndkit.com/svelte) for full documentation, guides, and interactive examples.\n"
  },
  {
    "path": "packages/svelte/package.json",
    "content": "{\n  \"name\": \"@dnd-kit/svelte\",\n  \"version\": \"0.3.2\",\n  \"type\": \"module\",\n  \"svelte\": \"./dist/core/index.js\",\n  \"types\": \"./dist/core/index.d.ts\",\n  \"sideEffects\": false,\n  \"license\": \"MIT\",\n  \"files\": [\n    \"LICENSE\",\n    \"README.md\",\n    \"dist\"\n  ],\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/core/index.d.ts\",\n      \"svelte\": \"./dist/core/index.js\",\n      \"default\": \"./dist/core/index.js\"\n    },\n    \"./sortable\": {\n      \"types\": \"./dist/sortable/index.d.ts\",\n      \"svelte\": \"./dist/sortable/index.js\",\n      \"default\": \"./dist/sortable/index.js\"\n    },\n    \"./utilities\": {\n      \"types\": \"./dist/utilities/index.d.ts\",\n      \"svelte\": \"./dist/utilities/index.js\",\n      \"default\": \"./dist/utilities/index.js\"\n    }\n  },\n  \"scripts\": {\n    \"build\": \"svelte-package -i src -o dist\",\n    \"dev\": \"svelte-package -i src -o dist --watch\",\n    \"clean\": \"rm -rf .turbo && rm -rf node_modules && rm -rf dist\"\n  },\n  \"dependencies\": {\n    \"@dnd-kit/abstract\": \"^0.3.2\",\n    \"@dnd-kit/dom\": \"^0.3.2\",\n    \"@dnd-kit/state\": \"^0.3.2\",\n    \"tslib\": \"^2.6.2\"\n  },\n  \"peerDependencies\": {\n    \"svelte\": \"^5.29.0\"\n  },\n  \"devDependencies\": {\n    \"@sveltejs/package\": \"^2.5.7\",\n    \"svelte\": \"^5.29.0\",\n    \"typescript\": \"^5.5.2\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/clauderic/dnd-kit\"\n  }\n}\n"
  },
  {
    "path": "packages/svelte/src/core/context/DragDropProvider.svelte",
    "content": "<script lang=\"ts\">\n  import type {Snippet} from 'svelte';\n  import {onDestroy} from 'svelte';\n  import type {DragDropEventHandlers} from '@dnd-kit/abstract';\n  import {\n    DragDropManager,\n    defaultPreset,\n    resolveCustomizable,\n    type DragDropManagerInput,\n    type Draggable,\n    type Droppable,\n  } from '@dnd-kit/dom';\n\n  import {createRenderer} from './renderer.svelte.js';\n  import {setDragDropContext} from './context.js';\n\n  type Events = DragDropEventHandlers<Draggable, Droppable, DragDropManager>;\n\n  interface Props extends DragDropManagerInput {\n    manager?: DragDropManager;\n    children?: Snippet;\n    onBeforeDragStart?: Events['beforedragstart'];\n    onDragStart?: Events['dragstart'];\n    onDragMove?: Events['dragmove'];\n    onDragOver?: Events['dragover'];\n    onDragEnd?: Events['dragend'];\n    onCollision?: Events['collision'];\n  }\n\n  let {\n    manager: managerProp,\n    plugins,\n    sensors,\n    modifiers,\n    children,\n    onBeforeDragStart,\n    onDragStart,\n    onDragMove,\n    onDragOver,\n    onDragEnd,\n    onCollision,\n  }: Props = $props();\n\n  const {renderer, trackRendering} = createRenderer();\n\n  // Create manager once; plugins/sensors/modifiers are synced reactively via $effect below\n  const manager = managerProp ?? new DragDropManager({});\n\n  manager.renderer = renderer;\n\n  setDragDropContext(manager);\n\n  $effect(() => {\n    manager.plugins = resolveCustomizable(plugins, defaultPreset.plugins);\n    manager.sensors = resolveCustomizable(sensors, defaultPreset.sensors);\n    manager.modifiers = resolveCustomizable(modifiers, defaultPreset.modifiers);\n  });\n\n  $effect(() => {\n    const cleanupFns: (() => void)[] = [];\n\n    cleanupFns.push(\n      manager.monitor.addEventListener('beforedragstart', (event, mgr) =>\n        trackRendering(() => onBeforeDragStart?.(event, mgr))\n      )\n    );\n\n    cleanupFns.push(\n      manager.monitor.addEventListener('dragstart', (event, mgr) =>\n        onDragStart?.(event, mgr)\n      )\n    );\n\n    cleanupFns.push(\n      manager.monitor.addEventListener('dragover', (event, mgr) =>\n        trackRendering(() => onDragOver?.(event, mgr))\n      )\n    );\n\n    cleanupFns.push(\n      manager.monitor.addEventListener('dragmove', (event, mgr) =>\n        trackRendering(() => onDragMove?.(event, mgr))\n      )\n    );\n\n    cleanupFns.push(\n      manager.monitor.addEventListener('dragend', (event, mgr) =>\n        trackRendering(() => onDragEnd?.(event, mgr))\n      )\n    );\n\n    cleanupFns.push(\n      manager.monitor.addEventListener('collision', (event, mgr) =>\n        onCollision?.(event, mgr)\n      )\n    );\n\n    return () => cleanupFns.forEach((fn) => fn());\n  });\n\n  onDestroy(() => {\n    if (!managerProp) {\n      manager.destroy();\n    }\n  });\n</script>\n\n{@render children?.()}\n"
  },
  {
    "path": "packages/svelte/src/core/context/context.ts",
    "content": "import {getContext, setContext} from 'svelte';\nimport type {DragDropManager} from '@dnd-kit/dom';\n\nexport const DND_CONTEXT_KEY = Symbol('DragDropProvider');\n\nexport function setDragDropContext(manager: DragDropManager) {\n  setContext(DND_CONTEXT_KEY, manager);\n}\n\nexport function getDragDropContext(): DragDropManager {\n  const manager = getContext<DragDropManager | undefined>(DND_CONTEXT_KEY);\n\n  if (!manager) {\n    throw new Error(\n      'getDragDropManager was called outside of a DragDropProvider. ' +\n        'Make sure your component is wrapped in a DragDropProvider.'\n    );\n  }\n\n  return manager;\n}\n"
  },
  {
    "path": "packages/svelte/src/core/context/renderer.svelte.ts",
    "content": "import type {DragDropManager} from '@dnd-kit/dom';\nimport {tick} from 'svelte';\n\ntype Renderer = DragDropManager['renderer'];\n\nexport function createRenderer(): {\n  renderer: Renderer;\n  trackRendering: (callback: () => void) => void;\n} {\n  let transitionCount = $state(0);\n  let rendering: Promise<void> | null = null;\n  let resolver: (() => void) | null = null;\n\n  $effect(() => {\n    // Track transitionCount so this effect re-runs after DOM updates\n    void transitionCount;\n    resolver?.();\n    rendering = null;\n  });\n\n  const renderer: Renderer = {\n    get rendering() {\n      return rendering ?? Promise.resolve();\n    },\n  };\n\n  function trackRendering(callback: () => void) {\n    if (!rendering) {\n      rendering = new Promise<void>((resolve) => {\n        resolver = resolve;\n      });\n    }\n\n    callback();\n\n    tick().then(() => {\n      transitionCount++;\n    });\n  }\n\n  return {\n    renderer,\n    trackRendering,\n  };\n}\n"
  },
  {
    "path": "packages/svelte/src/core/draggable/DragOverlay.svelte",
    "content": "<script lang=\"ts\">\n  import type {Snippet} from 'svelte';\n  import type {DragDropManager, Draggable, DropAnimation} from '@dnd-kit/dom';\n  import {Feedback} from '@dnd-kit/dom';\n\n  import {createDeepSignal} from '../../utilities/createDeepSignal.svelte.js';\n  import {getDragDropManager} from '../hooks/getDragDropManager.js';\n  import {DND_CONTEXT_KEY, setDragDropContext} from '../context/context.js';\n\n  interface Props {\n    /**\n     * Whether the drag overlay is disabled.\n     */\n    disabled?: boolean;\n    /**\n     * Customize or disable the drop animation that plays when a drag operation ends.\n     *\n     * - `undefined` – use the default animation (250ms ease)\n     * - `null` – disable the drop animation entirely\n     * - `{duration, easing}` – customize the animation timing\n     * - `(context) => Promise<void> | void` – provide a fully custom animation function\n     */\n    dropAnimation?: DropAnimation | null;\n    /**\n     * Content to render inside the overlay.\n     * Receives the drag source as a snippet parameter.\n     */\n    children?: Snippet<[Draggable]>;\n  }\n\n  let {disabled = false, dropAnimation, children}: Props = $props();\n\n  const manager = getDragDropManager();\n  let overlayElement = $state<HTMLElement | null>(null);\n\n  const trackedDragOperation = createDeepSignal(() => manager.dragOperation);\n\n  // Provide a patched manager that prevents children from registering\n  const noop = () => () => {};\n\n  const patchedRegistry = new Proxy(manager.registry, {\n    get(target, property) {\n      if (property === 'register' || property === 'unregister') {\n        return noop;\n      }\n\n      return target[property as keyof typeof target];\n    },\n  });\n\n  const patchedManager = new Proxy(manager, {\n    get(target, property) {\n      if (property === 'registry') {\n        return patchedRegistry;\n      }\n\n      return target[property as keyof typeof target];\n    },\n  }) as DragDropManager;\n\n  setDragDropContext(patchedManager);\n\n  // Register overlay element and dropAnimation with the Feedback plugin\n  $effect(() => {\n    const el = overlayElement;\n    if (!el || disabled) return;\n\n    const feedback = manager.plugins.find(\n      (plugin): plugin is Feedback => plugin instanceof Feedback\n    );\n\n    if (!feedback) return;\n\n    feedback.overlay = el;\n    feedback.dropAnimation = dropAnimation;\n\n    return () => {\n      feedback.overlay = undefined;\n      feedback.dropAnimation = undefined;\n    };\n  });\n</script>\n\n<div bind:this={overlayElement} data-dnd-overlay>\n  {#if !disabled && trackedDragOperation.current.source}\n    {@render children?.(trackedDragOperation.current.source)}\n  {/if}\n</div>\n"
  },
  {
    "path": "packages/svelte/src/core/draggable/createDraggable.svelte.ts",
    "content": "import type {Data} from '@dnd-kit/abstract';\nimport type {DraggableInput} from '@dnd-kit/dom';\nimport {Draggable} from '@dnd-kit/dom';\n\nimport {createDeepSignal} from '../../utilities/createDeepSignal.svelte.js';\nimport {createInstance} from '../hooks/createInstance.svelte.js';\n\nexport type CreateDraggableInput<T extends Data = Data> = Omit<\n  DraggableInput<T>,\n  'handle' | 'element' | 'register'\n>;\n\nexport function createDraggable<T extends Data = Data>(\n  input: CreateDraggableInput<T>\n) {\n  const draggable = createInstance(\n    (manager) =>\n      new Draggable(\n        {\n          ...input,\n          register: false,\n        },\n        manager\n      )\n  );\n\n  const tracked = createDeepSignal(() => draggable);\n\n  // Sync reactive properties from input getters\n  $effect(() => {\n    draggable.id = input.id;\n    draggable.disabled = input.disabled ?? false;\n    draggable.alignment = input.alignment;\n    draggable.plugins = input.plugins;\n    draggable.modifiers = input.modifiers;\n    draggable.sensors = input.sensors;\n\n    if (input.data) {\n      draggable.data = input.data;\n    }\n  });\n\n  return {\n    get draggable() {\n      return draggable;\n    },\n    get isDragging() {\n      return tracked.current.isDragging;\n    },\n    get isDropping() {\n      return tracked.current.isDropping;\n    },\n    get isDragSource() {\n      return tracked.current.isDragSource;\n    },\n    attach(node: HTMLElement) {\n      draggable.element = node;\n\n      return () => {\n        draggable.element = undefined;\n      };\n    },\n    attachHandle(node: HTMLElement) {\n      draggable.handle = node;\n\n      return () => {\n        draggable.handle = undefined;\n      };\n    },\n  };\n}\n"
  },
  {
    "path": "packages/svelte/src/core/droppable/createDroppable.svelte.ts",
    "content": "import type {Data} from '@dnd-kit/abstract';\nimport type {DroppableInput} from '@dnd-kit/dom';\nimport {Droppable} from '@dnd-kit/dom';\n\nimport {createDeepSignal} from '../../utilities/createDeepSignal.svelte.js';\nimport {createInstance} from '../hooks/createInstance.svelte.js';\n\nexport type CreateDroppableInput<T extends Data = Data> = Omit<\n  DroppableInput<T>,\n  'element' | 'register'\n>;\n\nexport function createDroppable<T extends Data = Data>(\n  input: CreateDroppableInput<T>\n) {\n  const droppable = createInstance(\n    (manager) =>\n      new Droppable(\n        {\n          ...input,\n          register: false,\n        },\n        manager\n      )\n  );\n\n  const tracked = createDeepSignal(() => droppable);\n\n  // Sync reactive properties from input getters\n  $effect(() => {\n    droppable.id = input.id;\n    droppable.accept = input.accept;\n    droppable.type = input.type;\n    droppable.disabled = input.disabled ?? false;\n\n    if (input.collisionDetector) {\n      droppable.collisionDetector = input.collisionDetector;\n    }\n\n    if (input.data) {\n      droppable.data = input.data;\n    }\n  });\n\n  return {\n    get droppable() {\n      return droppable;\n    },\n    get isDropTarget() {\n      return tracked.current.isDropTarget;\n    },\n    attach(node: HTMLElement) {\n      droppable.element = node;\n\n      return () => {\n        droppable.element = undefined;\n      };\n    },\n  };\n}\n"
  },
  {
    "path": "packages/svelte/src/core/hooks/createDragDropMonitor.svelte.ts",
    "content": "import type {DragDropEventHandlers, Data} from '@dnd-kit/abstract';\nimport type {Draggable, Droppable, DragDropManager} from '@dnd-kit/dom';\nimport type {CleanupFunction} from '@dnd-kit/state';\n\nimport {getDragDropManager} from './getDragDropManager.js';\n\ntype EventNameOverrides = {\n  beforedragstart: 'onBeforeDragStart';\n};\n\ntype EventHandlerName<T extends string> = T extends keyof EventNameOverrides\n  ? EventNameOverrides[T]\n  : T extends `drag${infer Second}${infer Rest}`\n    ? `onDrag${Uppercase<Second>}${Rest}`\n    : `on${Capitalize<T>}`;\n\ntype Events<\n  T extends Data,\n  U extends Draggable<T>,\n  V extends Droppable<T>,\n  W extends DragDropManager<T, U, V>,\n> = DragDropEventHandlers<U, V, W>;\n\nexport type EventHandlers<\n  T extends Data = Data,\n  U extends Draggable<T> = Draggable<T>,\n  V extends Droppable<T> = Droppable<T>,\n  W extends DragDropManager<T, U, V> = DragDropManager<T, U, V>,\n> = {\n  [K in keyof Events<T, U, V, W> as EventHandlerName<K>]?: Events<\n    T,\n    U,\n    V,\n    W\n  >[K];\n};\n\nexport function createDragDropMonitor<\n  T extends Data = Data,\n  U extends Draggable<T> = Draggable<T>,\n  V extends Droppable<T> = Droppable<T>,\n  W extends DragDropManager<T, U, V> = DragDropManager<T, U, V>,\n>(handlers: EventHandlers<T, U, V, W>): void {\n  const manager = getDragDropManager();\n\n  $effect(() => {\n    if (!manager) {\n      if (process.env.NODE_ENV !== 'production') {\n        console.warn(\n          'createDragDropMonitor was called outside of a DragDropProvider. ' +\n            'Make sure your app is wrapped in a DragDropProvider component.'\n        );\n      }\n      return;\n    }\n\n    const cleanupFns = Object.entries(handlers).reduce<CleanupFunction[]>(\n      (acc, [handlerName, handler]) => {\n        if (handler) {\n          const eventName = handlerName\n            .replace(/^on/, '')\n            .toLowerCase() as keyof Events<T, U, V, W>;\n\n          const unsubscribe = manager.monitor.addEventListener(\n            eventName,\n            handler as any\n          );\n\n          acc.push(unsubscribe);\n        }\n\n        return acc;\n      },\n      []\n    );\n\n    return () => cleanupFns.forEach((cleanup) => cleanup());\n  });\n}\n"
  },
  {
    "path": "packages/svelte/src/core/hooks/createDragOperation.ts",
    "content": "import {createDeepSignal} from '../../utilities/createDeepSignal.svelte.js';\nimport {getDragDropManager} from './getDragDropManager.js';\n\nexport function createDragOperation() {\n  const manager = getDragDropManager();\n  const trackedDragOperation = createDeepSignal(() => manager.dragOperation);\n\n  return {\n    get source() {\n      return trackedDragOperation.current.source;\n    },\n    get target() {\n      return trackedDragOperation.current.target;\n    },\n    get status() {\n      return trackedDragOperation.current.status;\n    },\n  };\n}\n"
  },
  {
    "path": "packages/svelte/src/core/hooks/createInstance.svelte.ts",
    "content": "import type {DragDropManager} from '@dnd-kit/dom';\nimport type {CleanupFunction} from '@dnd-kit/state';\n\nimport {getDragDropManager} from './getDragDropManager.js';\n\nexport interface Instance<T extends DragDropManager = DragDropManager> {\n  manager: T | undefined;\n  register(): CleanupFunction | void;\n}\n\nexport function createInstance<T extends Instance>(\n  initializer: (manager: DragDropManager | undefined) => T\n): T {\n  const manager = getDragDropManager();\n  const instance = initializer(manager);\n\n  $effect(() => {\n    instance.manager = manager;\n    const cleanup = instance.register();\n\n    return () => {\n      if (typeof cleanup === 'function') cleanup();\n    };\n  });\n\n  return instance;\n}\n"
  },
  {
    "path": "packages/svelte/src/core/hooks/getDragDropManager.ts",
    "content": "import {getDragDropContext} from '../context/context.js';\n\nexport function getDragDropManager() {\n  return getDragDropContext();\n}\n"
  },
  {
    "path": "packages/svelte/src/core/index.ts",
    "content": "export {default as DragDropProvider} from './context/DragDropProvider.svelte';\n\nexport {default as DragOverlay} from './draggable/DragOverlay.svelte';\n\nexport {\n  createDraggable,\n  type CreateDraggableInput,\n} from './draggable/createDraggable.svelte.js';\n\nexport {\n  createDroppable,\n  type CreateDroppableInput,\n} from './droppable/createDroppable.svelte.js';\n\nexport {getDragDropManager} from './hooks/getDragDropManager.js';\n\nexport {\n  createDragDropMonitor,\n  type EventHandlers as DragDropEventHandlers,\n} from './hooks/createDragDropMonitor.svelte.js';\n\nexport {createDragOperation} from './hooks/createDragOperation.js';\n\nexport {createInstance} from './hooks/createInstance.svelte.js';\n\nexport {KeyboardSensor, PointerSensor} from '@dnd-kit/dom';\nexport type {DragDropManager} from '@dnd-kit/dom';\n"
  },
  {
    "path": "packages/svelte/src/sortable/createSortable.svelte.ts",
    "content": "import {type Data} from '@dnd-kit/abstract';\nimport type {SortableInput} from '@dnd-kit/dom/sortable';\nimport {defaultSortableTransition, Sortable} from '@dnd-kit/dom/sortable';\nimport {batch} from '@dnd-kit/state';\n\nimport {createDeepSignal} from '../utilities/createDeepSignal.svelte.js';\nimport {createInstance} from '../core/hooks/createInstance.svelte.js';\n\nexport type CreateSortableInput<T extends Data = Data> = Omit<\n  SortableInput<T>,\n  'handle' | 'element' | 'source' | 'target' | 'register'\n>;\n\nexport function createSortable<T extends Data = Data>(\n  input: CreateSortableInput<T>\n) {\n  const sortable = createInstance((manager) => {\n    return new Sortable(\n      {\n        ...input,\n        register: false,\n        transition: {\n          ...defaultSortableTransition,\n          ...input.transition,\n        },\n      },\n      manager\n    );\n  });\n\n  const tracked = createDeepSignal(() => sortable);\n\n  // Sync reactive properties from input getters\n  $effect(() => {\n    sortable.id = input.id;\n    sortable.disabled = input.disabled ?? false;\n    sortable.alignment = input.alignment;\n    sortable.plugins = input.plugins;\n    sortable.modifiers = input.modifiers;\n    sortable.sensors = input.sensors;\n    sortable.accept = input.accept;\n    sortable.type = input.type;\n    sortable.collisionPriority = input.collisionPriority;\n    sortable.transition = {\n      ...defaultSortableTransition,\n      ...input.transition,\n    };\n\n    if (input.data) {\n      sortable.data = input.data;\n    }\n  });\n\n  // Batch group/index updates to ensure atomic state changes\n  $effect.pre(() => {\n    const group = input.group;\n    const index = input.index;\n\n    batch(() => {\n      sortable.group = group;\n      sortable.index = index;\n    });\n  });\n\n  // Refresh shape when index changes while idle\n  $effect(() => {\n    void input.index;\n\n    if (\n      sortable.manager?.dragOperation.status.idle &&\n      sortable.transition?.idle\n    ) {\n      sortable.refreshShape();\n    }\n  });\n\n  return {\n    get sortable() {\n      return sortable;\n    },\n    get isDragging() {\n      return tracked.current.isDragging;\n    },\n    get isDropping() {\n      return tracked.current.isDropping;\n    },\n    get isDragSource() {\n      return tracked.current.isDragSource;\n    },\n    get isDropTarget() {\n      return tracked.current.isDropTarget;\n    },\n    attach(node: HTMLElement) {\n      sortable.element = node;\n\n      return () => {\n        sortable.element = undefined;\n      };\n    },\n    attachHandle(node: HTMLElement) {\n      sortable.handle = node;\n\n      return () => {\n        sortable.handle = undefined;\n      };\n    },\n    attachSource(node: HTMLElement) {\n      sortable.source = node;\n\n      return () => {\n        sortable.source = undefined;\n      };\n    },\n    attachTarget(node: HTMLElement) {\n      sortable.target = node;\n\n      return () => {\n        sortable.target = undefined;\n      };\n    },\n  };\n}\n"
  },
  {
    "path": "packages/svelte/src/sortable/index.ts",
    "content": "export {createSortable} from './createSortable.svelte.js';\nexport type {CreateSortableInput} from './createSortable.svelte.js';\n\nexport {isSortable, isSortableOperation} from '@dnd-kit/dom/sortable';\n"
  },
  {
    "path": "packages/svelte/src/utilities/createDeepSignal.svelte.ts",
    "content": "import {effect, untracked} from '@dnd-kit/state';\n\n/**\n * Bridge between @dnd-kit/state (Preact signals) and Svelte 5 reactivity.\n *\n * Uses a hybrid push-pull strategy:\n * - Pull: A Proxy tracks which properties the template actually reads\n * - Push: A single @dnd-kit/state effect watches only tracked properties\n *   and bumps a single $state dirty counter when any change\n * - Read: Getters read `dirty` (so Svelte subscribes) then return\n *   the current value from the instance\n */\nexport function createDeepSignal<T extends object | null | undefined>(\n  getTarget: () => T\n): {readonly current: T} {\n  const tracked = new Map<string | symbol, any>();\n  let dirty = $state(0);\n\n  $effect(() => {\n    const target = getTarget();\n\n    if (!target) {\n      tracked.clear();\n      return;\n    }\n\n    const dispose = effect(() => {\n      let stale = false;\n\n      for (const entry of tracked) {\n        const [key] = entry;\n        const value = untracked(() => entry[1]);\n        const latestValue = (target as any)[key];\n\n        if (value !== latestValue) {\n          stale = true;\n          tracked.set(key, latestValue);\n        }\n      }\n\n      if (stale) {\n        dirty++;\n      }\n    });\n\n    return dispose;\n  });\n\n  return {\n    get current(): T {\n      const target = getTarget();\n\n      // Reading dirty subscribes the Svelte template/effect to changes\n      void dirty;\n\n      return target\n        ? (new Proxy(target as object, {\n            get(obj, key) {\n              const value = (obj as any)[key];\n              tracked.set(key, value);\n              return value;\n            },\n          }) as T)\n        : target;\n    },\n  };\n}\n"
  },
  {
    "path": "packages/svelte/src/utilities/index.ts",
    "content": "export {createDeepSignal} from './createDeepSignal.svelte.js';\n"
  },
  {
    "path": "packages/svelte/tsconfig.json",
    "content": "{\n  \"extends\": \"../../config/typescript/svelte.json\",\n  \"include\": [\"src/**/*\"],\n  \"exclude\": [\"dist\", \"build\", \"node_modules\"]\n}\n"
  },
  {
    "path": "packages/vue/CHANGELOG.md",
    "content": "# @dnd-kit/vue\n\n## 0.3.2\n\n### Patch Changes\n\n- Updated dependencies [[`7260746`](https://github.com/clauderic/dnd-kit/commit/7260746b0930d51afb3098ef120bffd7d3aaea03)]:\n  - @dnd-kit/dom@0.3.2\n  - @dnd-kit/abstract@0.3.2\n  - @dnd-kit/state@0.3.2\n\n## 0.3.1\n\n### Patch Changes\n\n- Updated dependencies [[`4341114`](https://github.com/clauderic/dnd-kit/commit/43411143063349caeded4f778923473624ce25cf)]:\n  - @dnd-kit/abstract@0.3.1\n  - @dnd-kit/dom@0.3.1\n  - @dnd-kit/state@0.3.1\n\n## 0.3.0\n\n### Minor Changes\n\n- [`6a59647`](https://github.com/clauderic/dnd-kit/commit/6a59647ebba2114b2e423f282ab25bf2ea40318d) Thanks [@clauderic](https://github.com/clauderic)! - Allow `plugins`, `sensors`, and `modifiers` to accept a function that receives the defaults, making it easy to extend or configure them without replacing the entire array.\n\n  ```ts\n  // Add a plugin alongside the defaults\n  const manager = new DragDropManager({\n    plugins: (defaults) => [...defaults, MyPlugin],\n  });\n  ```\n\n  ```tsx\n  // Configure a default plugin in React\n  <DragDropProvider\n    plugins={(defaults) => [\n      ...defaults,\n      Feedback.configure({dropAnimation: null}),\n    ]}\n  />\n  ```\n\n  Previously, passing `plugins`, `sensors`, or `modifiers` would replace the defaults entirely, requiring consumers to import and spread `defaultPreset`. The function form receives the default values as an argument, so consumers can add, remove, or configure individual entries without needing to know or maintain the full default list.\n\n- [`68e44de`](https://github.com/clauderic/dnd-kit/commit/68e44deb6f824b38a58d9b4b1bd81e2efa9193f9) Thanks [@clauderic](https://github.com/clauderic)! - Add `isSortableOperation` type guard and export `SortableDraggable`/`SortableDroppable` types.\n\n  `isSortableOperation(operation)` narrows a `DragOperationSnapshot` so that `source` is typed as `SortableDraggable` and `target` as `SortableDroppable`, providing typed access to sortable-specific properties like `index`, `initialIndex`, `group`, and `initialGroup`.\n\n  Re-exported from all framework packages (`@dnd-kit/react/sortable`, `@dnd-kit/vue/sortable`, `@dnd-kit/svelte/sortable`, `@dnd-kit/solid/sortable`).\n\n- [#1880](https://github.com/clauderic/dnd-kit/pull/1880) [`a53b4c7`](https://github.com/clauderic/dnd-kit/commit/a53b4c71f320c1a1447e55c147af4912c1a4fcf5) Thanks [@clauderic](https://github.com/clauderic)! - Add @dnd-kit/vue adapter package for Vue 3.5+\n\n- [`570c2a9`](https://github.com/clauderic/dnd-kit/commit/570c2a972e5cc48c54c72b276c53604c9a277b50) Thanks [@clauderic](https://github.com/clauderic)! - Add `DragOverlay` component to `@dnd-kit/vue`.\n\n### Patch Changes\n\n- Updated dependencies [[`6a59647`](https://github.com/clauderic/dnd-kit/commit/6a59647ebba2114b2e423f282ab25bf2ea40318d), [`5d64078`](https://github.com/clauderic/dnd-kit/commit/5d640782702b74da8be38cbd1e29271d04781854), [`863ce2b`](https://github.com/clauderic/dnd-kit/commit/863ce2b74ec0f4d630f4b7036c363bc2e3d04f24), [`863ce2b`](https://github.com/clauderic/dnd-kit/commit/863ce2b74ec0f4d630f4b7036c363bc2e3d04f24), [`e8ae539`](https://github.com/clauderic/dnd-kit/commit/e8ae539abe05a1df41d45078b108167022ac9ef7), [`41d7e27`](https://github.com/clauderic/dnd-kit/commit/41d7e27edb30cea9940cd5c46c6fcc81f7b401a6), [`68e44de`](https://github.com/clauderic/dnd-kit/commit/68e44deb6f824b38a58d9b4b1bd81e2efa9193f9)]:\n  - @dnd-kit/abstract@0.3.0\n  - @dnd-kit/dom@0.3.0\n  - @dnd-kit/state@0.3.0\n"
  },
  {
    "path": "packages/vue/README.md",
    "content": "# @dnd-kit/vue\n\n[![Stable release](https://img.shields.io/npm/v/@dnd-kit/vue.svg)](https://npm.im/@dnd-kit/vue)\n\nThe Vue adapter for **@dnd-kit** — a lightweight, performant, and extensible drag and drop toolkit. Built on top of `@dnd-kit/dom`.\n\n## Installation\n\n```bash\nnpm install @dnd-kit/vue\n```\n\n## Quick start\n\n```vue\n<script setup>\nimport {ref} from 'vue';\nimport {DragDropProvider, useDraggable, useDroppable} from '@dnd-kit/vue';\n\nconst draggable = useDraggable({id: 'draggable'});\nconst droppable = useDroppable({id: 'droppable'});\nconst parent = ref(null);\n\nfunction onDragEnd(event) {\n  if (event.canceled) return;\n  parent.value = event.operation.target?.id ?? null;\n}\n</script>\n\n<template>\n  <DragDropProvider @dragEnd=\"onDragEnd\">\n    <button v-if=\"!parent\" :ref=\"draggable.ref\">Drag me</button>\n    <div :ref=\"droppable.ref\">\n      <button v-if=\"parent\" :ref=\"draggable.ref\">Dropped!</button>\n    </div>\n  </DragDropProvider>\n</template>\n```\n\n## Composables\n\n| Composable     | Import                  | Description                        |\n| -------------- | ----------------------- | ---------------------------------- |\n| `useDraggable` | `@dnd-kit/vue`          | Make an element draggable          |\n| `useDroppable` | `@dnd-kit/vue`          | Create a drop target               |\n| `useSortable`  | `@dnd-kit/vue/sortable` | Combine drag and drop with sorting |\n\n## Components\n\n- **`<DragDropProvider>`** — Wraps your drag and drop interface, manages sensors, plugins, and events.\n- **`<DragOverlay>`** — Renders a custom overlay element during drag operations.\n\n## Documentation\n\nVisit [dndkit.com](https://dndkit.com/vue) for full documentation, guides, and interactive examples.\n"
  },
  {
    "path": "packages/vue/package.json",
    "content": "{\n  \"name\": \"@dnd-kit/vue\",\n  \"version\": \"0.3.2\",\n  \"main\": \"./index.cjs\",\n  \"module\": \"./index.js\",\n  \"type\": \"module\",\n  \"types\": \"./index.d.ts\",\n  \"sideEffects\": false,\n  \"license\": \"MIT\",\n  \"files\": [\n    \"LICENSE\",\n    \"README.md\",\n    \"index.js\",\n    \"index.d.ts\",\n    \"index.cjs\",\n    \"composables.js\",\n    \"composables.d.ts\",\n    \"composables.cjs\",\n    \"sortable.js\",\n    \"sortable.d.ts\",\n    \"sortable.cjs\",\n    \"utilities.js\",\n    \"utilities.d.ts\",\n    \"utilities.cjs\"\n  ],\n  \"exports\": {\n    \".\": {\n      \"types\": \"./index.d.ts\",\n      \"import\": \"./index.js\",\n      \"require\": \"./index.cjs\"\n    },\n    \"./composables\": {\n      \"types\": \"./composables.d.ts\",\n      \"import\": \"./composables.js\",\n      \"require\": \"./composables.cjs\"\n    },\n    \"./sortable\": {\n      \"types\": \"./sortable.d.ts\",\n      \"import\": \"./sortable.js\",\n      \"require\": \"./sortable.cjs\"\n    },\n    \"./utilities\": {\n      \"types\": \"./utilities.d.ts\",\n      \"import\": \"./utilities.js\",\n      \"require\": \"./utilities.cjs\"\n    }\n  },\n  \"scripts\": {\n    \"build\": \"bun build:utilities && bun build:composables && bun build:core && bun build:sortable\",\n    \"build:core\": \"tsup src/core/index.ts\",\n    \"build:composables\": \"tsup --entry.composables src/composables/index.ts\",\n    \"build:sortable\": \"tsup --entry.sortable src/sortable/index.ts\",\n    \"build:utilities\": \"tsup --entry.utilities src/utilities/index.ts\",\n    \"dev\": \"bun build:utilities --watch & bun build:composables --watch & bun build:core --watch & bun build:sortable --watch\",\n    \"clean\": \"rm -rf .turbo && rm -rf node_modules && rm -rf dist\"\n  },\n  \"dependencies\": {\n    \"@dnd-kit/abstract\": \"^0.3.2\",\n    \"@dnd-kit/dom\": \"^0.3.2\",\n    \"@dnd-kit/state\": \"^0.3.2\",\n    \"tslib\": \"^2.6.2\"\n  },\n  \"peerDependencies\": {\n    \"vue\": \"^3.5.0\"\n  },\n  \"devDependencies\": {\n    \"tsup\": \"8.3.0\",\n    \"typescript\": \"^5.5.2\",\n    \"vue\": \"^3.5.0\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/clauderic/dnd-kit\"\n  }\n}\n"
  },
  {
    "path": "packages/vue/src/composables/index.ts",
    "content": "export {useDeepSignal} from './useDeepSignal.ts';\n"
  },
  {
    "path": "packages/vue/src/composables/useDeepSignal.ts",
    "content": "import {effect, untracked} from '@dnd-kit/state';\nimport type {ComputedRef, MaybeRefOrGetter} from 'vue';\nimport {computed, onWatcherCleanup, ref, toValue, watchEffect} from 'vue';\n\n/** Trigger a recompute when reading signal properties of an object. */\nexport function useDeepSignal<T extends object | null | undefined>(\n  target: MaybeRefOrGetter<T>\n): ComputedRef<T> {\n  const tracked = new Map<string | symbol, any>();\n  const dirty = ref(0);\n\n  watchEffect(() => {\n    const _target = toValue(target);\n    if (!_target) {\n      tracked.clear();\n      return;\n    }\n\n    onWatcherCleanup(\n      effect(() => {\n        let stale = false;\n\n        for (const entry of tracked) {\n          const [key] = entry;\n          const value = untracked(() => entry[1]);\n          const latestValue = (_target as any)[key];\n\n          if (value !== latestValue) {\n            stale = true;\n            tracked.set(key, latestValue);\n          }\n        }\n\n        if (stale) {\n          dirty.value++;\n        }\n      })\n    );\n  }, {flush: 'post'});\n\n  return computed(() => {\n    const _target = toValue(target);\n\n    void dirty.value;\n\n    return _target\n      ? new Proxy(_target, {\n          get(target, key) {\n            const value = (target as any)[key];\n\n            tracked.set(key, value);\n\n            return value;\n          },\n        })\n      : _target;\n  });\n}\n"
  },
  {
    "path": "packages/vue/src/core/context/DragDropProvider.ts",
    "content": "import type {DragDropEventHandlers} from '@dnd-kit/abstract';\nimport {\n  defaultPreset,\n  resolveCustomizable,\n  type DragDropManagerInput,\n  type Draggable,\n  type Droppable,\n} from '@dnd-kit/dom';\nimport {DragDropManager} from '@dnd-kit/dom';\nimport {\n  computed,\n  defineComponent,\n  onUnmounted,\n  onWatcherCleanup,\n  shallowRef,\n  watch,\n  watchEffect,\n} from 'vue';\nimport {useRenderer} from './renderer.ts';\nimport {provideDragDropContext} from './context.ts';\n\ntype NamedTuple<T extends (...args: any) => any> = T extends (\n  ...args: infer A\n) => any\n  ? A\n  : never;\n\ntype ToVueEmits<T extends Record<string, (...args: any) => any>> = {\n  [K in keyof T]: NamedTuple<T[K]>;\n};\n\ntype Events = ToVueEmits<DragDropEventHandlers<Draggable, Droppable, DragDropManager>>;\n\nexport interface DragDropProviderProps extends DragDropManagerInput {\n  manager?: DragDropManager;\n}\n\nexport type DragDropProviderEmits = {\n  beforeDragStart: Events['beforedragstart'];\n  collision: Events['collision'];\n  dragStart: Events['dragstart'];\n  dragMove: Events['dragmove'];\n  dragOver: Events['dragover'];\n  dragEnd: Events['dragend'];\n};\n\nexport default /* #__PURE__ */ defineComponent<DragDropProviderProps>({\n  props: [\n    'manager',\n    'plugins',\n    'sensors',\n    'modifiers',\n  ] as unknown as undefined,\n  emits: [\n    'beforeDragStart',\n    'collision',\n    'dragStart',\n    'dragMove',\n    'dragOver',\n    'dragEnd',\n  ] as unknown as DragDropProviderEmits,\n  setup(props, {emit, slots}) {\n    const {renderer, trackRendering} = useRenderer();\n    const manager = shallowRef(props.manager ?? new DragDropManager(props));\n\n    watch(\n      [() => props.manager],\n      () => {\n        const _manager = props.manager ?? new DragDropManager(props);\n        const cleanupFns: (() => void)[] = [];\n\n        _manager.renderer = renderer;\n\n        cleanupFns.push(\n          _manager.monitor.addEventListener(\n            'beforedragstart',\n            (event, manager) =>\n              trackRendering(() => emit('beforeDragStart', event, manager))\n          )\n        );\n\n        cleanupFns.push(\n          _manager.monitor.addEventListener('dragstart', (event, manager) =>\n            emit('dragStart', event, manager)\n          )\n        );\n\n        cleanupFns.push(\n          _manager.monitor.addEventListener('dragover', (event, manager) =>\n            trackRendering(() => emit('dragOver', event, manager))\n          )\n        );\n\n        cleanupFns.push(\n          _manager.monitor.addEventListener('dragmove', (event, manager) =>\n            trackRendering(() => emit('dragMove', event, manager))\n          )\n        );\n\n        cleanupFns.push(\n          _manager.monitor.addEventListener('dragend', (event, manager) =>\n            trackRendering(() => emit('dragEnd', event, manager))\n          )\n        );\n\n        cleanupFns.push(\n          _manager.monitor.addEventListener('collision', (event, manager) =>\n            emit('collision', event, manager)\n          )\n        );\n\n        manager.value = _manager;\n\n        onWatcherCleanup(() => cleanupFns.forEach((fn) => fn()));\n      },\n      {\n        immediate: true,\n      }\n    );\n\n    watchEffect(() => {\n      manager.value.plugins = resolveCustomizable(props.plugins, defaultPreset.plugins);\n      manager.value.sensors = resolveCustomizable(props.sensors, defaultPreset.sensors);\n      manager.value.modifiers = resolveCustomizable(props.modifiers, defaultPreset.modifiers);\n    });\n\n    provideDragDropContext(computed(() => manager.value));\n\n    onUnmounted(() => {\n      if (!props.manager) {\n        manager.value.destroy();\n      }\n    });\n\n    return () => slots.default?.();\n  },\n});\n"
  },
  {
    "path": "packages/vue/src/core/context/context.ts",
    "content": "import type {DragDropManager} from '@dnd-kit/dom';\nimport type {ComputedRef} from 'vue';\nimport {createContext} from '../../utilities/index.ts';\n\nexport const [injectDragDropContext, provideDragDropContext] =\n  createContext<ComputedRef<DragDropManager>>('DragDropProvider');\n"
  },
  {
    "path": "packages/vue/src/core/context/renderer.ts",
    "content": "import type {DragDropManager} from '@dnd-kit/dom';\nimport {nextTick, ref, watch} from 'vue';\n\ntype Renderer = DragDropManager['renderer'];\n\nexport function useRenderer(): {\n  renderer: Renderer;\n  trackRendering: (callback: () => void) => void;\n} {\n  const transitionCount = ref(0);\n  const rendering = ref<Promise<void> | null>(null);\n  let resolver: (() => void) | null = null;\n\n  watch(\n    transitionCount,\n    () => {\n      resolver?.();\n      rendering.value = null;\n    },\n    {\n      flush: 'post',\n    }\n  );\n\n  const renderer: Renderer = {\n    get rendering() {\n      return rendering.value ?? Promise.resolve();\n    },\n  };\n\n  function trackRendering(callback: () => void) {\n    if (!rendering.value) {\n      rendering.value = new Promise<void>((resolve) => {\n        resolver = resolve;\n      });\n    }\n\n    callback();\n\n    nextTick(() => {\n      transitionCount.value++;\n    });\n  }\n\n  return {\n    renderer,\n    trackRendering,\n  };\n}\n"
  },
  {
    "path": "packages/vue/src/core/draggable/DragOverlay.ts",
    "content": "import {Feedback} from '@dnd-kit/dom';\nimport type {DragDropManager, DropAnimation} from '@dnd-kit/dom';\nimport {\n  computed,\n  defineComponent,\n  h,\n  onUnmounted,\n  ref,\n  watchEffect,\n  type PropType,\n} from 'vue';\n\nimport {useDeepSignal} from '../../composables/useDeepSignal.ts';\nimport {provideDragDropContext} from '../context/context.ts';\nimport {useDragDropManager} from '../hooks/useDragDropManager.ts';\n\nexport interface DragOverlayProps {\n  /**\n   * The HTML tag to render as the overlay wrapper element.\n   * @default 'div'\n   */\n  tag?: string;\n  /**\n   * Whether the drag overlay is disabled.\n   */\n  disabled?: boolean;\n  /**\n   * Customize or disable the drop animation that plays when a drag operation ends.\n   *\n   * - `undefined` – use the default animation (250ms ease)\n   * - `null` – disable the drop animation entirely\n   * - `{duration, easing}` – customize the animation timing\n   * - `(context) => Promise<void> | void` – provide a fully custom animation function\n   */\n  dropAnimation?: DropAnimation | null;\n}\n\nconst noop = () => () => {};\n\nexport default /* #__PURE__ */ defineComponent({\n  name: 'DragOverlay',\n  props: {\n    tag: {\n      type: String,\n      default: 'div',\n    },\n    disabled: {\n      type: Boolean,\n      default: false,\n    },\n    dropAnimation: {\n      type: [Object, Function] as PropType<DropAnimation | null>,\n      default: undefined,\n    },\n  },\n  setup(props, {slots}) {\n    const manager = useDragDropManager();\n    const overlayRef = ref<HTMLElement | null>(null);\n\n    const trackedDragOperation = useDeepSignal(\n      computed(() => manager.value.dragOperation)\n    );\n\n    const source = computed(() => trackedDragOperation.value.source ?? null);\n\n    // Register overlay element and dropAnimation with the Feedback plugin\n    watchEffect(() => {\n      const el = overlayRef.value;\n      const mgr = manager.value;\n\n      if (!el || !mgr || props.disabled) return;\n\n      const feedback = mgr.plugins.find(\n        (plugin): plugin is Feedback => plugin instanceof Feedback\n      );\n\n      if (!feedback) return;\n\n      feedback.overlay = el;\n      feedback.dropAnimation = props.dropAnimation;\n\n      onUnmounted(() => {\n        feedback.overlay = undefined;\n        feedback.dropAnimation = undefined;\n      });\n    });\n\n    // Provide a patched manager that prevents children from registering\n    const patchedManager = computed(() => {\n      const mgr = manager.value;\n\n      if (!mgr) return mgr;\n\n      const patchedRegistry = new Proxy(mgr.registry, {\n        get(target, property) {\n          if (property === 'register' || property === 'unregister') {\n            return noop;\n          }\n\n          return target[property as keyof typeof target];\n        },\n      });\n\n      return new Proxy(mgr, {\n        get(target, property) {\n          if (property === 'registry') {\n            return patchedRegistry;\n          }\n\n          return target[property as keyof typeof target];\n        },\n      }) as DragDropManager;\n    });\n\n    provideDragDropContext(patchedManager);\n\n    return () => {\n      const hasSource = source.value != null && !props.disabled;\n\n      return h(\n        props.tag,\n        {\n          ref: overlayRef,\n          'data-dnd-overlay': true,\n        },\n        hasSource ? slots.default?.({source: source.value}) : undefined\n      );\n    };\n  },\n});\n"
  },
  {
    "path": "packages/vue/src/core/draggable/useDraggable.ts",
    "content": "import type {Data} from '@dnd-kit/abstract';\nimport type {DraggableInput} from '@dnd-kit/dom';\nimport {Draggable} from '@dnd-kit/dom';\nimport {useDeepSignal} from '../../composables/useDeepSignal.ts';\nimport {toValueDeep, unrefElement} from '../../utilities/index.ts';\nimport type {MaybeRefOrGetter} from 'vue';\nimport {computed, shallowReadonly, toValue, watchEffect} from 'vue';\nimport type {MaybeElement, MaybeRefsOrGetters} from '../../types.ts';\nimport {useInstance} from '../hooks/useInstance.ts';\n\nexport interface UseDraggableInput<T extends Data = Data>\n  extends MaybeRefsOrGetters<Omit<DraggableInput<T>, 'handle' | 'element'>> {\n  handle?: MaybeRefOrGetter<MaybeElement>;\n  element?: MaybeRefOrGetter<MaybeElement>;\n}\n\nexport function useDraggable<T extends Data = Data>(\n  input: UseDraggableInput<T>\n) {\n  const draggable = useInstance(\n    (manager) =>\n      new Draggable(\n        {\n          ...toValueDeep(input),\n          register: false,\n          element: unrefElement(input.element) ?? undefined,\n          handle: unrefElement(input.handle) ?? undefined,\n        },\n        manager\n      )\n  );\n  const trackedDraggable = useDeepSignal(draggable);\n\n  watchEffect(() => {\n    draggable.value.element = unrefElement(input.element) ?? undefined;\n    draggable.value.handle = unrefElement(input.handle) ?? undefined;\n\n    draggable.value.id = toValue(input.id);\n    draggable.value.disabled = toValue(input.disabled) ?? false;\n    draggable.value.alignment = toValue(input.alignment);\n    draggable.value.plugins = toValue(input.plugins);\n    draggable.value.modifiers = toValue(input.modifiers);\n    draggable.value.sensors = toValue(input.sensors);\n\n    if (toValue(input.data)) {\n      draggable.value.data = toValue(input.data)!;\n    }\n  });\n\n  return {\n    draggable: shallowReadonly(draggable),\n    isDragging: computed(() => trackedDraggable.value.isDragging),\n    isDropping: computed(() => trackedDraggable.value.isDropping),\n    isDragSource: computed(() => trackedDraggable.value.isDragSource),\n  };\n}\n"
  },
  {
    "path": "packages/vue/src/core/droppable/useDroppable.ts",
    "content": "import type {Data} from '@dnd-kit/abstract';\nimport type {DroppableInput} from '@dnd-kit/dom';\nimport {Droppable} from '@dnd-kit/dom';\nimport {useDeepSignal} from '../../composables/useDeepSignal.ts';\nimport {toValueDeep, unrefElement} from '../../utilities/index.ts';\nimport type {MaybeRefOrGetter} from 'vue';\nimport {computed, shallowReadonly, toValue, watchEffect} from 'vue';\nimport type {MaybeElement, MaybeRefsOrGetters} from '../../types.ts';\nimport {useInstance} from '../hooks/useInstance.ts';\n\nexport interface UseDroppableInput<T extends Data = Data>\n  extends MaybeRefsOrGetters<Omit<DroppableInput<T>, 'element'>> {\n  element?: MaybeRefOrGetter<MaybeElement>;\n}\n\nexport function useDroppable<T extends Data = Data>(\n  input: UseDroppableInput<T>\n) {\n  const droppable = useInstance(\n    (manager) =>\n      new Droppable(\n        {\n          ...toValueDeep(input),\n          register: false,\n          element: unrefElement(input.element) ?? undefined,\n        },\n        manager\n      )\n  );\n  const trackedDroppable = useDeepSignal(droppable);\n\n  watchEffect(() => {\n    droppable.value.element = unrefElement(input.element) ?? undefined;\n\n    droppable.value.id = toValue(input.id);\n    droppable.value.accept = toValue(input.accept);\n    droppable.value.type = toValue(input.type);\n    droppable.value.disabled = toValue(input.disabled) ?? false;\n\n    if (toValue(input.collisionDetector)) {\n      droppable.value.collisionDetector = toValue(input.collisionDetector)!;\n    }\n\n    if (toValue(input.data)) {\n      droppable.value.data = toValue(input.data)!;\n    }\n  });\n\n  return {\n    droppable: shallowReadonly(droppable),\n    isDropTarget: computed(() => trackedDroppable.value.isDropTarget),\n  };\n}\n"
  },
  {
    "path": "packages/vue/src/core/hooks/useDragDropManager.ts",
    "content": "import {injectDragDropContext} from '../context/context.ts';\n\nexport function useDragDropManager() {\n  return injectDragDropContext();\n}\n"
  },
  {
    "path": "packages/vue/src/core/hooks/useDragDropMonitor.ts",
    "content": "import type {DragDropEventHandlers, Data} from '@dnd-kit/abstract';\nimport type {Draggable, Droppable, DragDropManager} from '@dnd-kit/dom';\nimport {onWatcherCleanup, watchEffect} from 'vue';\nimport type {CleanupFunction} from '@dnd-kit/state';\n\nimport {useDragDropManager} from './useDragDropManager.ts';\n\ntype EventNameOverrides = {\n  beforedragstart: 'onBeforeDragStart';\n};\n\ntype EventHandlerName<T extends string> = T extends keyof EventNameOverrides\n  ? EventNameOverrides[T]\n  : T extends `drag${infer Second}${infer Rest}`\n    ? `onDrag${Uppercase<Second>}${Rest}`\n    : `on${Capitalize<T>}`;\n\ntype Events<\n  T extends Data,\n  U extends Draggable<T>,\n  V extends Droppable<T>,\n  W extends DragDropManager<T, U, V>,\n> = DragDropEventHandlers<U, V, W>;\n\nexport type EventHandlers<\n  T extends Data = Data,\n  U extends Draggable<T> = Draggable<T>,\n  V extends Droppable<T> = Droppable<T>,\n  W extends DragDropManager<T, U, V> = DragDropManager<T, U, V>,\n> = {\n  [K in keyof Events<T, U, V, W> as EventHandlerName<K>]?: Events<T, U, V, W>[K];\n};\n\nexport function useDragDropMonitor<\n  T extends Data = Data,\n  U extends Draggable<T> = Draggable<T>,\n  V extends Droppable<T> = Droppable<T>,\n  W extends DragDropManager<T, U, V> = DragDropManager<T, U, V>,\n>(handlers: EventHandlers<T, U, V, W>): void {\n  const manager = useDragDropManager();\n\n  watchEffect(() => {\n    if (!manager) {\n      if (process.env.NODE_ENV !== 'production') {\n        console.warn(\n          'useDragDropMonitor composable was called outside of a DragDropProvider. ' +\n            'Make sure your app is wrapped in a DragDropProvider component.'\n        );\n      }\n      return;\n    }\n\n    const cleanupFns = Object.entries(handlers).reduce<CleanupFunction[]>(\n      (acc, [handlerName, handler]) => {\n        if (handler) {\n          const eventName = handlerName\n            .replace(/^on/, '')\n            .toLowerCase() as keyof Events<T, U, V, W>;\n\n          const unsubscribe = manager.value.monitor.addEventListener(\n            eventName,\n            handler as any\n          );\n\n          acc.push(unsubscribe);\n        }\n\n        return acc;\n      },\n      []\n    );\n\n    onWatcherCleanup(() => cleanupFns.forEach((cleanup) => cleanup()));\n  });\n}\n"
  },
  {
    "path": "packages/vue/src/core/hooks/useDragOperation.ts",
    "content": "import {computed} from 'vue';\n\nimport {useDeepSignal} from '../../composables/useDeepSignal.ts';\nimport {useDragDropManager} from './useDragDropManager.ts';\n\nexport function useDragOperation() {\n  const manager = useDragDropManager();\n  const trackedDragOperation = useDeepSignal(\n    computed(() => manager.value.dragOperation)\n  );\n\n  return {\n    get source() {\n      return trackedDragOperation.value.source;\n    },\n    get target() {\n      return trackedDragOperation.value.target;\n    },\n    get status() {\n      return trackedDragOperation.value.status;\n    },\n  };\n}\n"
  },
  {
    "path": "packages/vue/src/core/hooks/useInstance.ts",
    "content": "import type {DragDropManager} from '@dnd-kit/dom';\nimport type {CleanupFunction} from '@dnd-kit/state';\nimport {computed, onWatcherCleanup, shallowRef, watchEffect} from 'vue';\n\nimport {useDragDropManager} from './useDragDropManager.ts';\n\nexport interface Instance<T extends DragDropManager = DragDropManager> {\n  manager: T | undefined;\n  register(): CleanupFunction | void;\n}\n\nexport function useInstance<T extends Instance>(\n  initializer: (manager: DragDropManager | undefined) => T\n) {\n  const manager = useDragDropManager();\n  const instance = shallowRef(initializer(manager.value));\n\n  watchEffect(() => {\n    instance.value.manager = manager.value;\n    onWatcherCleanup(instance.value.register());\n  });\n\n  return computed(() => instance.value);\n}\n"
  },
  {
    "path": "packages/vue/src/core/index.ts",
    "content": "export {default as DragDropProvider} from './context/DragDropProvider.ts';\nexport type {\n  DragDropProviderProps,\n  DragDropProviderEmits,\n} from './context/DragDropProvider.ts';\n\nexport {default as DragOverlay} from './draggable/DragOverlay.ts';\nexport type {DragOverlayProps} from './draggable/DragOverlay.ts';\n\nexport {\n  useDraggable,\n  type UseDraggableInput,\n} from './draggable/useDraggable.ts';\n\nexport {\n  useDroppable,\n  type UseDroppableInput,\n} from './droppable/useDroppable.ts';\n\nexport {useDragDropManager} from './hooks/useDragDropManager.ts';\n\nexport {\n  useDragDropMonitor,\n  type EventHandlers as DragDropEventHandlers,\n} from './hooks/useDragDropMonitor.ts';\n\nexport {useDragOperation} from './hooks/useDragOperation.ts';\n\nexport {useInstance} from './hooks/useInstance.ts';\n\nexport {KeyboardSensor, PointerSensor} from '@dnd-kit/dom';\nexport type {DragDropManager} from '@dnd-kit/dom';\n"
  },
  {
    "path": "packages/vue/src/sortable/index.ts",
    "content": "export {useSortable} from './useSortable.ts';\nexport type {UseSortableInput} from './useSortable.ts';\n\nexport {isSortable, isSortableOperation} from '@dnd-kit/dom/sortable';\n"
  },
  {
    "path": "packages/vue/src/sortable/useSortable.ts",
    "content": "import {type Data} from '@dnd-kit/abstract';\nimport type {SortableInput} from '@dnd-kit/dom/sortable';\nimport {defaultSortableTransition, Sortable} from '@dnd-kit/dom/sortable';\nimport {batch} from '@dnd-kit/state';\nimport {useDeepSignal} from '@dnd-kit/vue/composables';\nimport {toValueDeep, unrefElement} from '@dnd-kit/vue/utilities';\nimport {useInstance} from '@dnd-kit/vue';\nimport type {MaybeRefOrGetter} from 'vue';\nimport {\n  computed,\n  shallowReadonly,\n  toValue,\n  watch,\n  watchEffect,\n} from 'vue';\nimport type {MaybeElement, MaybeRefsOrGetters} from '../types.ts';\n\nexport interface UseSortableInput<T extends Data = Data>\n  extends MaybeRefsOrGetters<\n    Omit<SortableInput<T>, 'handle' | 'element' | 'source' | 'target'>\n  > {\n  handle?: MaybeRefOrGetter<MaybeElement>;\n  element?: MaybeRefOrGetter<MaybeElement>;\n  source?: MaybeRefOrGetter<MaybeElement>;\n  target?: MaybeRefOrGetter<MaybeElement>;\n}\n\nexport function useSortable<T extends Data = Data>(input: UseSortableInput<T>) {\n  const transition = computed(() => ({\n    ...defaultSortableTransition,\n    ...toValue(input.transition),\n  }));\n\n  const sortable = useInstance((manager) => {\n    const _input = toValueDeep(input);\n\n    return new Sortable(\n      {\n        ..._input,\n        register: false,\n        transition: transition.value,\n        element: unrefElement(input.element),\n        handle: unrefElement(input.handle),\n        target: unrefElement(input.target),\n      },\n      manager\n    );\n  });\n  const trackedSortable = useDeepSignal(sortable);\n\n  watchEffect(() => {\n    sortable.value.element = unrefElement(input.element);\n    sortable.value.handle = unrefElement(input.handle);\n\n    if (unrefElement(input.source)) {\n      sortable.value.source = unrefElement(input.source);\n    }\n    if (unrefElement(input.target)) {\n      sortable.value.target = unrefElement(input.target);\n    }\n\n    sortable.value.id = toValue(input.id);\n    sortable.value.disabled = toValue(input.disabled) ?? false;\n    sortable.value.alignment = toValue(input.alignment);\n    sortable.value.plugins = toValue(input.plugins);\n    sortable.value.modifiers = toValue(input.modifiers);\n    sortable.value.sensors = toValue(input.sensors);\n    sortable.value.accept = toValue(input.accept);\n    sortable.value.type = toValue(input.type);\n    sortable.value.collisionPriority = toValue(input.collisionPriority);\n    sortable.value.transition = transition.value;\n\n    if (toValue(input.data)) {\n      sortable.value.data = toValue(input.data)!;\n    }\n  });\n\n  watch(\n    [() => toValue(input.group), () => toValue(input.index)],\n    () => {\n      batch(() => {\n        sortable.value.group = toValue(input.group);\n        sortable.value.index = toValue(input.index);\n      });\n    },\n    {flush: 'sync'}\n  );\n\n  watch(\n    () => toValue(input.index),\n    () => {\n      if (\n        sortable.value.manager?.dragOperation.status.idle &&\n        sortable.value.transition?.idle\n      ) {\n        sortable.value.refreshShape();\n      }\n    }\n  );\n\n  return {\n    sortable: shallowReadonly(sortable),\n    isDragging: computed(() => trackedSortable.value.isDragging),\n    isDropping: computed(() => trackedSortable.value.isDropping),\n    isDragSource: computed(() => trackedSortable.value.isDragSource),\n    isDropTarget: computed(() => trackedSortable.value.isDropTarget),\n  };\n}\n"
  },
  {
    "path": "packages/vue/src/types.ts",
    "content": "import type {ComponentPublicInstance, MaybeRefOrGetter} from 'vue';\n\nexport type MaybeRefsOrGetters<T> = {\n  [K in keyof T]: MaybeRefOrGetter<T[K]>;\n};\n\nexport type MaybeElement =\n  | HTMLElement\n  | ComponentPublicInstance\n  | undefined\n  | null;\n"
  },
  {
    "path": "packages/vue/src/utilities/context.ts",
    "content": "import type {InjectionKey} from 'vue';\nimport {inject, provide} from 'vue';\n\nexport function createContext<TContextValue>(componentName: string) {\n  const injectionKey: InjectionKey<TContextValue | null> = Symbol(\n    `${componentName}Context`\n  );\n\n  return [injectContext, provideContext] as const;\n\n  function injectContext<\n    T extends TContextValue | null | undefined = TContextValue,\n  >(fallback?: T): T extends null ? TContextValue | null : TContextValue {\n    const context = inject(injectionKey, fallback);\n    if (context) return context;\n\n    if (context === null) return context as any;\n\n    throw new Error(\n      `Injection \\`${injectionKey.toString()}\\` not found. Component must be used within \\`${componentName}\\``\n    );\n  }\n  function provideContext(contextValue: TContextValue) {\n    provide(injectionKey, contextValue);\n    return contextValue;\n  }\n}\n"
  },
  {
    "path": "packages/vue/src/utilities/element.ts",
    "content": "import type {ComponentPublicInstance, MaybeRefOrGetter} from 'vue';\nimport {toValue} from 'vue';\nimport type {MaybeElement} from '../types.ts';\n\nexport type UnRefElementReturn<T extends MaybeElement = MaybeElement> =\n  T extends ComponentPublicInstance\n    ? Exclude<MaybeElement, ComponentPublicInstance | null>\n    : Exclude<T, null> | undefined;\n\nexport function unrefElement<T extends MaybeElement>(\n  elRef: MaybeRefOrGetter<T>\n): UnRefElementReturn<T> {\n  const plain = toValue(elRef);\n  return (plain as ComponentPublicInstance)?.$el ?? plain ?? undefined;\n}\n"
  },
  {
    "path": "packages/vue/src/utilities/index.ts",
    "content": "export {createContext} from './context.ts';\nexport {unrefElement, type UnRefElementReturn} from './element.ts';\nexport {toValueDeep} from './ref.ts';\n"
  },
  {
    "path": "packages/vue/src/utilities/ref.ts",
    "content": "import {toValue} from 'vue';\nimport type {MaybeRefsOrGetters} from '../types.ts';\n\nexport function toValueDeep<T>(input: MaybeRefsOrGetters<T>): T {\n  return Object.fromEntries(\n    Object.entries(input).map(([key, value]) => [key, toValue(value)])\n  ) as T;\n}\n"
  },
  {
    "path": "packages/vue/tsconfig.json",
    "content": "{\n  \"extends\": \"../../config/typescript/vue.json\",\n  \"include\": [\"src/**/*\"],\n  \"exclude\": [\"dist\", \"build\", \"node_modules\"]\n}\n"
  },
  {
    "path": "packages/vue/tsup.config.ts",
    "content": "import {defineConfig} from 'tsup';\n\nexport default defineConfig((options) => ({\n  dts: true,\n  outDir: './',\n  external: [\n    '@dnd-kit/abstract',\n    '@dnd-kit/vue',\n    '@dnd-kit/dom',\n    '@dnd-kit/state',\n  ],\n  format: ['esm', 'cjs'],\n  sourcemap: true,\n  treeshake: !options.watch,\n}));\n"
  },
  {
    "path": "turbo.json",
    "content": "{\n  \"$schema\": \"https://turbo.build/schema.json\",\n  \"tasks\": {\n    \"build\": {\n      \"outputs\": [\n        \"./packages/**/*.js\",\n        \"./packages/**/*.js.map\",\n        \"./packages/**/*.cjs\",\n        \"./packages/**/*.cjs.map\",\n        \"./packages/**/*.d.ts\",\n        \"./packages/**/*.d.cts\",\n        \"dist/**\",\n        \"storybook-static/**\"\n      ],\n      \"dependsOn\": [\"^build\"]\n    },\n    \"lint\": {},\n    \"test\": {\n      \"cache\": false,\n      \"persistent\": true,\n      \"dependsOn\": [\"build\"]\n    },\n    \"test:e2e\": {\n      \"cache\": false,\n      \"dependsOn\": [\"build\"]\n    },\n    \"dev\": {\n      \"cache\": false,\n      \"persistent\": true\n    },\n    \"clean\": {\n      \"cache\": false\n    }\n  }\n}\n"
  }
]