react-dragdrop-kit 1.1.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,196 +1,289 @@
1
- # react-dragdrop-kit
2
-
3
- A flexible and lightweight **drag-and-drop toolkit for React**. Build **sortable lists, grids, and boards** with a simple, fully-controlled API and customizable previews. Powered by Atlassian’s pragmatic drag-and-drop under the hood.
4
-
5
- <p>
6
- <a href="https://www.npmjs.com/package/react-dragdrop-kit"><img alt="npm" src="https://img.shields.io/npm/v/react-dragdrop-kit.svg?label=react-dragdrop-kit"></a>
7
- <a href="https://www.npmjs.com/package/react-dragdrop-kit"><img alt="downloads" src="https://img.shields.io/npm/dm/react-dragdrop-kit.svg"></a>
8
- <a href="https://github.com/Yourstruggle11/react-dragdrop-kit"><img alt="license" src="https://img.shields.io/badge/license-MIT-blue.svg"></a>
9
- </p>
10
-
11
- ---
12
-
13
- ## ✨ Features
14
-
15
- - 🔁 **Sortable** (vertical / horizontal)
16
- - 🎯 **Controlled**: you own the array, update on `onReorder`
17
- - 🧩 **Custom render** per item (cards, compact, detailed… anything)
18
- - 🧲 **Drop indicator** + optional **custom drag preview**
19
- - 🧪 **TypeScript** types included
20
- - Ships tiny bundles (only `dist/` published)
21
-
22
- ---
23
-
24
- ## 📦 Install
25
-
26
- ```bash
27
- npm i react-dragdrop-kit
28
- # or
29
- yarn add react-dragdrop-kit
30
- # or
31
- pnpm add react-dragdrop-kit
32
- ````
33
-
34
-
35
- ## 🚀 Quick Start (Basic Example)
36
-
37
- ```tsx
38
- // examples/basic-example.tsx
39
-
40
- import * as React from "react";
41
- import { DragDropList, type DraggableItem, type OrderUpdate } from "react-dragdrop-kit";
42
-
43
- interface TodoItem extends DraggableItem {
44
- title: string;
45
- completed: boolean;
46
- }
47
-
48
- const initial: TodoItem[] = [
49
- { id: "1", position: 0, title: "Learn React", completed: false },
50
- { id: "2", position: 1, title: "Build awesome app", completed: false },
51
- { id: "3", position: 2, title: "Deploy to production", completed: false },
52
- ];
53
-
54
- export default function BasicExample() {
55
- const [todos, setTodos] = React.useState(initial);
56
-
57
- const handleReorder = (next: TodoItem[], updates: OrderUpdate[]) => {
58
- // keep positions normalized
59
- setTodos(next.map((it, i) => ({ ...it, position: i })));
60
- // optionally send `updates` to your API
61
- // console.log("order updates", updates);
62
- };
63
-
64
- return (
65
- <DragDropList
66
- items={todos}
67
- onReorder={handleReorder}
68
- renderItem={(item) => (
69
- <div style={{ padding: 12, border: "1px solid #e5e7eb", borderRadius: 8 }}>
70
- <input
71
- type="checkbox"
72
- checked={item.completed}
73
- onChange={() =>
74
- setTodos((prev) =>
75
- prev.map((t) => (t.id === item.id ? { ...t, completed: !t.completed } : t))
76
- )
77
- }
78
- />
79
- <span style={{ marginLeft: 8 }}>{item.title}</span>
80
- </div>
81
- )}
82
- showDropIndicator
83
- gap={8}
84
- />
85
- );
86
- }
87
- ```
88
-
89
- ---
90
-
91
- ## 🎨 Styled Example (Tailwind)
92
-
93
- ```tsx
94
- // examples/tailwind-example.tsx
95
-
96
- import * as React from "react";
97
- import { DragDropList } from "react-dragdrop-kit";
98
-
99
- export default function TailwindExample() {
100
- const [items, setItems] = React.useState([
101
- { id: "1", position: 0, name: "Dashboard", icon: "📊" },
102
- { id: "2", position: 1, name: "Projects", icon: "📁" },
103
- { id: "3", position: 2, name: "Team", icon: "👥" },
104
- { id: "4", position: 3, name: "Calendar", icon: "📅" },
105
- ]);
106
-
107
- return (
108
- <DragDropList
109
- items={items}
110
- onReorder={(next) => setItems(next.map((it, i) => ({ ...it, position: i })))}
111
- containerClassName="bg-gray-50 rounded-xl p-6 space-y-2"
112
- itemClassName="bg-white rounded-lg shadow-sm hover:shadow-lg transition-all duration-200 cursor-move"
113
- dragPreviewClassName="bg-blue-100 rounded-lg shadow-2xl"
114
- showDropIndicator
115
- dropIndicatorClassName="bg-blue-500"
116
- renderItem={(item) => (
117
- <div className="flex items-center p-4 space-x-3">
118
- <span className="text-2xl">{item.icon}</span>
119
- <span className="font-medium text-gray-700">{item.name}</span>
120
- <div className="ml-auto">
121
- <svg className="w-5 h-5 text-gray-400" fill="currentColor" viewBox="0 0 20 20">
122
- <path d="M10 6a2 2 0 110-4 2 2 0 010 4zM10 12a2 2 0 110-4 2 2 0 010 4zM10 18a2 2 0 110-4 2 2 0 010 4z" />
123
- </svg>
124
- </div>
125
- </div>
126
- )}
127
- />
128
- );
129
- }
130
- ```
131
-
132
- ---
133
-
134
- ## 🧩 API
135
-
136
- ### `<DragDropList />`
137
-
138
- | Prop | Type | Default | Description |
139
- | ------------------------ | --------------------------------------------- | ------------ | ------------------------------------------------------------------------------------------------------ |
140
- | `items` | `Array<DraggableItem & T>` | — | Items to render. Must include `{ id: string; position: number }`. You can extend with your own fields. |
141
- | `onReorder` | `(next: T[], updates: OrderUpdate[]) => void` | — | Called after drop. `next` is the new array; `updates` has id + newPosition. |
142
- | `renderItem` | `(item: T) => React.ReactNode` | — | Custom renderer for each item. |
143
- | `direction` | `"vertical" \| "horizontal"` | `"vertical"` | Drag axis + layout. |
144
- | `gap` | `number` | `0` | Gap (px) between items. |
145
- | `disabled` | `boolean` | `false` | Disable dragging. |
146
- | `showDropIndicator` | `boolean` | `false` | Show a drop indicator while dragging. |
147
- | `dropIndicatorClassName` | `string` | — | CSS class applied to the drop indicator element. |
148
- | `dragPreviewStyle` | `React.CSSProperties` | — | Inline styles for custom drag preview. |
149
- | `containerClassName` | `string` | — | Class applied to the container. |
150
- | `itemClassName` | `string` | — | Class applied to each item wrapper. |
151
- | `containerStyle` | `React.CSSProperties` | — | Inline styles for the container. |
152
- | `itemStyle` | `React.CSSProperties` | — | Inline styles for each item wrapper. |
153
- | `onDragStart` | `(item: T, index: number) => void` | — | Optional callback when drag starts. |
154
- | `onDragEnd` | `(item: T, index: number) => void` | — | Optional callback when drag ends. |
155
-
156
- #### Types
157
-
158
- ```ts
159
- export type DraggableItem = {
160
- id: string;
161
- position: number; // 0-based
162
- };
163
-
164
- export type OrderUpdate = {
165
- id: string;
166
- newPosition: number;
167
- // Extend in your app if you need: { oldPosition, moved }
168
- };
169
- ```
170
-
171
- ---
172
-
173
- ## 🧠 Strict Mode (React 19)
174
-
175
- In dev, React Strict Mode **double-mounts** to surface side effects. If you see duplicate `onReorder` calls in development, ensure your event listeners clean up correctly and keep callback identities stable with `useCallback`. Production builds call once.
176
-
177
- ---
178
-
179
- ## 📚 More Examples
180
-
181
- This repo includes full examples:
182
-
183
- * [Basic Example](./examples/basic-example.tsx)
184
- * [Tailwind Example](./examples/tailwind-example.tsx)
185
- * [Material UI Example](./examples/material-ui-example.tsx)
186
- * [Horizontal Kanban](./examples/horizontal-kanban.tsx)
187
- * [Advanced Features](./examples/advanced-features.tsx)
188
- * [Styled Components Example](./examples/styled-components-example.tsx)
189
-
190
- 👉 Explore the [`examples/`](./examples) folder for the complete code.
191
-
192
- ---
193
-
194
- ## 📝 License
195
-
196
- MIT © [Yourstruggle11](https://github.com/Yourstruggle11)
1
+ # react-dragdrop-kit
2
+
3
+ A flexible, lightweight drag-and-drop toolkit for React.
4
+ Build sortable lists, grids, and Kanban boards with a controlled API and minimal overhead.
5
+
6
+ [![npm version](https://img.shields.io/npm/v/react-dragdrop-kit.svg)](https://www.npmjs.com/package/react-dragdrop-kit)
7
+ [![npm downloads](https://img.shields.io/npm/dm/react-dragdrop-kit.svg)](https://www.npmjs.com/package/react-dragdrop-kit)
8
+ [![bundle size](https://img.shields.io/bundlephobia/minzip/react-dragdrop-kit)](https://bundlephobia.com/package/react-dragdrop-kit)
9
+ [![license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/Yourstruggle11/react-dragdrop-kit)
10
+ [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/Yourstruggle11/react-dragdrop-kit)
11
+
12
+ ## Why this library
13
+
14
+ `react-dragdrop-kit` is designed around a controlled data model:
15
+
16
+ - You own state.
17
+ - The library reports drag intent and reorder results.
18
+ - You decide what to persist and render.
19
+
20
+ This keeps behavior predictable and easy to integrate with app-specific rules.
21
+
22
+ ## Feature overview
23
+
24
+ ### List and grid drag-and-drop
25
+
26
+ - Vertical and horizontal list support
27
+ - Controlled reorder callback: `onReorder(newItems, orderUpdates)`
28
+ - Optional visual drop indicator
29
+ - Optional custom drag preview style/class
30
+ - Optional handle-only dragging via `dragHandle`
31
+ - Optional multi-item drag with `selectedIds` + `multiDragEnabled`
32
+
33
+ ### Kanban module
34
+
35
+ - Card reorder within columns
36
+ - Card movement across columns
37
+ - Column reordering
38
+ - Headless rendering (`renderColumn`, `renderCard`)
39
+ - Accessibility helpers (`AnnouncerProvider`, `useAnnouncer`, `announcements`)
40
+ - Keyboard drag-reorder is planned, not fully shipped yet
41
+
42
+ ### General
43
+
44
+ - TypeScript-first API
45
+ - Lightweight runtime and tree-shakeable exports
46
+ - Built on `@atlaskit/pragmatic-drag-and-drop`
47
+
48
+ ## Installation
49
+
50
+ ```bash
51
+ npm install react-dragdrop-kit
52
+ # or
53
+ pnpm add react-dragdrop-kit
54
+ # or
55
+ yarn add react-dragdrop-kit
56
+ ```
57
+
58
+ ## Package entry points
59
+
60
+ ```ts
61
+ import { DragDropList } from "react-dragdrop-kit";
62
+ ```
63
+
64
+ ```ts
65
+ import { KanbanBoard, applyDragResult } from "react-dragdrop-kit/kanban";
66
+ ```
67
+
68
+ ## Quick start: sortable list
69
+
70
+ ```tsx
71
+ import { useState } from "react";
72
+ import { DragDropList } from "react-dragdrop-kit";
73
+
74
+ interface Todo {
75
+ id: string;
76
+ position: number;
77
+ title: string;
78
+ }
79
+
80
+ export default function TodoList() {
81
+ const [items, setItems] = useState<Todo[]>([
82
+ { id: "1", position: 0, title: "Design" },
83
+ { id: "2", position: 1, title: "Build" },
84
+ { id: "3", position: 2, title: "Ship" },
85
+ ]);
86
+
87
+ return (
88
+ <DragDropList
89
+ items={items}
90
+ onReorder={(next) =>
91
+ setItems(next.map((item, index) => ({ ...item, position: index })))
92
+ }
93
+ renderItem={(item) => (
94
+ <div style={{ padding: 12, border: "1px solid #e5e7eb", borderRadius: 8 }}>
95
+ {item.title}
96
+ </div>
97
+ )}
98
+ showDropIndicator
99
+ gap={8}
100
+ />
101
+ );
102
+ }
103
+ ```
104
+
105
+ ## Quick start: drag handle and multi-drag
106
+
107
+ ```tsx
108
+ <DragDropList
109
+ items={items}
110
+ onReorder={handleReorder}
111
+ renderItem={renderItem}
112
+ dragHandle="[data-drag-handle]"
113
+ selectedIds={selectedIds}
114
+ multiDragEnabled
115
+ />
116
+ ```
117
+
118
+ Behavior notes:
119
+
120
+ - `dragHandle` is optional. If provided, drag starts only from matching descendants.
121
+ - `multiDragEnabled` is opt-in. Without it, behavior remains single-item drag.
122
+ - `selectedIds` is consumed only when multi-drag is enabled.
123
+
124
+ ## Quick start: Kanban board
125
+
126
+ ```tsx
127
+ import { useCallback, useState } from "react";
128
+ import {
129
+ KanbanBoard,
130
+ applyDragResult,
131
+ type DropResult,
132
+ type KanbanBoardState,
133
+ } from "react-dragdrop-kit/kanban";
134
+
135
+ export default function Board() {
136
+ const [state, setState] = useState<KanbanBoardState>({
137
+ columns: [
138
+ { id: "todo", title: "To Do", cardIds: ["task-1", "task-2"] },
139
+ { id: "done", title: "Done", cardIds: [] },
140
+ ],
141
+ cards: {
142
+ "task-1": { id: "task-1", title: "Design landing page" },
143
+ "task-2": { id: "task-2", title: "Implement auth" },
144
+ },
145
+ });
146
+
147
+ const handleDragEnd = useCallback(
148
+ (result: DropResult, stateBefore: KanbanBoardState) => {
149
+ if (!result.destination) return;
150
+ setState(applyDragResult(stateBefore, result));
151
+ },
152
+ []
153
+ );
154
+
155
+ return (
156
+ <KanbanBoard
157
+ state={state}
158
+ onDragEnd={handleDragEnd}
159
+ renderColumn={(column) => <div style={{ padding: 12 }}>{column.title}</div>}
160
+ renderCard={(card) => <div style={{ padding: 12 }}>{card.title}</div>}
161
+ />
162
+ );
163
+ }
164
+ ```
165
+
166
+ ## API reference: list module
167
+
168
+ ### Core types
169
+
170
+ ```ts
171
+ type DraggableItem = {
172
+ id: string;
173
+ position: number;
174
+ [key: string]: any;
175
+ };
176
+
177
+ type OrderUpdate = {
178
+ id: string;
179
+ newPosition: number;
180
+ moved?: boolean;
181
+ };
182
+ ```
183
+
184
+ ### DragDropList props
185
+
186
+ | Prop | Type | Default | Description |
187
+ | --- | --- | --- | --- |
188
+ | `items` | `T[]` | Required | Controlled items. Each item must include `id` and `position`. |
189
+ | `onReorder` | `(newItems: T[], orderUpdates: OrderUpdate[]) => void` | Required | Fired after successful drop/reorder. |
190
+ | `renderItem` | `(item: T, index: number) => ReactNode` | Required | Item renderer. |
191
+ | `containerClassName` | `string` | `""` | Class name for container. |
192
+ | `containerStyle` | `React.CSSProperties` | `{}` | Inline style for container. |
193
+ | `itemClassName` | `string` | `""` | Class for each draggable wrapper. |
194
+ | `itemStyle` | `React.CSSProperties` | `{}` | Style for each draggable wrapper. |
195
+ | `dragPreviewClassName` | `string` | `""` | Class for generated drag preview. |
196
+ | `dragPreviewStyle` | `React.CSSProperties` | `{}` | Style for generated drag preview. |
197
+ | `onDragStart` | `(item: T, index: number) => void` | `undefined` | Callback on item drag start. |
198
+ | `onDragEnd` | `(item: T, index: number) => void` | `undefined` | Callback on item drag end. |
199
+ | `disabled` | `boolean` | `false` | Disables list drag/drop. |
200
+ | `gap` | `number \| string` | `undefined` | Gap applied to container. |
201
+ | `direction` | `"vertical" \| "horizontal"` | `"vertical"` | Layout and closest-edge interpretation. |
202
+ | `showDropIndicator` | `boolean` | `false` | Enables drop indicator line. |
203
+ | `dropIndicatorClassName` | `string` | `""` | Class for drop indicator. |
204
+ | `dropIndicatorStyle` | `React.CSSProperties` | `{}` | Style for drop indicator. |
205
+ | `dropIndicatorPosition` | `"top" \| "bottom"` | `"bottom"` | Indicator position for hovered target item. |
206
+ | `dragHandle` | `string` | `undefined` | CSS selector for handle-only dragging. |
207
+ | `selectedIds` | `string[]` | `[]` | Selected IDs used by multi-drag. |
208
+ | `multiDragEnabled` | `boolean` | `false` | Enables grouped drag behavior. |
209
+
210
+ ## API reference: Kanban module
211
+
212
+ The full Kanban API is documented in [docs/kanban.md](./docs/kanban.md).
213
+
214
+ Exports:
215
+
216
+ - Components: `KanbanBoard`, `KanbanColumnView`, `KanbanCardView`
217
+ - Hooks: `useKanbanDnd`, `useAutoscroll`
218
+ - A11y: `AnnouncerProvider`, `useAnnouncer`, `announcements`
219
+ - Utils: `applyDragResult`, `reorderArray`
220
+ - Types: `KanbanBoardState`, `DropResult`, `KanbanCard`, `KanbanColumn`, and more
221
+
222
+ ## Examples
223
+
224
+ ### Repository examples
225
+
226
+ - `examples/basic-example.tsx`
227
+ - `examples/advanced-features.tsx`
228
+ - `examples/material-ui-example.tsx`
229
+ - `examples/tailwind-example.tsx`
230
+ - `examples/kanban/basic-kanban.tsx`
231
+ - `examples/kanban/rich-cards-kanban.tsx`
232
+ - `examples/kanban/themed-kanban.tsx`
233
+ - `examples/kanban/accessible-kanban.tsx`
234
+
235
+ ### Demo examples
236
+
237
+ - List/grid examples under `apps/demo/src/examples/*`
238
+ - Kanban demos:
239
+ - `apps/demo/src/examples/BasicKanban/index.tsx`
240
+ - `apps/demo/src/examples/RichKanban/index.tsx`
241
+ - `apps/demo/src/examples/SwimlanesKanban/index.tsx`
242
+ - `apps/demo/src/examples/WipLimitsKanban/index.tsx`
243
+
244
+ ## Migration notes
245
+
246
+ ### From react-beautiful-dnd
247
+
248
+ High-level mapping for Kanban use cases:
249
+
250
+ - `DragDropContext` -> `KanbanBoard`
251
+ - `Droppable` -> `KanbanColumnView`
252
+ - `Draggable` -> `KanbanCardView`
253
+
254
+ Important differences:
255
+
256
+ 1. State is normalized (`columns` + `cards`) instead of nested.
257
+ 2. IDs are explicit and owned by your app.
258
+ 3. Rendering is done via render functions (`renderColumn`, `renderCard`).
259
+
260
+ ## Development notes
261
+
262
+ ### React Strict Mode
263
+
264
+ In development, React Strict Mode can mount effects twice.
265
+ Ensure listener setup and cleanup are idempotent when integrating custom logic.
266
+
267
+ ## Bundle size
268
+
269
+ Approximate minified sizes:
270
+
271
+ - `react-dragdrop-kit`: about 5KB
272
+ - `react-dragdrop-kit/kanban`: about 9KB
273
+
274
+ ## Documentation and links
275
+
276
+ - [Kanban guide](./docs/kanban.md)
277
+ - [Known issues](./KNOWN_ISSUES.md)
278
+ - [Changelog](./packages/react-dragdrop-kit/CHANGELOG.md)
279
+ - [Examples folder](./examples)
280
+ - [Demo app](https://react-dragdrop-kit.netlify.app/)
281
+
282
+ ## Support
283
+
284
+ - [Report issues](https://github.com/Yourstruggle11/react-dragdrop-kit/issues)
285
+ - [Request features](https://github.com/Yourstruggle11/react-dragdrop-kit/issues/new)
286
+
287
+ ## License
288
+
289
+ MIT
package/dist/index.esm.js CHANGED
@@ -1,2 +1,2 @@
1
- import e,{useRef as t,useState as a,useCallback as r,useEffect as o}from"react";import{combine as i}from"@atlaskit/pragmatic-drag-and-drop/combine";import{draggable as n,dropTargetForElements as d,monitorForElements as s}from"@atlaskit/pragmatic-drag-and-drop/element/adapter";import{extractClosestEdge as l}from"@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge";const c={container:{default:{minHeight:"200px",transition:"all 0.2s ease",borderRadius:"8px",border:"1px solid #e2e8f0",backgroundColor:"#ffffff",display:"flex",flexDirection:"column",gap:"16px",padding:"16px"},dragging:{backgroundColor:"rgba(66, 153, 225, 0.05)",borderColor:"#3182ce"},horizontal:{flexDirection:"row",flexWrap:"wrap"}},item:{default:{transition:"all 0.2s ease",cursor:"grab",userSelect:"none",position:"relative"},dragging:{opacity:.5,cursor:"grabbing"},hover:{transform:"scale(1.02)",boxShadow:"0 4px 6px rgba(0, 0, 0, 0.1)"},disabled:{cursor:"not-allowed",opacity:.6}},preview:{position:"fixed",pointerEvents:"none",zIndex:9999,opacity:.8,transform:"rotate(2deg)",boxShadow:"0 10px 20px rgba(0, 0, 0, 0.15)"},dropIndicator:{position:"absolute",height:"2px",backgroundColor:"#3182ce",left:0,right:0,zIndex:10,transition:"all 0.2s ease"}},g="draggable-item";function p({item:s,index:l,children:p,className:m="",style:u={},dragPreviewClassName:b="",dragPreviewStyle:v={},onDragStart:f,onDragEnd:x,disabled:y=!1,showDropIndicator:D=!1,dropIndicatorClassName:h="",dropIndicatorStyle:I={},dropIndicatorPosition:j="bottom"}){const O=t(null),[w,S]=a(!1),[N,C]=a(!1),[E,P]=a(null),k=r(e=>y?()=>{}:n({element:e,getInitialData:()=>({type:g,id:s.id,index:l}),onGenerateDragPreview:({nativeSetDragImage:t})=>{const a=e.cloneNode(!0),r=Object.assign(Object.assign({},c.preview),v);b&&(a.className=b),Object.assign(a.style,r,{width:`${(null==e?void 0:e.offsetWidth)||100}px`,height:`${(null==e?void 0:e.offsetHeight)||50}px`}),document.body.appendChild(a),t&&t(a,20,20),requestAnimationFrame(()=>a.remove())},onDragStart:()=>{S(!0),null==f||f(s,l)},onDrop:()=>{S(!1),null==x||x(s,l)}}),[s,l,b,v,f,x,y]),z=r(e=>y?()=>{}:d({element:e,getData:()=>({type:g,id:s.id,index:l}),canDrop:e=>{var t;return(null===(t=e.source.data)||void 0===t?void 0:t.type)===g},getIsSticky:()=>!0,onDragEnter:({source:e,self:t})=>{var a,r;(null===(a=e.data)||void 0===a?void 0:a.id)!==(null===(r=t.data)||void 0===r?void 0:r.id)&&(C(!0),D&&P(j))},onDragLeave:()=>{C(!1),P(null)},onDrop:()=>{C(!1),P(null)}}),[s.id,l,y,D,j]);return o(()=>{const e=O.current;if(e)return e.setAttribute("data-index",l.toString()),y?()=>{}:i(k(e),z(e))},[l,k,z,y]),e.createElement("div",{ref:O,className:m,style:(()=>{const e=Object.assign({},c.item.default);return y?Object.assign(e,c.item.disabled):w?Object.assign(e,c.item.dragging):N&&Object.assign(e,c.item.hover),Object.assign(Object.assign({},e),u)})()},D&&"top"===E&&e.createElement("div",{className:h,style:Object.assign(Object.assign(Object.assign({},c.dropIndicator),I),{top:-1})}),p,D&&"bottom"===E&&e.createElement("div",{className:h,style:Object.assign(Object.assign(Object.assign({},c.dropIndicator),I),{bottom:-1})}))}function m({items:e,onReorder:t,disabled:a=!1}){if(a)return()=>{};return s({onDrop:({location:a,source:r})=>{var o;const i=null===(o=r.data)||void 0===o?void 0:o.index;if(void 0===i)return;const{dropTargets:n}=a.current,d=n.find(e=>{var t,a,o;return"draggable-item"===(null===(t=e.data)||void 0===t?void 0:t.type)&&(null===(a=e.data)||void 0===a?void 0:a.id)!==(null===(o=r.data)||void 0===o?void 0:o.id)});if(!d)return;const s=l(d),c=Number(d.element.getAttribute("data-index")),g="bottom"===s?c+1:c;if(i!==g){const a=[...e],r=function(e,t,a){const r=Array.from(e),[o]=r.splice(t,1);return r.splice(a,0,o),r}(e,i,g),o=function(e,t){const a=t.filter((t,a)=>{var r;return t.id!==(null===(r=e[a])||void 0===r?void 0:r.id)}),r=a.slice().sort((e,t)=>e.position-t.position).map(e=>e.position);return a.map((e,t)=>({id:e.id,newPosition:r[t]}))}(a,r);t(r,o)}}})}function u({items:n,onReorder:s,renderItem:l,containerClassName:g="",containerStyle:u={},itemClassName:b="",itemStyle:v={},dragPreviewClassName:f="",dragPreviewStyle:x={},onDragStart:y,onDragEnd:D,disabled:h=!1,gap:I,direction:j="vertical",showDropIndicator:O=!1,dropIndicatorClassName:w="",dropIndicatorStyle:S={},dropIndicatorPosition:N="bottom"}){const C=t(null),E=m({items:n,onReorder:s,disabled:h}),[P,k]=a(!1),z=r(e=>h?()=>{}:d({element:e,getData:()=>({type:"container"}),onDragEnter:()=>k(!0),onDragLeave:()=>k(!1),onDrop:()=>k(!1)}),[h]);return o(()=>{const e=C.current;if(e&&!h)return i(z(e),E)},[z,E,h]),e.createElement("div",{ref:C,className:g,style:(()=>{const e=Object.assign({},c.container.default);return"horizontal"===j&&Object.assign(e,c.container.horizontal),P&&Object.assign(e,c.container.dragging),void 0!==I&&(e.gap="number"==typeof I?`${I}px`:I),Object.assign(Object.assign({},e),u)})()},n.map((t,a)=>e.createElement(p,{key:t.id,item:t,index:a,className:b,style:v,dragPreviewClassName:f,dragPreviewStyle:x,onDragStart:y,onDragEnd:D,disabled:h,showDropIndicator:O,dropIndicatorClassName:w,dropIndicatorStyle:S,dropIndicatorPosition:N},l(t,a))))}export{u as DragDropList,p as DraggableItemWrapper,c as defaultStyles,m as useDragDropMonitor};
1
+ import e,{useRef as t,useState as n,useCallback as a,useEffect as r}from"react";import{draggable as i,dropTargetForElements as o,monitorForElements as d}from"@atlaskit/pragmatic-drag-and-drop/element/adapter";import{combine as s}from"@atlaskit/pragmatic-drag-and-drop/combine";import{attachClosestEdge as l,extractClosestEdge as c}from"@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge";const g={container:{default:{minHeight:"200px",transition:"all 0.2s ease",borderRadius:"8px",border:"1px solid #e2e8f0",backgroundColor:"#ffffff",display:"flex",flexDirection:"column",gap:"16px",padding:"16px"},dragging:{backgroundColor:"rgba(66, 153, 225, 0.05)",borderColor:"#3182ce"},horizontal:{flexDirection:"row",flexWrap:"wrap"}},item:{default:{transition:"all 0.2s ease",cursor:"grab",userSelect:"none",position:"relative"},dragging:{opacity:.5,cursor:"grabbing"},hover:{transform:"scale(1.02)",boxShadow:"0 4px 6px rgba(0, 0, 0, 0.1)"},disabled:{cursor:"not-allowed",opacity:.6}},preview:{position:"fixed",pointerEvents:"none",zIndex:9999,opacity:.8,transform:"rotate(2deg)",boxShadow:"0 10px 20px rgba(0, 0, 0, 0.15)"},dropIndicator:{position:"absolute",height:"2px",backgroundColor:"#3182ce",left:0,right:0,zIndex:10,transition:"all 0.2s ease"}},m="draggable-item";function u({item:d,index:c,children:u,className:p="",style:f={},dragPreviewClassName:b="",dragPreviewStyle:v={},onDragStart:h,onDragEnd:x,disabled:D=!1,showDropIndicator:y=!1,dropIndicatorClassName:I="",dropIndicatorStyle:w={},dropIndicatorPosition:S="bottom",direction:j="vertical",dragHandle:O}){const N=t(null),[C,E]=n(!1),[P,M]=n(!1),[k,z]=n(null),H=a(e=>{if(D)return()=>{};const t=O?e.querySelector(O):void 0;return i({element:e,dragHandle:null!=t?t:void 0,canDrag:()=>!O||Boolean(t),getInitialData:()=>({type:m,id:d.id,index:c}),onGenerateDragPreview:({nativeSetDragImage:t})=>{const n=e.cloneNode(!0),a=Object.assign(Object.assign({},g.preview),v);b&&(n.className=b),Object.assign(n.style,a,{width:`${(null==e?void 0:e.offsetWidth)||100}px`,height:`${(null==e?void 0:e.offsetHeight)||50}px`}),document.body.appendChild(n),t&&t(n,20,20),requestAnimationFrame(()=>n.remove())},onDragStart:()=>{E(!0),null==h||h(d,c)},onDrop:()=>{E(!1),null==x||x(d,c)}})},[d,c,O,b,v,h,x,D]),L=a(e=>D?()=>{}:o({element:e,getData:({input:e,element:t})=>{const n={type:m,id:d.id,index:c};return l(n,{input:e,element:t,allowedEdges:[..."horizontal"===j?["left","right"]:["top","bottom"]]})},canDrop:({source:e})=>{var t;return(null===(t=e.data)||void 0===t?void 0:t.type)===m},getIsSticky:()=>!0,onDragEnter:({source:e,self:t})=>{var n,a;(null===(n=e.data)||void 0===n?void 0:n.id)!==(null===(a=t.data)||void 0===a?void 0:a.id)&&(M(!0),y&&z(S))},onDragLeave:()=>{M(!1),z(null)},onDrop:()=>{M(!1),z(null)}}),[d.id,c,j,D,y,S]);return r(()=>{const e=N.current;if(e)return e.setAttribute("data-index",c.toString()),D?()=>{}:s(H(e),L(e))},[c,H,L,D]),e.createElement("div",{ref:N,className:p,style:(()=>{const e=Object.assign({},g.item.default);return D?Object.assign(e,g.item.disabled):C?Object.assign(e,g.item.dragging):P&&Object.assign(e,g.item.hover),Object.assign(Object.assign({},e),f)})()},y&&"top"===k&&e.createElement("div",{className:I,style:Object.assign(Object.assign(Object.assign({},g.dropIndicator),w),{top:-1})}),u,y&&"bottom"===k&&e.createElement("div",{className:I,style:Object.assign(Object.assign(Object.assign({},g.dropIndicator),w),{bottom:-1})}))}function p(e,t,n){const a=Array.from(e),[r]=a.splice(t,1);return a.splice(n,0,r),a}function f(e){const{itemCount:t,sourceIndex:n,rawDestinationIndex:a,isSameList:r}=e;if(t<=0)return 0;const i=t,o=Math.max(0,Math.min(a,i)),d=r&&n<o?o-1:o,s=r?t-1:t;return Math.max(0,Math.min(d,s))}function b({items:e,onReorder:t,disabled:n=!1,direction:i="vertical",selectedIds:o=[],multiDragEnabled:s=!1}){const l=a(({location:n,source:a})=>{var r,d,l;const g=null===(r=a.data)||void 0===r?void 0:r.id,m=null===(d=a.data)||void 0===d?void 0:d.index;if(void 0===g||void 0===m)return;const{dropTargets:u}=n.current,b=u.find(e=>{var t,n;return"draggable-item"===(null===(t=e.data)||void 0===t?void 0:t.type)&&(null===(n=e.data)||void 0===n?void 0:n.id)!==g}),v=u.find(e=>{var t;return"container"===(null===(t=e.data)||void 0===t?void 0:t.type)});if(!b&&!v)return;let h=e.length;if(b){const e=Number(null===(l=b.data)||void 0===l?void 0:l.index);if(!Number.isFinite(e))return;const t=c(b.data);h="bottom"===t||"horizontal"===i&&"right"===t?e+1:e}const x=[...e];let D=e;if(s){const t=new Set(o);t.has(g)||t.clear(),t.add(g);const n=e.map((e,n)=>t.has(e.id)?n:-1).filter(e=>-1!==e);if(n.length>1)D=function(e,t,n){const a=Array.from(new Set(t.filter(t=>t>=0&&t<e.length))).sort((e,t)=>e-t);if(0===a.length)return e;const r=new Set(a),i=a.map(t=>e[t]),o=e.filter((e,t)=>!r.has(t)),d=Math.max(0,Math.min(n,e.length)),s=a.filter(e=>e<d).length,l=Math.max(0,Math.min(d-s,o.length)),c=[...o];return c.splice(l,0,...i),c}(e,n,h);else{const t=f({itemCount:e.length,sourceIndex:m,rawDestinationIndex:h,isSameList:!0});D=p(e,m,t)}}else{const t=f({itemCount:e.length,sourceIndex:m,rawDestinationIndex:h,isSameList:!0});D=p(e,m,t)}const y=D.some((e,t)=>{var n;return e.id!==(null===(n=x[t])||void 0===n?void 0:n.id)});if(!y)return;const I=function(e,t){const n=new Map(e.map((e,t)=>[e.id,t]));return t.flatMap((e,t)=>{const a=n.get(e.id);return void 0===a||a===t?[]:[{id:e.id,newPosition:t,moved:!0}]})}(x,D);t(D,I)},[e,t,i,o,s]);return r(()=>{if(!n)return d({onDrop:l})},[n,l]),a(()=>{},[])}function v({items:i,onReorder:d,renderItem:s,containerClassName:l="",containerStyle:c={},itemClassName:m="",itemStyle:p={},dragPreviewClassName:f="",dragPreviewStyle:v={},onDragStart:h,onDragEnd:x,disabled:D=!1,gap:y,direction:I="vertical",showDropIndicator:w=!1,dropIndicatorClassName:S="",dropIndicatorStyle:j={},dropIndicatorPosition:O="bottom",dragHandle:N,selectedIds:C=[],multiDragEnabled:E=!1}){const P=t(null);b({items:i,onReorder:d,disabled:D,direction:I,selectedIds:C,multiDragEnabled:E});const[M,k]=n(!1),z=a(e=>D?()=>{}:o({element:e,getData:()=>({type:"container"}),onDragEnter:()=>k(!0),onDragLeave:()=>k(!1),onDrop:()=>k(!1)}),[D]);return r(()=>{const e=P.current;if(e&&!D)return z(e)},[z,D]),e.createElement("div",{ref:P,className:l,style:(()=>{const e=Object.assign({},g.container.default);return"horizontal"===I&&Object.assign(e,g.container.horizontal),M&&Object.assign(e,g.container.dragging),void 0!==y&&(e.gap="number"==typeof y?`${y}px`:y),Object.assign(Object.assign({},e),c)})()},i.map((t,n)=>e.createElement(u,{key:t.id,item:t,index:n,className:m,style:p,dragPreviewClassName:f,dragPreviewStyle:v,onDragStart:h,onDragEnd:x,disabled:D,showDropIndicator:w,dropIndicatorClassName:S,dropIndicatorStyle:j,dropIndicatorPosition:O,direction:I,dragHandle:N},s(t,n))))}export{v as DragDropList,u as DraggableItemWrapper,g as defaultStyles,b as useDragDropMonitor};
2
2
  //# sourceMappingURL=index.esm.js.map