@dnd-block-tree/vanilla 2.2.1 → 2.4.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/dist/index.d.mts +60 -3
- package/dist/index.d.ts +60 -3
- package/dist/index.js +119 -31
- package/dist/index.mjs +117 -34
- package/package.json +6 -2
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { BaseBlock, BlockRendererProps as BlockRendererProps$1, BlockRenderers as BlockRenderers$1, OrderingStrategy, CanDragFn, CanDropFn, IdGeneratorFn, SensorConfig, BlockTreeCallbacks, ContainerRendererProps as ContainerRendererProps$1, InternalRenderers as InternalRenderers$1, RendererPropsFor as RendererPropsFor$1, BlockTreeInstance, Rect, CollisionCandidate, CoreCollisionDetection } from '@dnd-block-tree/core';
|
|
2
|
-
export { AnimationConfig, AutoExpandConfig, BaseBlock, BlockAction, BlockAddEvent, BlockDeleteEvent, BlockIndex, BlockMoveEvent, BlockPosition, BlockStateContextValue, BlockTreeCallbacks, BlockTreeConfig, BlockTreeCustomization, BlockTreeEvents, BlockTreeInstance, BlockTreeOptions, CanDragFn, CanDropFn, CollisionCandidate, CollisionResult, CoreCollisionDetection, DragEndEvent, DragMoveEvent, DragStartEvent, DropZoneConfig, DropZoneType, EventEmitter, ExpandAction, ExpandChangeEvent, HistoryAction, HistoryState, HoverChangeEvent, IdGeneratorFn, MoveOperation, NestedBlock, OrderingStrategy, Rect, SensorConfig, SnapshotRectsRef, TreeValidationResult, blockReducer, buildOrderedBlocks, cloneMap, cloneParentMap, closestCenterCollision, compareFractionalKeys, computeNormalizedIndex, createBlockTree, createStickyCollision, debounce, deleteBlockAndDescendants, expandReducer, extractBlockId, extractUUID, flatToNested, generateId, generateInitialKeys, generateKeyBetween, generateNKeysBetween, getBlockDepth, getDescendantIds, getDropZoneType, getSubtreeDepth, historyReducer, initFractionalOrder, nestedToFlat, reparentBlockIndex, reparentMultipleBlocks, validateBlockTree, weightedVerticalCollision } from '@dnd-block-tree/core';
|
|
1
|
+
import { BaseBlock, BlockRendererProps as BlockRendererProps$1, BlockRenderers as BlockRenderers$1, OrderingStrategy, CanDragFn, CanDropFn, IdGeneratorFn, SensorConfig, BlockTreeCallbacks, ContainerRendererProps as ContainerRendererProps$1, InternalRenderers as InternalRenderers$1, RendererPropsFor as RendererPropsFor$1, BlockTreeInstance, Rect, CollisionCandidate, CoreCollisionDetection, MergeBlockVersionsOptions } from '@dnd-block-tree/core';
|
|
2
|
+
export { AnimationConfig, AutoExpandConfig, BaseBlock, BlockAction, BlockAddEvent, BlockDeleteEvent, BlockIndex, BlockMoveEvent, BlockPosition, BlockStateContextValue, BlockTreeCallbacks, BlockTreeConfig, BlockTreeCustomization, BlockTreeEvents, BlockTreeInstance, BlockTreeOptions, CanDragFn, CanDropFn, CollisionCandidate, CollisionResult, CoreCollisionDetection, DragEndEvent, DragMoveEvent, DragStartEvent, DropZoneConfig, DropZoneType, EventEmitter, ExpandAction, ExpandChangeEvent, HistoryAction, HistoryState, HoverChangeEvent, IdGeneratorFn, MergeBlockVersionsOptions, MoveOperation, NestedBlock, OrderingStrategy, Rect, SensorConfig, SnapshotRectsRef, TreeValidationResult, blockReducer, buildOrderedBlocks, cloneMap, cloneParentMap, closestCenterCollision, compareFractionalKeys, computeNormalizedIndex, createBlockTree, createStickyCollision, debounce, deleteBlockAndDescendants, expandReducer, extractBlockId, extractUUID, flatToNested, generateId, generateInitialKeys, generateKeyBetween, generateNKeysBetween, getBlockDepth, getDescendantIds, getDropZoneType, getSubtreeDepth, historyReducer, initFractionalOrder, mergeBlockVersions, nestedToFlat, reparentBlockIndex, reparentMultipleBlocks, validateBlockTree, weightedVerticalCollision } from '@dnd-block-tree/core';
|
|
3
3
|
|
|
4
4
|
type BlockRendererProps<T extends BaseBlock = BaseBlock> = BlockRendererProps$1<T, HTMLElement>;
|
|
5
5
|
type ContainerRendererProps<T extends BaseBlock = BaseBlock> = ContainerRendererProps$1<T, HTMLElement>;
|
|
@@ -54,8 +54,13 @@ interface RenderBlockContext {
|
|
|
54
54
|
/** DefaultRenderer options */
|
|
55
55
|
interface DefaultRendererOptions<T extends BaseBlock = BaseBlock> {
|
|
56
56
|
container: HTMLElement;
|
|
57
|
+
containerTypes?: readonly string[];
|
|
57
58
|
renderBlock: (block: T, ctx: RenderBlockContext) => HTMLElement;
|
|
58
59
|
dropZoneHeight?: number;
|
|
60
|
+
dropZoneClassName?: string;
|
|
61
|
+
dropZoneActiveClassName?: string;
|
|
62
|
+
rootClassName?: string;
|
|
63
|
+
indentClassName?: string;
|
|
59
64
|
animateExpand?: boolean;
|
|
60
65
|
}
|
|
61
66
|
/** Cleanup function */
|
|
@@ -142,6 +147,54 @@ interface BlockHistory<T extends BaseBlock> {
|
|
|
142
147
|
*/
|
|
143
148
|
declare function createBlockHistory<T extends BaseBlock>(initialBlocks: T[], options?: BlockHistoryOptions): BlockHistory<T>;
|
|
144
149
|
|
|
150
|
+
interface DeferredSyncOptions<T extends BaseBlock> {
|
|
151
|
+
/** Called when remote data is applied (only when not busy) */
|
|
152
|
+
onResolve?: (blocks: T[]) => void;
|
|
153
|
+
/** Options passed to mergeBlockVersions when using 'merge' strategy */
|
|
154
|
+
mergeOptions?: MergeBlockVersionsOptions;
|
|
155
|
+
}
|
|
156
|
+
interface DeferredSync<T extends BaseBlock> {
|
|
157
|
+
/** Whether sync is currently deferred */
|
|
158
|
+
isBusy(): boolean;
|
|
159
|
+
/** Apply remote blocks — queues if busy, calls onResolve if idle */
|
|
160
|
+
apply(remoteBlocks: T[]): void;
|
|
161
|
+
/** Enter busy state (call before editing or dragging) */
|
|
162
|
+
enterBusy(): void;
|
|
163
|
+
/**
|
|
164
|
+
* Exit busy state and resolve any queued remote changes.
|
|
165
|
+
* Returns the merged result if a queue existed, null otherwise.
|
|
166
|
+
*/
|
|
167
|
+
exitBusy(localBlocks: T[], strategy: 'merge' | 'lww'): T[] | null;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Imperative deferred sync factory for vanilla JS.
|
|
171
|
+
* Queues remote updates during blocking actions and resolves
|
|
172
|
+
* on exit using merge or last-write-wins strategy.
|
|
173
|
+
*
|
|
174
|
+
* @param options - Configuration including onResolve callback and merge options
|
|
175
|
+
* @returns DeferredSync instance with busy/queue/flush methods
|
|
176
|
+
*
|
|
177
|
+
* @example
|
|
178
|
+
* ```ts
|
|
179
|
+
* const sync = createDeferredSync<MyBlock>({
|
|
180
|
+
* onResolve: (blocks) => controller.setBlocks(blocks),
|
|
181
|
+
* })
|
|
182
|
+
*
|
|
183
|
+
* // In your realtime subscription:
|
|
184
|
+
* socket.on('blocks', (blocks) => sync.apply(blocks))
|
|
185
|
+
*
|
|
186
|
+
* // Drag lifecycle:
|
|
187
|
+
* controller.on('drag:statechange', ({ isDragging }) => {
|
|
188
|
+
* if (isDragging) sync.enterBusy()
|
|
189
|
+
* else {
|
|
190
|
+
* const result = sync.exitBusy(controller.getBlocks(), 'lww')
|
|
191
|
+
* if (result) socket.emit('blocks', result)
|
|
192
|
+
* }
|
|
193
|
+
* })
|
|
194
|
+
* ```
|
|
195
|
+
*/
|
|
196
|
+
declare function createDeferredSync<T extends BaseBlock>(options?: DeferredSyncOptions<T>): DeferredSync<T>;
|
|
197
|
+
|
|
145
198
|
interface LayoutAnimationOptions {
|
|
146
199
|
duration?: number;
|
|
147
200
|
easing?: string;
|
|
@@ -276,6 +329,9 @@ interface TreeRendererOptions<T extends BaseBlock> {
|
|
|
276
329
|
renderBlock: (block: T, ctx: RenderBlockContext) => HTMLElement;
|
|
277
330
|
containerTypes: readonly string[];
|
|
278
331
|
dropZoneHeight?: number;
|
|
332
|
+
dropZoneClassName?: string;
|
|
333
|
+
rootClassName?: string;
|
|
334
|
+
indentClassName?: string;
|
|
279
335
|
}
|
|
280
336
|
/**
|
|
281
337
|
* Recursive DOM tree builder. Creates the full tree DOM from blocks.
|
|
@@ -286,6 +342,7 @@ declare function renderTree<T extends BaseBlock>(blocks: T[], expandedMap: Recor
|
|
|
286
342
|
interface DropZoneOptions {
|
|
287
343
|
id: string;
|
|
288
344
|
height?: number;
|
|
345
|
+
className?: string;
|
|
289
346
|
}
|
|
290
347
|
declare function createDropZoneElement(options: DropZoneOptions): HTMLElement;
|
|
291
348
|
declare function setDropZoneActive(el: HTMLElement, active: boolean): void;
|
|
@@ -311,4 +368,4 @@ declare function createDisposable(): Disposable & {
|
|
|
311
368
|
add(fn: () => void): void;
|
|
312
369
|
};
|
|
313
370
|
|
|
314
|
-
export { type BlockHistory, type BlockHistoryOptions, type BlockRendererProps, type BlockRenderers, type BlockTreeController, type BlockTreeControllerOptions, type ContainerRendererProps, type ControllerEvents, type DefaultRenderer, type DefaultRendererOptions, type Disposable, DragOverlay, type DragOverlayOptions, type DragState, type InternalRenderers, KeyboardSensor, type KeyboardSensorCallbacks, LayoutAnimation, type LayoutAnimationOptions, PointerSensor, type PointerSensorOptions, type RenderBlockContext, type RendererPropsFor, type Sensor, type SensorCallbacks, TouchSensor, type TouchSensorOptions, type TreeRendererOptions, type Unsubscribe, type VanillaSensorConfig, type VirtualRange, VirtualScroller, type VirtualScrollerOptions, buildCandidates, closestWithData, createBlockHistory, createBlockTreeController, createDefaultRenderer, createDisposable, createDropZoneElement, createElement, createGhostPreview, detectCollision, measureDropZoneRects, pointerToRect, renderTree, setDataAttributes, setDropZoneActive, triggerHaptic };
|
|
371
|
+
export { type BlockHistory, type BlockHistoryOptions, type BlockRendererProps, type BlockRenderers, type BlockTreeController, type BlockTreeControllerOptions, type ContainerRendererProps, type ControllerEvents, type DefaultRenderer, type DefaultRendererOptions, type DeferredSync, type DeferredSyncOptions, type Disposable, DragOverlay, type DragOverlayOptions, type DragState, type InternalRenderers, KeyboardSensor, type KeyboardSensorCallbacks, LayoutAnimation, type LayoutAnimationOptions, PointerSensor, type PointerSensorOptions, type RenderBlockContext, type RendererPropsFor, type Sensor, type SensorCallbacks, TouchSensor, type TouchSensorOptions, type TreeRendererOptions, type Unsubscribe, type VanillaSensorConfig, type VirtualRange, VirtualScroller, type VirtualScrollerOptions, buildCandidates, closestWithData, createBlockHistory, createBlockTreeController, createDefaultRenderer, createDeferredSync, createDisposable, createDropZoneElement, createElement, createGhostPreview, detectCollision, measureDropZoneRects, pointerToRect, renderTree, setDataAttributes, setDropZoneActive, triggerHaptic };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { BaseBlock, BlockRendererProps as BlockRendererProps$1, BlockRenderers as BlockRenderers$1, OrderingStrategy, CanDragFn, CanDropFn, IdGeneratorFn, SensorConfig, BlockTreeCallbacks, ContainerRendererProps as ContainerRendererProps$1, InternalRenderers as InternalRenderers$1, RendererPropsFor as RendererPropsFor$1, BlockTreeInstance, Rect, CollisionCandidate, CoreCollisionDetection } from '@dnd-block-tree/core';
|
|
2
|
-
export { AnimationConfig, AutoExpandConfig, BaseBlock, BlockAction, BlockAddEvent, BlockDeleteEvent, BlockIndex, BlockMoveEvent, BlockPosition, BlockStateContextValue, BlockTreeCallbacks, BlockTreeConfig, BlockTreeCustomization, BlockTreeEvents, BlockTreeInstance, BlockTreeOptions, CanDragFn, CanDropFn, CollisionCandidate, CollisionResult, CoreCollisionDetection, DragEndEvent, DragMoveEvent, DragStartEvent, DropZoneConfig, DropZoneType, EventEmitter, ExpandAction, ExpandChangeEvent, HistoryAction, HistoryState, HoverChangeEvent, IdGeneratorFn, MoveOperation, NestedBlock, OrderingStrategy, Rect, SensorConfig, SnapshotRectsRef, TreeValidationResult, blockReducer, buildOrderedBlocks, cloneMap, cloneParentMap, closestCenterCollision, compareFractionalKeys, computeNormalizedIndex, createBlockTree, createStickyCollision, debounce, deleteBlockAndDescendants, expandReducer, extractBlockId, extractUUID, flatToNested, generateId, generateInitialKeys, generateKeyBetween, generateNKeysBetween, getBlockDepth, getDescendantIds, getDropZoneType, getSubtreeDepth, historyReducer, initFractionalOrder, nestedToFlat, reparentBlockIndex, reparentMultipleBlocks, validateBlockTree, weightedVerticalCollision } from '@dnd-block-tree/core';
|
|
1
|
+
import { BaseBlock, BlockRendererProps as BlockRendererProps$1, BlockRenderers as BlockRenderers$1, OrderingStrategy, CanDragFn, CanDropFn, IdGeneratorFn, SensorConfig, BlockTreeCallbacks, ContainerRendererProps as ContainerRendererProps$1, InternalRenderers as InternalRenderers$1, RendererPropsFor as RendererPropsFor$1, BlockTreeInstance, Rect, CollisionCandidate, CoreCollisionDetection, MergeBlockVersionsOptions } from '@dnd-block-tree/core';
|
|
2
|
+
export { AnimationConfig, AutoExpandConfig, BaseBlock, BlockAction, BlockAddEvent, BlockDeleteEvent, BlockIndex, BlockMoveEvent, BlockPosition, BlockStateContextValue, BlockTreeCallbacks, BlockTreeConfig, BlockTreeCustomization, BlockTreeEvents, BlockTreeInstance, BlockTreeOptions, CanDragFn, CanDropFn, CollisionCandidate, CollisionResult, CoreCollisionDetection, DragEndEvent, DragMoveEvent, DragStartEvent, DropZoneConfig, DropZoneType, EventEmitter, ExpandAction, ExpandChangeEvent, HistoryAction, HistoryState, HoverChangeEvent, IdGeneratorFn, MergeBlockVersionsOptions, MoveOperation, NestedBlock, OrderingStrategy, Rect, SensorConfig, SnapshotRectsRef, TreeValidationResult, blockReducer, buildOrderedBlocks, cloneMap, cloneParentMap, closestCenterCollision, compareFractionalKeys, computeNormalizedIndex, createBlockTree, createStickyCollision, debounce, deleteBlockAndDescendants, expandReducer, extractBlockId, extractUUID, flatToNested, generateId, generateInitialKeys, generateKeyBetween, generateNKeysBetween, getBlockDepth, getDescendantIds, getDropZoneType, getSubtreeDepth, historyReducer, initFractionalOrder, mergeBlockVersions, nestedToFlat, reparentBlockIndex, reparentMultipleBlocks, validateBlockTree, weightedVerticalCollision } from '@dnd-block-tree/core';
|
|
3
3
|
|
|
4
4
|
type BlockRendererProps<T extends BaseBlock = BaseBlock> = BlockRendererProps$1<T, HTMLElement>;
|
|
5
5
|
type ContainerRendererProps<T extends BaseBlock = BaseBlock> = ContainerRendererProps$1<T, HTMLElement>;
|
|
@@ -54,8 +54,13 @@ interface RenderBlockContext {
|
|
|
54
54
|
/** DefaultRenderer options */
|
|
55
55
|
interface DefaultRendererOptions<T extends BaseBlock = BaseBlock> {
|
|
56
56
|
container: HTMLElement;
|
|
57
|
+
containerTypes?: readonly string[];
|
|
57
58
|
renderBlock: (block: T, ctx: RenderBlockContext) => HTMLElement;
|
|
58
59
|
dropZoneHeight?: number;
|
|
60
|
+
dropZoneClassName?: string;
|
|
61
|
+
dropZoneActiveClassName?: string;
|
|
62
|
+
rootClassName?: string;
|
|
63
|
+
indentClassName?: string;
|
|
59
64
|
animateExpand?: boolean;
|
|
60
65
|
}
|
|
61
66
|
/** Cleanup function */
|
|
@@ -142,6 +147,54 @@ interface BlockHistory<T extends BaseBlock> {
|
|
|
142
147
|
*/
|
|
143
148
|
declare function createBlockHistory<T extends BaseBlock>(initialBlocks: T[], options?: BlockHistoryOptions): BlockHistory<T>;
|
|
144
149
|
|
|
150
|
+
interface DeferredSyncOptions<T extends BaseBlock> {
|
|
151
|
+
/** Called when remote data is applied (only when not busy) */
|
|
152
|
+
onResolve?: (blocks: T[]) => void;
|
|
153
|
+
/** Options passed to mergeBlockVersions when using 'merge' strategy */
|
|
154
|
+
mergeOptions?: MergeBlockVersionsOptions;
|
|
155
|
+
}
|
|
156
|
+
interface DeferredSync<T extends BaseBlock> {
|
|
157
|
+
/** Whether sync is currently deferred */
|
|
158
|
+
isBusy(): boolean;
|
|
159
|
+
/** Apply remote blocks — queues if busy, calls onResolve if idle */
|
|
160
|
+
apply(remoteBlocks: T[]): void;
|
|
161
|
+
/** Enter busy state (call before editing or dragging) */
|
|
162
|
+
enterBusy(): void;
|
|
163
|
+
/**
|
|
164
|
+
* Exit busy state and resolve any queued remote changes.
|
|
165
|
+
* Returns the merged result if a queue existed, null otherwise.
|
|
166
|
+
*/
|
|
167
|
+
exitBusy(localBlocks: T[], strategy: 'merge' | 'lww'): T[] | null;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Imperative deferred sync factory for vanilla JS.
|
|
171
|
+
* Queues remote updates during blocking actions and resolves
|
|
172
|
+
* on exit using merge or last-write-wins strategy.
|
|
173
|
+
*
|
|
174
|
+
* @param options - Configuration including onResolve callback and merge options
|
|
175
|
+
* @returns DeferredSync instance with busy/queue/flush methods
|
|
176
|
+
*
|
|
177
|
+
* @example
|
|
178
|
+
* ```ts
|
|
179
|
+
* const sync = createDeferredSync<MyBlock>({
|
|
180
|
+
* onResolve: (blocks) => controller.setBlocks(blocks),
|
|
181
|
+
* })
|
|
182
|
+
*
|
|
183
|
+
* // In your realtime subscription:
|
|
184
|
+
* socket.on('blocks', (blocks) => sync.apply(blocks))
|
|
185
|
+
*
|
|
186
|
+
* // Drag lifecycle:
|
|
187
|
+
* controller.on('drag:statechange', ({ isDragging }) => {
|
|
188
|
+
* if (isDragging) sync.enterBusy()
|
|
189
|
+
* else {
|
|
190
|
+
* const result = sync.exitBusy(controller.getBlocks(), 'lww')
|
|
191
|
+
* if (result) socket.emit('blocks', result)
|
|
192
|
+
* }
|
|
193
|
+
* })
|
|
194
|
+
* ```
|
|
195
|
+
*/
|
|
196
|
+
declare function createDeferredSync<T extends BaseBlock>(options?: DeferredSyncOptions<T>): DeferredSync<T>;
|
|
197
|
+
|
|
145
198
|
interface LayoutAnimationOptions {
|
|
146
199
|
duration?: number;
|
|
147
200
|
easing?: string;
|
|
@@ -276,6 +329,9 @@ interface TreeRendererOptions<T extends BaseBlock> {
|
|
|
276
329
|
renderBlock: (block: T, ctx: RenderBlockContext) => HTMLElement;
|
|
277
330
|
containerTypes: readonly string[];
|
|
278
331
|
dropZoneHeight?: number;
|
|
332
|
+
dropZoneClassName?: string;
|
|
333
|
+
rootClassName?: string;
|
|
334
|
+
indentClassName?: string;
|
|
279
335
|
}
|
|
280
336
|
/**
|
|
281
337
|
* Recursive DOM tree builder. Creates the full tree DOM from blocks.
|
|
@@ -286,6 +342,7 @@ declare function renderTree<T extends BaseBlock>(blocks: T[], expandedMap: Recor
|
|
|
286
342
|
interface DropZoneOptions {
|
|
287
343
|
id: string;
|
|
288
344
|
height?: number;
|
|
345
|
+
className?: string;
|
|
289
346
|
}
|
|
290
347
|
declare function createDropZoneElement(options: DropZoneOptions): HTMLElement;
|
|
291
348
|
declare function setDropZoneActive(el: HTMLElement, active: boolean): void;
|
|
@@ -311,4 +368,4 @@ declare function createDisposable(): Disposable & {
|
|
|
311
368
|
add(fn: () => void): void;
|
|
312
369
|
};
|
|
313
370
|
|
|
314
|
-
export { type BlockHistory, type BlockHistoryOptions, type BlockRendererProps, type BlockRenderers, type BlockTreeController, type BlockTreeControllerOptions, type ContainerRendererProps, type ControllerEvents, type DefaultRenderer, type DefaultRendererOptions, type Disposable, DragOverlay, type DragOverlayOptions, type DragState, type InternalRenderers, KeyboardSensor, type KeyboardSensorCallbacks, LayoutAnimation, type LayoutAnimationOptions, PointerSensor, type PointerSensorOptions, type RenderBlockContext, type RendererPropsFor, type Sensor, type SensorCallbacks, TouchSensor, type TouchSensorOptions, type TreeRendererOptions, type Unsubscribe, type VanillaSensorConfig, type VirtualRange, VirtualScroller, type VirtualScrollerOptions, buildCandidates, closestWithData, createBlockHistory, createBlockTreeController, createDefaultRenderer, createDisposable, createDropZoneElement, createElement, createGhostPreview, detectCollision, measureDropZoneRects, pointerToRect, renderTree, setDataAttributes, setDropZoneActive, triggerHaptic };
|
|
371
|
+
export { type BlockHistory, type BlockHistoryOptions, type BlockRendererProps, type BlockRenderers, type BlockTreeController, type BlockTreeControllerOptions, type ContainerRendererProps, type ControllerEvents, type DefaultRenderer, type DefaultRendererOptions, type DeferredSync, type DeferredSyncOptions, type Disposable, DragOverlay, type DragOverlayOptions, type DragState, type InternalRenderers, KeyboardSensor, type KeyboardSensorCallbacks, LayoutAnimation, type LayoutAnimationOptions, PointerSensor, type PointerSensorOptions, type RenderBlockContext, type RendererPropsFor, type Sensor, type SensorCallbacks, TouchSensor, type TouchSensorOptions, type TreeRendererOptions, type Unsubscribe, type VanillaSensorConfig, type VirtualRange, VirtualScroller, type VirtualScrollerOptions, buildCandidates, closestWithData, createBlockHistory, createBlockTreeController, createDefaultRenderer, createDeferredSync, createDisposable, createDropZoneElement, createElement, createGhostPreview, detectCollision, measureDropZoneRects, pointerToRect, renderTree, setDataAttributes, setDropZoneActive, triggerHaptic };
|
package/dist/index.js
CHANGED
|
@@ -55,6 +55,8 @@ var DragOverlay = class {
|
|
|
55
55
|
const overlay = document.createElement("div");
|
|
56
56
|
overlay.setAttribute("data-drag-overlay", "true");
|
|
57
57
|
overlay.style.position = "fixed";
|
|
58
|
+
overlay.style.left = "0";
|
|
59
|
+
overlay.style.top = "0";
|
|
58
60
|
overlay.style.zIndex = "9999";
|
|
59
61
|
overlay.style.pointerEvents = "none";
|
|
60
62
|
overlay.style.opacity = "0.7";
|
|
@@ -380,11 +382,11 @@ function createBlockTreeController(options = {}) {
|
|
|
380
382
|
const draggableElements = /* @__PURE__ */ new Map();
|
|
381
383
|
const dropZoneElements = /* @__PURE__ */ new Map();
|
|
382
384
|
let snapshotRects = null;
|
|
385
|
+
let dragFromPosition = null;
|
|
383
386
|
const selectedIds = /* @__PURE__ */ new Set();
|
|
384
387
|
let lastSelectedId = null;
|
|
385
388
|
const activeSensors = [];
|
|
386
|
-
|
|
387
|
-
let overlayRenderer = null;
|
|
389
|
+
let overlay = new DragOverlay();
|
|
388
390
|
let history = null;
|
|
389
391
|
tree.on("blocks:change", (blocks) => {
|
|
390
392
|
onChange?.(blocks);
|
|
@@ -417,18 +419,26 @@ function createBlockTreeController(options = {}) {
|
|
|
417
419
|
const sensorCallbacks = {
|
|
418
420
|
onDragStart(blockId, x, y) {
|
|
419
421
|
const draggedIds = selectedIds.has(blockId) && selectedIds.size > 1 ? [...selectedIds] : [blockId];
|
|
422
|
+
const blocks = tree.getBlocks();
|
|
423
|
+
const dragBlock = blocks.find((b) => b.id === blockId);
|
|
424
|
+
if (dragBlock) {
|
|
425
|
+
const siblings = blocks.filter((b) => b.parentId === dragBlock.parentId);
|
|
426
|
+
dragFromPosition = {
|
|
427
|
+
parentId: dragBlock.parentId,
|
|
428
|
+
index: siblings.findIndex((b) => b.id === blockId)
|
|
429
|
+
};
|
|
430
|
+
}
|
|
420
431
|
const started = tree.startDrag(blockId, draggedIds);
|
|
421
|
-
if (!started)
|
|
432
|
+
if (!started) {
|
|
433
|
+
dragFromPosition = null;
|
|
434
|
+
return;
|
|
435
|
+
}
|
|
422
436
|
stickyCollision.reset();
|
|
423
437
|
snapshotRects = measureDropZoneRects(dropZoneElements);
|
|
424
438
|
const block = tree.getBlock(blockId);
|
|
425
439
|
const el = draggableElements.get(blockId);
|
|
426
440
|
if (block && el) {
|
|
427
|
-
|
|
428
|
-
overlay.show(block, el, x, y);
|
|
429
|
-
} else {
|
|
430
|
-
overlay.show(block, el, x, y);
|
|
431
|
-
}
|
|
441
|
+
overlay.show(block, el, x, y);
|
|
432
442
|
}
|
|
433
443
|
emitter.emit("drag:statechange", getDragState());
|
|
434
444
|
},
|
|
@@ -439,22 +449,35 @@ function createBlockTreeController(options = {}) {
|
|
|
439
449
|
if (!detector) return;
|
|
440
450
|
const targetZone = detectCollision(detector, snapshotRects, x, y);
|
|
441
451
|
if (targetZone) {
|
|
452
|
+
const prevHover = tree.getHoverZone();
|
|
442
453
|
tree.updateDrag(targetZone);
|
|
454
|
+
if (tree.getHoverZone() !== prevHover) {
|
|
455
|
+
emitter.emit("drag:statechange", getDragState());
|
|
456
|
+
}
|
|
443
457
|
}
|
|
444
458
|
},
|
|
445
459
|
onDragEnd(_x, _y) {
|
|
460
|
+
const draggedBlockIds = selectedIds.size > 1 ? [...selectedIds] : [];
|
|
461
|
+
const activeDragId = tree.getActiveId();
|
|
446
462
|
const result = tree.endDrag();
|
|
447
463
|
overlay.hide();
|
|
448
464
|
snapshotRects = null;
|
|
449
|
-
if (result && callbacks?.onBlockMove) {
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
465
|
+
if (result && callbacks?.onBlockMove && activeDragId) {
|
|
466
|
+
const movedBlock = result.blocks.find((b) => b.id === activeDragId);
|
|
467
|
+
const movedIds = draggedBlockIds.length > 0 ? draggedBlockIds : activeDragId ? [activeDragId] : [];
|
|
468
|
+
if (movedBlock) {
|
|
469
|
+
const siblings = result.blocks.filter((b) => b.parentId === movedBlock.parentId);
|
|
470
|
+
const toIndex = siblings.findIndex((b) => b.id === activeDragId);
|
|
471
|
+
callbacks.onBlockMove({
|
|
472
|
+
block: movedBlock,
|
|
473
|
+
from: dragFromPosition ?? { parentId: null, index: 0 },
|
|
474
|
+
to: { parentId: movedBlock.parentId, index: toIndex },
|
|
475
|
+
blocks: result.blocks,
|
|
476
|
+
movedIds
|
|
477
|
+
});
|
|
478
|
+
}
|
|
457
479
|
}
|
|
480
|
+
dragFromPosition = null;
|
|
458
481
|
emitter.emit("drag:statechange", getDragState());
|
|
459
482
|
emitter.emit("render", tree.getBlocks(), tree.getExpandedMap());
|
|
460
483
|
},
|
|
@@ -658,7 +681,7 @@ function createBlockTreeController(options = {}) {
|
|
|
658
681
|
return emitter.on(event, handler);
|
|
659
682
|
},
|
|
660
683
|
setOverlayRenderer(render) {
|
|
661
|
-
|
|
684
|
+
overlay = new DragOverlay({ renderOverlay: render });
|
|
662
685
|
},
|
|
663
686
|
getTree: () => tree,
|
|
664
687
|
destroy() {
|
|
@@ -673,6 +696,33 @@ function createBlockTreeController(options = {}) {
|
|
|
673
696
|
};
|
|
674
697
|
return controller;
|
|
675
698
|
}
|
|
699
|
+
function createDeferredSync(options) {
|
|
700
|
+
let busy = false;
|
|
701
|
+
let queue = null;
|
|
702
|
+
return {
|
|
703
|
+
isBusy: () => busy,
|
|
704
|
+
apply(remoteBlocks) {
|
|
705
|
+
if (busy) {
|
|
706
|
+
queue = remoteBlocks;
|
|
707
|
+
} else {
|
|
708
|
+
options?.onResolve?.(remoteBlocks);
|
|
709
|
+
}
|
|
710
|
+
},
|
|
711
|
+
enterBusy() {
|
|
712
|
+
busy = true;
|
|
713
|
+
},
|
|
714
|
+
exitBusy(localBlocks, strategy) {
|
|
715
|
+
busy = false;
|
|
716
|
+
const queued = queue;
|
|
717
|
+
queue = null;
|
|
718
|
+
if (!queued) return null;
|
|
719
|
+
if (strategy === "lww") {
|
|
720
|
+
return localBlocks;
|
|
721
|
+
}
|
|
722
|
+
return core.mergeBlockVersions(localBlocks, queued, options?.mergeOptions);
|
|
723
|
+
}
|
|
724
|
+
};
|
|
725
|
+
}
|
|
676
726
|
|
|
677
727
|
// src/layout-animation.ts
|
|
678
728
|
var LayoutAnimation = class {
|
|
@@ -748,14 +798,18 @@ var VirtualScroller = class {
|
|
|
748
798
|
|
|
749
799
|
// src/renderer/drop-zone.ts
|
|
750
800
|
function createDropZoneElement(options) {
|
|
751
|
-
const { id, height = 4 } = options;
|
|
801
|
+
const { id, height = 4, className } = options;
|
|
752
802
|
const el = createElement("div");
|
|
753
803
|
setDataAttributes(el, {
|
|
754
804
|
"zone-id": id
|
|
755
805
|
});
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
806
|
+
if (className) {
|
|
807
|
+
el.className = className;
|
|
808
|
+
} else {
|
|
809
|
+
el.style.height = `${height}px`;
|
|
810
|
+
el.style.minHeight = `${height}px`;
|
|
811
|
+
el.style.transition = "background-color 150ms ease";
|
|
812
|
+
}
|
|
759
813
|
return el;
|
|
760
814
|
}
|
|
761
815
|
function setDropZoneActive(el, active) {
|
|
@@ -764,29 +818,32 @@ function setDropZoneActive(el, active) {
|
|
|
764
818
|
|
|
765
819
|
// src/renderer/tree-renderer.ts
|
|
766
820
|
function renderTree(blocks, expandedMap, controller, options, parentId = null, depth = 0) {
|
|
767
|
-
const { renderBlock, containerTypes, dropZoneHeight } = options;
|
|
821
|
+
const { renderBlock, containerTypes, dropZoneHeight, dropZoneClassName, rootClassName, indentClassName } = options;
|
|
768
822
|
const container = createElement("div", {
|
|
769
823
|
role: parentId === null ? "tree" : "group"
|
|
770
824
|
});
|
|
771
825
|
if (parentId === null) {
|
|
772
826
|
container.setAttribute("data-dnd-tree-root", "true");
|
|
827
|
+
if (rootClassName) container.className = rootClassName;
|
|
828
|
+
} else {
|
|
829
|
+
if (indentClassName) container.className = indentClassName;
|
|
773
830
|
}
|
|
774
831
|
const children = blocks.filter((b) => b.parentId === parentId);
|
|
775
832
|
const activeId = controller.getDragState().activeId;
|
|
776
833
|
const selectedIds = controller.getSelectedIds();
|
|
777
834
|
const index = controller.getTree().getBlockIndex();
|
|
778
835
|
if (parentId !== null) {
|
|
779
|
-
const startZone = createDropZoneElement({ id: `into-${parentId}`, height: dropZoneHeight });
|
|
836
|
+
const startZone = createDropZoneElement({ id: `into-${parentId}`, height: dropZoneHeight, className: dropZoneClassName });
|
|
780
837
|
controller.registerDropZone(`into-${parentId}`, startZone);
|
|
781
838
|
container.appendChild(startZone);
|
|
782
839
|
} else {
|
|
783
|
-
const rootStart = createDropZoneElement({ id: "root-start", height: dropZoneHeight });
|
|
840
|
+
const rootStart = createDropZoneElement({ id: "root-start", height: dropZoneHeight, className: dropZoneClassName });
|
|
784
841
|
controller.registerDropZone("root-start", rootStart);
|
|
785
842
|
container.appendChild(rootStart);
|
|
786
843
|
}
|
|
787
844
|
for (const block of children) {
|
|
788
845
|
if (block.id === activeId) continue;
|
|
789
|
-
const beforeZone = createDropZoneElement({ id: `before-${block.id}`, height: dropZoneHeight });
|
|
846
|
+
const beforeZone = createDropZoneElement({ id: `before-${block.id}`, height: dropZoneHeight, className: dropZoneClassName });
|
|
790
847
|
controller.registerDropZone(`before-${block.id}`, beforeZone);
|
|
791
848
|
container.appendChild(beforeZone);
|
|
792
849
|
const isContainer = containerTypes.includes(block.type);
|
|
@@ -822,11 +879,11 @@ function renderTree(blocks, expandedMap, controller, options, parentId = null, d
|
|
|
822
879
|
container.appendChild(blockEl);
|
|
823
880
|
}
|
|
824
881
|
if (parentId !== null) {
|
|
825
|
-
const endZone = createDropZoneElement({ id: `end-${parentId}`, height: dropZoneHeight });
|
|
882
|
+
const endZone = createDropZoneElement({ id: `end-${parentId}`, height: dropZoneHeight, className: dropZoneClassName });
|
|
826
883
|
controller.registerDropZone(`end-${parentId}`, endZone);
|
|
827
884
|
container.appendChild(endZone);
|
|
828
885
|
} else {
|
|
829
|
-
const rootEnd = createDropZoneElement({ id: "root-end", height: dropZoneHeight });
|
|
886
|
+
const rootEnd = createDropZoneElement({ id: "root-end", height: dropZoneHeight, className: dropZoneClassName });
|
|
830
887
|
controller.registerDropZone("root-end", rootEnd);
|
|
831
888
|
container.appendChild(rootEnd);
|
|
832
889
|
}
|
|
@@ -835,21 +892,47 @@ function renderTree(blocks, expandedMap, controller, options, parentId = null, d
|
|
|
835
892
|
|
|
836
893
|
// src/renderer/default-renderer.ts
|
|
837
894
|
function createDefaultRenderer(controller, options) {
|
|
838
|
-
const { container, renderBlock, dropZoneHeight,
|
|
839
|
-
const containerTypes = controller.getTree().containerTypes ?? [];
|
|
895
|
+
const { container, containerTypes: explicitContainerTypes, renderBlock, dropZoneHeight, dropZoneClassName, dropZoneActiveClassName } = options;
|
|
896
|
+
const containerTypes = explicitContainerTypes ?? controller.getTree().containerTypes ?? [];
|
|
897
|
+
const activeClasses = dropZoneActiveClassName?.split(/\s+/).filter(Boolean) ?? [];
|
|
840
898
|
function render(blocks, expandedMap) {
|
|
841
|
-
container.
|
|
899
|
+
while (container.firstChild) container.removeChild(container.firstChild);
|
|
842
900
|
const tree = renderTree(blocks, expandedMap, controller, {
|
|
843
901
|
renderBlock,
|
|
844
902
|
containerTypes,
|
|
845
|
-
dropZoneHeight
|
|
903
|
+
dropZoneHeight,
|
|
904
|
+
dropZoneClassName,
|
|
905
|
+
rootClassName: options.rootClassName,
|
|
906
|
+
indentClassName: options.indentClassName
|
|
846
907
|
});
|
|
847
908
|
container.appendChild(tree);
|
|
848
909
|
}
|
|
910
|
+
let activeZoneEl = null;
|
|
911
|
+
function onDragStateChange(state) {
|
|
912
|
+
if (activeZoneEl) {
|
|
913
|
+
setDropZoneActive(activeZoneEl, false);
|
|
914
|
+
if (activeClasses.length) {
|
|
915
|
+
activeZoneEl.classList.remove(...activeClasses);
|
|
916
|
+
}
|
|
917
|
+
activeZoneEl = null;
|
|
918
|
+
}
|
|
919
|
+
if (state.isDragging && state.hoverZone) {
|
|
920
|
+
const zoneEl = container.querySelector(`[data-zone-id="${state.hoverZone}"]`);
|
|
921
|
+
if (zoneEl) {
|
|
922
|
+
setDropZoneActive(zoneEl, true);
|
|
923
|
+
if (activeClasses.length) {
|
|
924
|
+
zoneEl.classList.add(...activeClasses);
|
|
925
|
+
}
|
|
926
|
+
activeZoneEl = zoneEl;
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
}
|
|
849
930
|
const unsubRender = controller.on("render", render);
|
|
931
|
+
const unsubDrag = controller.on("drag:statechange", onDragStateChange);
|
|
850
932
|
render(controller.getBlocks(), controller.getExpandedMap());
|
|
851
933
|
const renderer = () => {
|
|
852
934
|
unsubRender();
|
|
935
|
+
unsubDrag();
|
|
853
936
|
};
|
|
854
937
|
renderer.refresh = () => {
|
|
855
938
|
render(controller.getBlocks(), controller.getExpandedMap());
|
|
@@ -988,6 +1071,10 @@ Object.defineProperty(exports, "initFractionalOrder", {
|
|
|
988
1071
|
enumerable: true,
|
|
989
1072
|
get: function () { return core.initFractionalOrder; }
|
|
990
1073
|
});
|
|
1074
|
+
Object.defineProperty(exports, "mergeBlockVersions", {
|
|
1075
|
+
enumerable: true,
|
|
1076
|
+
get: function () { return core.mergeBlockVersions; }
|
|
1077
|
+
});
|
|
991
1078
|
Object.defineProperty(exports, "nestedToFlat", {
|
|
992
1079
|
enumerable: true,
|
|
993
1080
|
get: function () { return core.nestedToFlat; }
|
|
@@ -1019,6 +1106,7 @@ exports.closestWithData = closestWithData;
|
|
|
1019
1106
|
exports.createBlockHistory = createBlockHistory;
|
|
1020
1107
|
exports.createBlockTreeController = createBlockTreeController;
|
|
1021
1108
|
exports.createDefaultRenderer = createDefaultRenderer;
|
|
1109
|
+
exports.createDeferredSync = createDeferredSync;
|
|
1022
1110
|
exports.createDisposable = createDisposable;
|
|
1023
1111
|
exports.createDropZoneElement = createDropZoneElement;
|
|
1024
1112
|
exports.createElement = createElement;
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { historyReducer, createStickyCollision, createBlockTree, EventEmitter, getBlockDepth } from '@dnd-block-tree/core';
|
|
2
|
-
export { EventEmitter, blockReducer, buildOrderedBlocks, cloneMap, cloneParentMap, closestCenterCollision, compareFractionalKeys, computeNormalizedIndex, createBlockTree, createStickyCollision, debounce, deleteBlockAndDescendants, expandReducer, extractBlockId, extractUUID, flatToNested, generateId, generateInitialKeys, generateKeyBetween, generateNKeysBetween, getBlockDepth, getDescendantIds, getDropZoneType, getSubtreeDepth, historyReducer, initFractionalOrder, nestedToFlat, reparentBlockIndex, reparentMultipleBlocks, validateBlockTree, weightedVerticalCollision } from '@dnd-block-tree/core';
|
|
1
|
+
import { historyReducer, createStickyCollision, createBlockTree, EventEmitter, mergeBlockVersions, getBlockDepth } from '@dnd-block-tree/core';
|
|
2
|
+
export { EventEmitter, blockReducer, buildOrderedBlocks, cloneMap, cloneParentMap, closestCenterCollision, compareFractionalKeys, computeNormalizedIndex, createBlockTree, createStickyCollision, debounce, deleteBlockAndDescendants, expandReducer, extractBlockId, extractUUID, flatToNested, generateId, generateInitialKeys, generateKeyBetween, generateNKeysBetween, getBlockDepth, getDescendantIds, getDropZoneType, getSubtreeDepth, historyReducer, initFractionalOrder, mergeBlockVersions, nestedToFlat, reparentBlockIndex, reparentMultipleBlocks, validateBlockTree, weightedVerticalCollision } from '@dnd-block-tree/core';
|
|
3
3
|
|
|
4
4
|
// src/index.ts
|
|
5
5
|
|
|
@@ -54,6 +54,8 @@ var DragOverlay = class {
|
|
|
54
54
|
const overlay = document.createElement("div");
|
|
55
55
|
overlay.setAttribute("data-drag-overlay", "true");
|
|
56
56
|
overlay.style.position = "fixed";
|
|
57
|
+
overlay.style.left = "0";
|
|
58
|
+
overlay.style.top = "0";
|
|
57
59
|
overlay.style.zIndex = "9999";
|
|
58
60
|
overlay.style.pointerEvents = "none";
|
|
59
61
|
overlay.style.opacity = "0.7";
|
|
@@ -379,11 +381,11 @@ function createBlockTreeController(options = {}) {
|
|
|
379
381
|
const draggableElements = /* @__PURE__ */ new Map();
|
|
380
382
|
const dropZoneElements = /* @__PURE__ */ new Map();
|
|
381
383
|
let snapshotRects = null;
|
|
384
|
+
let dragFromPosition = null;
|
|
382
385
|
const selectedIds = /* @__PURE__ */ new Set();
|
|
383
386
|
let lastSelectedId = null;
|
|
384
387
|
const activeSensors = [];
|
|
385
|
-
|
|
386
|
-
let overlayRenderer = null;
|
|
388
|
+
let overlay = new DragOverlay();
|
|
387
389
|
let history = null;
|
|
388
390
|
tree.on("blocks:change", (blocks) => {
|
|
389
391
|
onChange?.(blocks);
|
|
@@ -416,18 +418,26 @@ function createBlockTreeController(options = {}) {
|
|
|
416
418
|
const sensorCallbacks = {
|
|
417
419
|
onDragStart(blockId, x, y) {
|
|
418
420
|
const draggedIds = selectedIds.has(blockId) && selectedIds.size > 1 ? [...selectedIds] : [blockId];
|
|
421
|
+
const blocks = tree.getBlocks();
|
|
422
|
+
const dragBlock = blocks.find((b) => b.id === blockId);
|
|
423
|
+
if (dragBlock) {
|
|
424
|
+
const siblings = blocks.filter((b) => b.parentId === dragBlock.parentId);
|
|
425
|
+
dragFromPosition = {
|
|
426
|
+
parentId: dragBlock.parentId,
|
|
427
|
+
index: siblings.findIndex((b) => b.id === blockId)
|
|
428
|
+
};
|
|
429
|
+
}
|
|
419
430
|
const started = tree.startDrag(blockId, draggedIds);
|
|
420
|
-
if (!started)
|
|
431
|
+
if (!started) {
|
|
432
|
+
dragFromPosition = null;
|
|
433
|
+
return;
|
|
434
|
+
}
|
|
421
435
|
stickyCollision.reset();
|
|
422
436
|
snapshotRects = measureDropZoneRects(dropZoneElements);
|
|
423
437
|
const block = tree.getBlock(blockId);
|
|
424
438
|
const el = draggableElements.get(blockId);
|
|
425
439
|
if (block && el) {
|
|
426
|
-
|
|
427
|
-
overlay.show(block, el, x, y);
|
|
428
|
-
} else {
|
|
429
|
-
overlay.show(block, el, x, y);
|
|
430
|
-
}
|
|
440
|
+
overlay.show(block, el, x, y);
|
|
431
441
|
}
|
|
432
442
|
emitter.emit("drag:statechange", getDragState());
|
|
433
443
|
},
|
|
@@ -438,22 +448,35 @@ function createBlockTreeController(options = {}) {
|
|
|
438
448
|
if (!detector) return;
|
|
439
449
|
const targetZone = detectCollision(detector, snapshotRects, x, y);
|
|
440
450
|
if (targetZone) {
|
|
451
|
+
const prevHover = tree.getHoverZone();
|
|
441
452
|
tree.updateDrag(targetZone);
|
|
453
|
+
if (tree.getHoverZone() !== prevHover) {
|
|
454
|
+
emitter.emit("drag:statechange", getDragState());
|
|
455
|
+
}
|
|
442
456
|
}
|
|
443
457
|
},
|
|
444
458
|
onDragEnd(_x, _y) {
|
|
459
|
+
const draggedBlockIds = selectedIds.size > 1 ? [...selectedIds] : [];
|
|
460
|
+
const activeDragId = tree.getActiveId();
|
|
445
461
|
const result = tree.endDrag();
|
|
446
462
|
overlay.hide();
|
|
447
463
|
snapshotRects = null;
|
|
448
|
-
if (result && callbacks?.onBlockMove) {
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
464
|
+
if (result && callbacks?.onBlockMove && activeDragId) {
|
|
465
|
+
const movedBlock = result.blocks.find((b) => b.id === activeDragId);
|
|
466
|
+
const movedIds = draggedBlockIds.length > 0 ? draggedBlockIds : activeDragId ? [activeDragId] : [];
|
|
467
|
+
if (movedBlock) {
|
|
468
|
+
const siblings = result.blocks.filter((b) => b.parentId === movedBlock.parentId);
|
|
469
|
+
const toIndex = siblings.findIndex((b) => b.id === activeDragId);
|
|
470
|
+
callbacks.onBlockMove({
|
|
471
|
+
block: movedBlock,
|
|
472
|
+
from: dragFromPosition ?? { parentId: null, index: 0 },
|
|
473
|
+
to: { parentId: movedBlock.parentId, index: toIndex },
|
|
474
|
+
blocks: result.blocks,
|
|
475
|
+
movedIds
|
|
476
|
+
});
|
|
477
|
+
}
|
|
456
478
|
}
|
|
479
|
+
dragFromPosition = null;
|
|
457
480
|
emitter.emit("drag:statechange", getDragState());
|
|
458
481
|
emitter.emit("render", tree.getBlocks(), tree.getExpandedMap());
|
|
459
482
|
},
|
|
@@ -657,7 +680,7 @@ function createBlockTreeController(options = {}) {
|
|
|
657
680
|
return emitter.on(event, handler);
|
|
658
681
|
},
|
|
659
682
|
setOverlayRenderer(render) {
|
|
660
|
-
|
|
683
|
+
overlay = new DragOverlay({ renderOverlay: render });
|
|
661
684
|
},
|
|
662
685
|
getTree: () => tree,
|
|
663
686
|
destroy() {
|
|
@@ -672,6 +695,33 @@ function createBlockTreeController(options = {}) {
|
|
|
672
695
|
};
|
|
673
696
|
return controller;
|
|
674
697
|
}
|
|
698
|
+
function createDeferredSync(options) {
|
|
699
|
+
let busy = false;
|
|
700
|
+
let queue = null;
|
|
701
|
+
return {
|
|
702
|
+
isBusy: () => busy,
|
|
703
|
+
apply(remoteBlocks) {
|
|
704
|
+
if (busy) {
|
|
705
|
+
queue = remoteBlocks;
|
|
706
|
+
} else {
|
|
707
|
+
options?.onResolve?.(remoteBlocks);
|
|
708
|
+
}
|
|
709
|
+
},
|
|
710
|
+
enterBusy() {
|
|
711
|
+
busy = true;
|
|
712
|
+
},
|
|
713
|
+
exitBusy(localBlocks, strategy) {
|
|
714
|
+
busy = false;
|
|
715
|
+
const queued = queue;
|
|
716
|
+
queue = null;
|
|
717
|
+
if (!queued) return null;
|
|
718
|
+
if (strategy === "lww") {
|
|
719
|
+
return localBlocks;
|
|
720
|
+
}
|
|
721
|
+
return mergeBlockVersions(localBlocks, queued, options?.mergeOptions);
|
|
722
|
+
}
|
|
723
|
+
};
|
|
724
|
+
}
|
|
675
725
|
|
|
676
726
|
// src/layout-animation.ts
|
|
677
727
|
var LayoutAnimation = class {
|
|
@@ -747,14 +797,18 @@ var VirtualScroller = class {
|
|
|
747
797
|
|
|
748
798
|
// src/renderer/drop-zone.ts
|
|
749
799
|
function createDropZoneElement(options) {
|
|
750
|
-
const { id, height = 4 } = options;
|
|
800
|
+
const { id, height = 4, className } = options;
|
|
751
801
|
const el = createElement("div");
|
|
752
802
|
setDataAttributes(el, {
|
|
753
803
|
"zone-id": id
|
|
754
804
|
});
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
805
|
+
if (className) {
|
|
806
|
+
el.className = className;
|
|
807
|
+
} else {
|
|
808
|
+
el.style.height = `${height}px`;
|
|
809
|
+
el.style.minHeight = `${height}px`;
|
|
810
|
+
el.style.transition = "background-color 150ms ease";
|
|
811
|
+
}
|
|
758
812
|
return el;
|
|
759
813
|
}
|
|
760
814
|
function setDropZoneActive(el, active) {
|
|
@@ -763,29 +817,32 @@ function setDropZoneActive(el, active) {
|
|
|
763
817
|
|
|
764
818
|
// src/renderer/tree-renderer.ts
|
|
765
819
|
function renderTree(blocks, expandedMap, controller, options, parentId = null, depth = 0) {
|
|
766
|
-
const { renderBlock, containerTypes, dropZoneHeight } = options;
|
|
820
|
+
const { renderBlock, containerTypes, dropZoneHeight, dropZoneClassName, rootClassName, indentClassName } = options;
|
|
767
821
|
const container = createElement("div", {
|
|
768
822
|
role: parentId === null ? "tree" : "group"
|
|
769
823
|
});
|
|
770
824
|
if (parentId === null) {
|
|
771
825
|
container.setAttribute("data-dnd-tree-root", "true");
|
|
826
|
+
if (rootClassName) container.className = rootClassName;
|
|
827
|
+
} else {
|
|
828
|
+
if (indentClassName) container.className = indentClassName;
|
|
772
829
|
}
|
|
773
830
|
const children = blocks.filter((b) => b.parentId === parentId);
|
|
774
831
|
const activeId = controller.getDragState().activeId;
|
|
775
832
|
const selectedIds = controller.getSelectedIds();
|
|
776
833
|
const index = controller.getTree().getBlockIndex();
|
|
777
834
|
if (parentId !== null) {
|
|
778
|
-
const startZone = createDropZoneElement({ id: `into-${parentId}`, height: dropZoneHeight });
|
|
835
|
+
const startZone = createDropZoneElement({ id: `into-${parentId}`, height: dropZoneHeight, className: dropZoneClassName });
|
|
779
836
|
controller.registerDropZone(`into-${parentId}`, startZone);
|
|
780
837
|
container.appendChild(startZone);
|
|
781
838
|
} else {
|
|
782
|
-
const rootStart = createDropZoneElement({ id: "root-start", height: dropZoneHeight });
|
|
839
|
+
const rootStart = createDropZoneElement({ id: "root-start", height: dropZoneHeight, className: dropZoneClassName });
|
|
783
840
|
controller.registerDropZone("root-start", rootStart);
|
|
784
841
|
container.appendChild(rootStart);
|
|
785
842
|
}
|
|
786
843
|
for (const block of children) {
|
|
787
844
|
if (block.id === activeId) continue;
|
|
788
|
-
const beforeZone = createDropZoneElement({ id: `before-${block.id}`, height: dropZoneHeight });
|
|
845
|
+
const beforeZone = createDropZoneElement({ id: `before-${block.id}`, height: dropZoneHeight, className: dropZoneClassName });
|
|
789
846
|
controller.registerDropZone(`before-${block.id}`, beforeZone);
|
|
790
847
|
container.appendChild(beforeZone);
|
|
791
848
|
const isContainer = containerTypes.includes(block.type);
|
|
@@ -821,11 +878,11 @@ function renderTree(blocks, expandedMap, controller, options, parentId = null, d
|
|
|
821
878
|
container.appendChild(blockEl);
|
|
822
879
|
}
|
|
823
880
|
if (parentId !== null) {
|
|
824
|
-
const endZone = createDropZoneElement({ id: `end-${parentId}`, height: dropZoneHeight });
|
|
881
|
+
const endZone = createDropZoneElement({ id: `end-${parentId}`, height: dropZoneHeight, className: dropZoneClassName });
|
|
825
882
|
controller.registerDropZone(`end-${parentId}`, endZone);
|
|
826
883
|
container.appendChild(endZone);
|
|
827
884
|
} else {
|
|
828
|
-
const rootEnd = createDropZoneElement({ id: "root-end", height: dropZoneHeight });
|
|
885
|
+
const rootEnd = createDropZoneElement({ id: "root-end", height: dropZoneHeight, className: dropZoneClassName });
|
|
829
886
|
controller.registerDropZone("root-end", rootEnd);
|
|
830
887
|
container.appendChild(rootEnd);
|
|
831
888
|
}
|
|
@@ -834,21 +891,47 @@ function renderTree(blocks, expandedMap, controller, options, parentId = null, d
|
|
|
834
891
|
|
|
835
892
|
// src/renderer/default-renderer.ts
|
|
836
893
|
function createDefaultRenderer(controller, options) {
|
|
837
|
-
const { container, renderBlock, dropZoneHeight,
|
|
838
|
-
const containerTypes = controller.getTree().containerTypes ?? [];
|
|
894
|
+
const { container, containerTypes: explicitContainerTypes, renderBlock, dropZoneHeight, dropZoneClassName, dropZoneActiveClassName } = options;
|
|
895
|
+
const containerTypes = explicitContainerTypes ?? controller.getTree().containerTypes ?? [];
|
|
896
|
+
const activeClasses = dropZoneActiveClassName?.split(/\s+/).filter(Boolean) ?? [];
|
|
839
897
|
function render(blocks, expandedMap) {
|
|
840
|
-
container.
|
|
898
|
+
while (container.firstChild) container.removeChild(container.firstChild);
|
|
841
899
|
const tree = renderTree(blocks, expandedMap, controller, {
|
|
842
900
|
renderBlock,
|
|
843
901
|
containerTypes,
|
|
844
|
-
dropZoneHeight
|
|
902
|
+
dropZoneHeight,
|
|
903
|
+
dropZoneClassName,
|
|
904
|
+
rootClassName: options.rootClassName,
|
|
905
|
+
indentClassName: options.indentClassName
|
|
845
906
|
});
|
|
846
907
|
container.appendChild(tree);
|
|
847
908
|
}
|
|
909
|
+
let activeZoneEl = null;
|
|
910
|
+
function onDragStateChange(state) {
|
|
911
|
+
if (activeZoneEl) {
|
|
912
|
+
setDropZoneActive(activeZoneEl, false);
|
|
913
|
+
if (activeClasses.length) {
|
|
914
|
+
activeZoneEl.classList.remove(...activeClasses);
|
|
915
|
+
}
|
|
916
|
+
activeZoneEl = null;
|
|
917
|
+
}
|
|
918
|
+
if (state.isDragging && state.hoverZone) {
|
|
919
|
+
const zoneEl = container.querySelector(`[data-zone-id="${state.hoverZone}"]`);
|
|
920
|
+
if (zoneEl) {
|
|
921
|
+
setDropZoneActive(zoneEl, true);
|
|
922
|
+
if (activeClasses.length) {
|
|
923
|
+
zoneEl.classList.add(...activeClasses);
|
|
924
|
+
}
|
|
925
|
+
activeZoneEl = zoneEl;
|
|
926
|
+
}
|
|
927
|
+
}
|
|
928
|
+
}
|
|
848
929
|
const unsubRender = controller.on("render", render);
|
|
930
|
+
const unsubDrag = controller.on("drag:statechange", onDragStateChange);
|
|
849
931
|
render(controller.getBlocks(), controller.getExpandedMap());
|
|
850
932
|
const renderer = () => {
|
|
851
933
|
unsubRender();
|
|
934
|
+
unsubDrag();
|
|
852
935
|
};
|
|
853
936
|
renderer.refresh = () => {
|
|
854
937
|
render(controller.getBlocks(), controller.getExpandedMap());
|
|
@@ -883,4 +966,4 @@ function createDisposable() {
|
|
|
883
966
|
};
|
|
884
967
|
}
|
|
885
968
|
|
|
886
|
-
export { DragOverlay, KeyboardSensor, LayoutAnimation, PointerSensor, TouchSensor, VirtualScroller, buildCandidates, closestWithData, createBlockHistory, createBlockTreeController, createDefaultRenderer, createDisposable, createDropZoneElement, createElement, createGhostPreview, detectCollision, measureDropZoneRects, pointerToRect, renderTree, setDataAttributes, setDropZoneActive, triggerHaptic };
|
|
969
|
+
export { DragOverlay, KeyboardSensor, LayoutAnimation, PointerSensor, TouchSensor, VirtualScroller, buildCandidates, closestWithData, createBlockHistory, createBlockTreeController, createDefaultRenderer, createDeferredSync, createDisposable, createDropZoneElement, createElement, createGhostPreview, detectCollision, measureDropZoneRects, pointerToRect, renderTree, setDataAttributes, setDropZoneActive, triggerHaptic };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dnd-block-tree/vanilla",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.0",
|
|
4
4
|
"description": "Vanilla JS/TS adapter for dnd-block-tree — zero framework dependencies",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -50,5 +50,9 @@
|
|
|
50
50
|
"vanilla",
|
|
51
51
|
"headless",
|
|
52
52
|
"hierarchical"
|
|
53
|
-
]
|
|
53
|
+
],
|
|
54
|
+
"publishConfig": {
|
|
55
|
+
"access": "public",
|
|
56
|
+
"provenance": true
|
|
57
|
+
}
|
|
54
58
|
}
|