@dnd-block-tree/svelte 2.1.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 +62 -0
- package/dist/bridge.d.ts +13 -0
- package/dist/bridge.d.ts.map +1 -0
- package/dist/bridge.js +55 -0
- package/dist/components/BlockTree.svelte +368 -0
- package/dist/components/BlockTree.svelte.d.ts +32 -0
- package/dist/components/BlockTree.svelte.d.ts.map +1 -0
- package/dist/components/BlockTreeDevTools.svelte +54 -0
- package/dist/components/BlockTreeDevTools.svelte.d.ts +12 -0
- package/dist/components/BlockTreeDevTools.svelte.d.ts.map +1 -0
- package/dist/components/BlockTreeSSR.svelte +22 -0
- package/dist/components/BlockTreeSSR.svelte.d.ts +9 -0
- package/dist/components/BlockTreeSSR.svelte.d.ts.map +1 -0
- package/dist/components/DragOverlay.svelte +48 -0
- package/dist/components/DragOverlay.svelte.d.ts +11 -0
- package/dist/components/DragOverlay.svelte.d.ts.map +1 -0
- package/dist/components/DraggableBlock.svelte +43 -0
- package/dist/components/DraggableBlock.svelte.d.ts +17 -0
- package/dist/components/DraggableBlock.svelte.d.ts.map +1 -0
- package/dist/components/DropZone.svelte +50 -0
- package/dist/components/DropZone.svelte.d.ts +13 -0
- package/dist/components/DropZone.svelte.d.ts.map +1 -0
- package/dist/components/GhostPreview.svelte +13 -0
- package/dist/components/GhostPreview.svelte.d.ts +8 -0
- package/dist/components/GhostPreview.svelte.d.ts.map +1 -0
- package/dist/components/TreeRenderer.svelte +197 -0
- package/dist/components/TreeRenderer.svelte.d.ts +35 -0
- package/dist/components/TreeRenderer.svelte.d.ts.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20 -0
- package/dist/state/block-history.svelte.d.ts +18 -0
- package/dist/state/block-history.svelte.d.ts.map +1 -0
- package/dist/state/block-history.svelte.js +30 -0
- package/dist/state/block-state.svelte.d.ts +27 -0
- package/dist/state/block-state.svelte.d.ts.map +1 -0
- package/dist/state/block-state.svelte.js +91 -0
- package/dist/state/tree-state.svelte.d.ts +39 -0
- package/dist/state/tree-state.svelte.d.ts.map +1 -0
- package/dist/state/tree-state.svelte.js +118 -0
- package/dist/types.d.ts +46 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +1 -0
- package/dist/utils/haptic.d.ts +6 -0
- package/dist/utils/haptic.d.ts.map +1 -0
- package/dist/utils/haptic.js +9 -0
- package/dist/utils/sensors.d.ts +11 -0
- package/dist/utils/sensors.d.ts.map +1 -0
- package/dist/utils/sensors.js +10 -0
- package/package.json +56 -0
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { blockReducer, computeNormalizedIndex, buildOrderedBlocks, getDescendantIds, generateId, generateKeyBetween, } from '@dnd-block-tree/core';
|
|
2
|
+
import { getContext, setContext } from 'svelte';
|
|
3
|
+
const BLOCK_STATE_KEY = Symbol('block-state');
|
|
4
|
+
export function createBlockState(options = {}) {
|
|
5
|
+
const { initialBlocks = [], containerTypes = [], orderingStrategy = 'integer', maxDepth, onChange, onBlockAdd, onBlockDelete, } = options;
|
|
6
|
+
let index = $state(computeNormalizedIndex(initialBlocks, orderingStrategy));
|
|
7
|
+
function dispatch(action) {
|
|
8
|
+
index = blockReducer(index, action, containerTypes, orderingStrategy, maxDepth);
|
|
9
|
+
}
|
|
10
|
+
const blocks = $derived.by(() => {
|
|
11
|
+
return buildOrderedBlocks(index, containerTypes, orderingStrategy);
|
|
12
|
+
});
|
|
13
|
+
const blockMap = $derived(index.byId);
|
|
14
|
+
const childrenMap = $derived.by(() => {
|
|
15
|
+
const map = new Map();
|
|
16
|
+
for (const [parentId, ids] of index.byParent.entries()) {
|
|
17
|
+
map.set(parentId, ids.map(id => index.byId.get(id)).filter(Boolean));
|
|
18
|
+
}
|
|
19
|
+
return map;
|
|
20
|
+
});
|
|
21
|
+
// Notify onChange when blocks change
|
|
22
|
+
$effect(() => {
|
|
23
|
+
onChange?.(blocks);
|
|
24
|
+
});
|
|
25
|
+
const state = {
|
|
26
|
+
get blocks() { return blocks; },
|
|
27
|
+
get blockMap() { return blockMap; },
|
|
28
|
+
get childrenMap() { return childrenMap; },
|
|
29
|
+
get normalizedIndex() { return index; },
|
|
30
|
+
createItem(type, parentId = null) {
|
|
31
|
+
const siblings = index.byParent.get(parentId) ?? [];
|
|
32
|
+
let order = siblings.length;
|
|
33
|
+
if (orderingStrategy === 'fractional') {
|
|
34
|
+
const lastId = siblings[siblings.length - 1];
|
|
35
|
+
const lastOrder = lastId ? String(index.byId.get(lastId).order) : null;
|
|
36
|
+
order = generateKeyBetween(lastOrder, null);
|
|
37
|
+
}
|
|
38
|
+
const newItem = { id: generateId(), type, parentId, order };
|
|
39
|
+
dispatch({ type: 'ADD_ITEM', payload: newItem });
|
|
40
|
+
onBlockAdd?.({ block: newItem, parentId, index: siblings.length });
|
|
41
|
+
return newItem;
|
|
42
|
+
},
|
|
43
|
+
insertItem(type, referenceId, position) {
|
|
44
|
+
const referenceBlock = index.byId.get(referenceId);
|
|
45
|
+
if (!referenceBlock)
|
|
46
|
+
throw new Error(`Reference block ${referenceId} not found`);
|
|
47
|
+
const parentId = referenceBlock.parentId ?? null;
|
|
48
|
+
const siblings = index.byParent.get(parentId) ?? [];
|
|
49
|
+
const refIdx = siblings.indexOf(referenceId);
|
|
50
|
+
const insertIdx = position === 'before' ? refIdx : refIdx + 1;
|
|
51
|
+
let order = insertIdx;
|
|
52
|
+
if (orderingStrategy === 'fractional') {
|
|
53
|
+
const prevId = insertIdx > 0 ? siblings[insertIdx - 1] : null;
|
|
54
|
+
const nextId = insertIdx < siblings.length ? siblings[insertIdx] : null;
|
|
55
|
+
const prevOrder = prevId ? String(index.byId.get(prevId).order) : null;
|
|
56
|
+
const nextOrder = nextId ? String(index.byId.get(nextId).order) : null;
|
|
57
|
+
order = generateKeyBetween(prevOrder, nextOrder);
|
|
58
|
+
}
|
|
59
|
+
const newItem = { id: generateId(), type, parentId, order };
|
|
60
|
+
dispatch({ type: 'INSERT_ITEM', payload: { item: newItem, parentId, index: insertIdx } });
|
|
61
|
+
onBlockAdd?.({ block: newItem, parentId, index: insertIdx });
|
|
62
|
+
return newItem;
|
|
63
|
+
},
|
|
64
|
+
deleteItem(id) {
|
|
65
|
+
const block = index.byId.get(id);
|
|
66
|
+
if (block && onBlockDelete) {
|
|
67
|
+
const deletedIds = [...getDescendantIds(index, id)];
|
|
68
|
+
onBlockDelete({ block, deletedIds, parentId: block.parentId });
|
|
69
|
+
}
|
|
70
|
+
dispatch({ type: 'DELETE_ITEM', payload: { id } });
|
|
71
|
+
},
|
|
72
|
+
moveItem(activeId, targetZone) {
|
|
73
|
+
dispatch({ type: 'MOVE_ITEM', payload: { activeId, targetZone } });
|
|
74
|
+
},
|
|
75
|
+
setAll(allBlocks) {
|
|
76
|
+
dispatch({ type: 'SET_ALL', payload: allBlocks });
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
return state;
|
|
80
|
+
}
|
|
81
|
+
/** Set block state in context */
|
|
82
|
+
export function setBlockStateContext(state) {
|
|
83
|
+
setContext(BLOCK_STATE_KEY, state);
|
|
84
|
+
}
|
|
85
|
+
/** Get block state from context */
|
|
86
|
+
export function getBlockStateContext() {
|
|
87
|
+
const ctx = getContext(BLOCK_STATE_KEY);
|
|
88
|
+
if (!ctx)
|
|
89
|
+
throw new Error('getBlockStateContext must be called inside a component that called setBlockStateContext');
|
|
90
|
+
return ctx;
|
|
91
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { BaseBlock, OrderingStrategy } from '@dnd-block-tree/core';
|
|
2
|
+
export interface TreeStateOptions {
|
|
3
|
+
previewDebounce?: number;
|
|
4
|
+
containerTypes?: readonly string[];
|
|
5
|
+
orderingStrategy?: OrderingStrategy;
|
|
6
|
+
}
|
|
7
|
+
export interface TreeState<T extends BaseBlock> {
|
|
8
|
+
readonly activeId: string | null;
|
|
9
|
+
readonly activeBlock: T | null;
|
|
10
|
+
readonly hoverZone: string | null;
|
|
11
|
+
readonly expandedMap: Record<string, boolean>;
|
|
12
|
+
readonly effectiveBlocks: T[];
|
|
13
|
+
readonly blocksByParent: Map<string | null, T[]>;
|
|
14
|
+
readonly isDragging: boolean;
|
|
15
|
+
setActiveId(id: string | null): void;
|
|
16
|
+
setHoverZone(zone: string | null): void;
|
|
17
|
+
toggleExpand(id: string): void;
|
|
18
|
+
setExpandAll(expanded: boolean): void;
|
|
19
|
+
handleHover(zoneId: string, parentId: string | null): void;
|
|
20
|
+
handleDragStart(id: string, blocks: T[], draggedIds?: string[]): void;
|
|
21
|
+
handleDragOver(targetZone: string): void;
|
|
22
|
+
handleDragEnd(): {
|
|
23
|
+
targetId: string;
|
|
24
|
+
reorderedBlocks: T[];
|
|
25
|
+
} | null;
|
|
26
|
+
cancelDrag(): void;
|
|
27
|
+
getInitialBlocks(): T[];
|
|
28
|
+
getCachedReorder(): {
|
|
29
|
+
targetId: string;
|
|
30
|
+
reorderedBlocks: T[];
|
|
31
|
+
} | null;
|
|
32
|
+
getDraggedIds(): string[];
|
|
33
|
+
}
|
|
34
|
+
export declare function createTreeState<T extends BaseBlock>(blocks: () => T[], blockMap: () => Map<string, T>, options?: TreeStateOptions): TreeState<T>;
|
|
35
|
+
/** Set tree state in context */
|
|
36
|
+
export declare function setTreeStateContext<T extends BaseBlock>(state: TreeState<T>): void;
|
|
37
|
+
/** Get tree state from context */
|
|
38
|
+
export declare function getTreeStateContext<T extends BaseBlock>(): TreeState<T>;
|
|
39
|
+
//# sourceMappingURL=tree-state.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tree-state.svelte.d.ts","sourceRoot":"","sources":["../../src/state/tree-state.svelte.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,SAAS,EAET,gBAAgB,EAMjB,MAAM,sBAAsB,CAAA;AAe7B,MAAM,WAAW,gBAAgB;IAC/B,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,cAAc,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IAClC,gBAAgB,CAAC,EAAE,gBAAgB,CAAA;CACpC;AAED,MAAM,WAAW,SAAS,CAAC,CAAC,SAAS,SAAS;IAC5C,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IAChC,QAAQ,CAAC,WAAW,EAAE,CAAC,GAAG,IAAI,CAAA;IAC9B,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACjC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC7C,QAAQ,CAAC,eAAe,EAAE,CAAC,EAAE,CAAA;IAC7B,QAAQ,CAAC,cAAc,EAAE,GAAG,CAAC,MAAM,GAAG,IAAI,EAAE,CAAC,EAAE,CAAC,CAAA;IAChD,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAA;IAC5B,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAAA;IACpC,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAAA;IACvC,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,YAAY,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI,CAAA;IACrC,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAAA;IAC1D,eAAe,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,EAAE,EAAE,UAAU,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,CAAA;IACrE,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACxC,aAAa,IAAI;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,eAAe,EAAE,CAAC,EAAE,CAAA;KAAE,GAAG,IAAI,CAAA;IAClE,UAAU,IAAI,IAAI,CAAA;IAClB,gBAAgB,IAAI,CAAC,EAAE,CAAA;IACvB,gBAAgB,IAAI;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,eAAe,EAAE,CAAC,EAAE,CAAA;KAAE,GAAG,IAAI,CAAA;IACrE,aAAa,IAAI,MAAM,EAAE,CAAA;CAC1B;AAED,wBAAgB,eAAe,CAAC,CAAC,SAAS,SAAS,EACjD,MAAM,EAAE,MAAM,CAAC,EAAE,EACjB,QAAQ,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,EAC9B,OAAO,GAAE,gBAAqB,GAC7B,SAAS,CAAC,CAAC,CAAC,CAoId;AAED,gCAAgC;AAChC,wBAAgB,mBAAmB,CAAC,CAAC,SAAS,SAAS,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC,GAAG,IAAI,CAElF;AAED,kCAAkC;AAClC,wBAAgB,mBAAmB,CAAC,CAAC,SAAS,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,CAIvE"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { expandReducer, computeNormalizedIndex, reparentBlockIndex, reparentMultipleBlocks, buildOrderedBlocks, debounce, getDropZoneType, extractBlockId, } from '@dnd-block-tree/core';
|
|
2
|
+
import { getContext, setContext } from 'svelte';
|
|
3
|
+
const TREE_STATE_KEY = Symbol('tree-state');
|
|
4
|
+
export function createTreeState(blocks, blockMap, options = {}) {
|
|
5
|
+
const { previewDebounce = 150, containerTypes = [], orderingStrategy = 'integer', } = options;
|
|
6
|
+
let activeId = $state(null);
|
|
7
|
+
let hoverZone = $state(null);
|
|
8
|
+
let expandedMap = $state({});
|
|
9
|
+
let virtualState = $state(null);
|
|
10
|
+
let isDragging = $state(false);
|
|
11
|
+
// Non-reactive refs (snapshots)
|
|
12
|
+
let initialBlocks = [];
|
|
13
|
+
let cachedReorder = null;
|
|
14
|
+
let draggedIds = [];
|
|
15
|
+
const activeBlock = $derived(activeId ? blockMap().get(activeId) ?? null : null);
|
|
16
|
+
const debouncedSetVirtual = debounce((newBlocks) => {
|
|
17
|
+
if (newBlocks) {
|
|
18
|
+
virtualState = computeNormalizedIndex(newBlocks);
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
virtualState = null;
|
|
22
|
+
}
|
|
23
|
+
}, previewDebounce);
|
|
24
|
+
const effectiveState = $derived(virtualState ?? computeNormalizedIndex(blocks(), orderingStrategy));
|
|
25
|
+
const effectiveBlocks = $derived(buildOrderedBlocks(effectiveState, containerTypes, orderingStrategy));
|
|
26
|
+
const blocksByParent = $derived.by(() => {
|
|
27
|
+
const map = new Map();
|
|
28
|
+
for (const [parentId, ids] of effectiveState.byParent.entries()) {
|
|
29
|
+
map.set(parentId, ids.map(id => effectiveState.byId.get(id)).filter(Boolean));
|
|
30
|
+
}
|
|
31
|
+
return map;
|
|
32
|
+
});
|
|
33
|
+
const state = {
|
|
34
|
+
get activeId() { return activeId; },
|
|
35
|
+
get activeBlock() { return activeBlock; },
|
|
36
|
+
get hoverZone() { return hoverZone; },
|
|
37
|
+
get expandedMap() { return expandedMap; },
|
|
38
|
+
get effectiveBlocks() { return effectiveBlocks; },
|
|
39
|
+
get blocksByParent() { return blocksByParent; },
|
|
40
|
+
get isDragging() { return isDragging; },
|
|
41
|
+
setActiveId(id) {
|
|
42
|
+
activeId = id;
|
|
43
|
+
},
|
|
44
|
+
setHoverZone(zone) {
|
|
45
|
+
hoverZone = zone;
|
|
46
|
+
},
|
|
47
|
+
toggleExpand(id) {
|
|
48
|
+
expandedMap = expandReducer(expandedMap, { type: 'TOGGLE', id });
|
|
49
|
+
},
|
|
50
|
+
setExpandAll(expanded) {
|
|
51
|
+
const containerIds = blocks()
|
|
52
|
+
.filter(b => containerTypes.includes(b.type))
|
|
53
|
+
.map(b => b.id);
|
|
54
|
+
expandedMap = expandReducer(expandedMap, { type: 'SET_ALL', expanded, ids: containerIds });
|
|
55
|
+
},
|
|
56
|
+
handleHover(zoneId, _parentId) {
|
|
57
|
+
if (!activeId)
|
|
58
|
+
return;
|
|
59
|
+
state.handleDragOver(zoneId);
|
|
60
|
+
},
|
|
61
|
+
handleDragStart(id, currentBlocks, ids) {
|
|
62
|
+
activeId = id;
|
|
63
|
+
isDragging = true;
|
|
64
|
+
initialBlocks = [...currentBlocks];
|
|
65
|
+
cachedReorder = null;
|
|
66
|
+
draggedIds = ids ?? [id];
|
|
67
|
+
},
|
|
68
|
+
handleDragOver(targetZone) {
|
|
69
|
+
if (!activeId)
|
|
70
|
+
return;
|
|
71
|
+
hoverZone = targetZone;
|
|
72
|
+
const baseIndex = computeNormalizedIndex(initialBlocks, orderingStrategy);
|
|
73
|
+
const updatedIndex = draggedIds.length > 1
|
|
74
|
+
? reparentMultipleBlocks(baseIndex, draggedIds, targetZone, containerTypes, orderingStrategy)
|
|
75
|
+
: reparentBlockIndex(baseIndex, activeId, targetZone, containerTypes, orderingStrategy);
|
|
76
|
+
const orderedBlocks = buildOrderedBlocks(updatedIndex, containerTypes, orderingStrategy);
|
|
77
|
+
cachedReorder = { targetId: targetZone, reorderedBlocks: orderedBlocks };
|
|
78
|
+
debouncedSetVirtual(orderedBlocks);
|
|
79
|
+
},
|
|
80
|
+
handleDragEnd() {
|
|
81
|
+
debouncedSetVirtual.cancel();
|
|
82
|
+
virtualState = null;
|
|
83
|
+
const result = cachedReorder;
|
|
84
|
+
activeId = null;
|
|
85
|
+
hoverZone = null;
|
|
86
|
+
isDragging = false;
|
|
87
|
+
cachedReorder = null;
|
|
88
|
+
initialBlocks = [];
|
|
89
|
+
draggedIds = [];
|
|
90
|
+
return result;
|
|
91
|
+
},
|
|
92
|
+
cancelDrag() {
|
|
93
|
+
debouncedSetVirtual.cancel();
|
|
94
|
+
virtualState = null;
|
|
95
|
+
activeId = null;
|
|
96
|
+
hoverZone = null;
|
|
97
|
+
isDragging = false;
|
|
98
|
+
cachedReorder = null;
|
|
99
|
+
initialBlocks = [];
|
|
100
|
+
draggedIds = [];
|
|
101
|
+
},
|
|
102
|
+
getInitialBlocks: () => initialBlocks,
|
|
103
|
+
getCachedReorder: () => cachedReorder,
|
|
104
|
+
getDraggedIds: () => draggedIds,
|
|
105
|
+
};
|
|
106
|
+
return state;
|
|
107
|
+
}
|
|
108
|
+
/** Set tree state in context */
|
|
109
|
+
export function setTreeStateContext(state) {
|
|
110
|
+
setContext(TREE_STATE_KEY, state);
|
|
111
|
+
}
|
|
112
|
+
/** Get tree state from context */
|
|
113
|
+
export function getTreeStateContext() {
|
|
114
|
+
const ctx = getContext(TREE_STATE_KEY);
|
|
115
|
+
if (!ctx)
|
|
116
|
+
throw new Error('getTreeStateContext must be called inside a component that called setTreeStateContext');
|
|
117
|
+
return ctx;
|
|
118
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { BaseBlock, BlockRendererProps as CoreBlockRendererProps, ContainerRendererProps as CoreContainerRendererProps, BlockRenderers as CoreBlockRenderers, InternalRenderers as CoreInternalRenderers, RendererPropsFor as CoreRendererPropsFor, OrderingStrategy, BlockAddEvent, BlockDeleteEvent, CanDragFn, CanDropFn, IdGeneratorFn, SensorConfig, DropZoneConfig, AnimationConfig, AutoExpandConfig, CoreCollisionDetection } from '@dnd-block-tree/core';
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
export type BlockRendererProps<T extends BaseBlock = BaseBlock> = CoreBlockRendererProps<T, Snippet>;
|
|
4
|
+
export type ContainerRendererProps<T extends BaseBlock = BaseBlock> = CoreContainerRendererProps<T, Snippet>;
|
|
5
|
+
export type RendererPropsFor<T extends BaseBlock, K extends T['type'], C extends readonly string[]> = CoreRendererPropsFor<T, K, C, Snippet>;
|
|
6
|
+
export type BlockRenderers<T extends BaseBlock = BaseBlock, C extends readonly string[] = readonly string[]> = CoreBlockRenderers<T, C, Snippet>;
|
|
7
|
+
export type InternalRenderers<T extends BaseBlock = BaseBlock> = CoreInternalRenderers<T, Snippet>;
|
|
8
|
+
/** Block state provider options */
|
|
9
|
+
export interface BlockStateOptions<T extends BaseBlock = BaseBlock> {
|
|
10
|
+
initialBlocks?: T[];
|
|
11
|
+
containerTypes?: readonly string[];
|
|
12
|
+
onChange?: (blocks: T[]) => void;
|
|
13
|
+
orderingStrategy?: OrderingStrategy;
|
|
14
|
+
maxDepth?: number;
|
|
15
|
+
onBlockAdd?: (event: BlockAddEvent<T>) => void;
|
|
16
|
+
onBlockDelete?: (event: BlockDeleteEvent<T>) => void;
|
|
17
|
+
}
|
|
18
|
+
/** Tree state context value (UI state) */
|
|
19
|
+
export interface TreeStateContextValue<T extends BaseBlock = BaseBlock> {
|
|
20
|
+
activeId: string | null;
|
|
21
|
+
activeBlock: T | null;
|
|
22
|
+
hoverZone: string | null;
|
|
23
|
+
expandedMap: Record<string, boolean>;
|
|
24
|
+
effectiveBlocks: T[];
|
|
25
|
+
blocksByParent: Map<string | null, T[]>;
|
|
26
|
+
setActiveId: (id: string | null) => void;
|
|
27
|
+
setHoverZone: (zone: string | null) => void;
|
|
28
|
+
toggleExpand: (id: string) => void;
|
|
29
|
+
setExpandAll: (expanded: boolean) => void;
|
|
30
|
+
handleHover: (zoneId: string, parentId: string | null) => void;
|
|
31
|
+
}
|
|
32
|
+
/** Full customization options for BlockTree (Svelte version) */
|
|
33
|
+
export interface BlockTreeCustomization<T extends BaseBlock = BaseBlock> {
|
|
34
|
+
canDrag?: CanDragFn<T>;
|
|
35
|
+
canDrop?: CanDropFn<T>;
|
|
36
|
+
collisionDetection?: CoreCollisionDetection;
|
|
37
|
+
sensors?: SensorConfig;
|
|
38
|
+
dropZones?: DropZoneConfig;
|
|
39
|
+
animation?: AnimationConfig;
|
|
40
|
+
autoExpand?: AutoExpandConfig;
|
|
41
|
+
idGenerator?: IdGeneratorFn;
|
|
42
|
+
initialExpanded?: string[] | 'all' | 'none';
|
|
43
|
+
orderingStrategy?: OrderingStrategy;
|
|
44
|
+
maxDepth?: number;
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"haptic.d.ts","sourceRoot":"","sources":["../../src/utils/haptic.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,wBAAgB,aAAa,CAAC,UAAU,SAAK,GAAG,IAAI,CAInD"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Trigger haptic feedback (vibration) on supported devices.
|
|
3
|
+
* Safe to call in any environment -- no-ops when `navigator.vibrate` is unavailable.
|
|
4
|
+
*/
|
|
5
|
+
export function triggerHaptic(durationMs = 10) {
|
|
6
|
+
if (typeof navigator !== 'undefined' && typeof navigator.vibrate === 'function') {
|
|
7
|
+
navigator.vibrate(durationMs);
|
|
8
|
+
}
|
|
9
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { SensorConfig } from '@dnd-block-tree/core';
|
|
2
|
+
export interface SensorConfigResult {
|
|
3
|
+
activationDistance: number;
|
|
4
|
+
longPressDelay: number;
|
|
5
|
+
hapticFeedback: boolean;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Get sensor configuration with defaults applied.
|
|
9
|
+
*/
|
|
10
|
+
export declare function getSensorConfig(config?: SensorConfig): SensorConfigResult;
|
|
11
|
+
//# sourceMappingURL=sensors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sensors.d.ts","sourceRoot":"","sources":["../../src/utils/sensors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AAExD,MAAM,WAAW,kBAAkB;IACjC,kBAAkB,EAAE,MAAM,CAAA;IAC1B,cAAc,EAAE,MAAM,CAAA;IACtB,cAAc,EAAE,OAAO,CAAA;CACxB;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,CAAC,EAAE,YAAY,GAAG,kBAAkB,CAMzE"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Get sensor configuration with defaults applied.
|
|
3
|
+
*/
|
|
4
|
+
export function getSensorConfig(config) {
|
|
5
|
+
return {
|
|
6
|
+
activationDistance: config?.activationDistance ?? 8,
|
|
7
|
+
longPressDelay: config?.longPressDelay ?? 200,
|
|
8
|
+
hapticFeedback: config?.hapticFeedback ?? false,
|
|
9
|
+
};
|
|
10
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@dnd-block-tree/svelte",
|
|
3
|
+
"version": "2.1.0",
|
|
4
|
+
"description": "Svelte 5 adapter for dnd-block-tree — drag-and-drop hierarchical block trees",
|
|
5
|
+
"svelte": "./dist/index.js",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"svelte": "./dist/index.js",
|
|
12
|
+
"default": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": ["dist", "!dist/**/*.test.*"],
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "svelte-package -i src -o dist",
|
|
18
|
+
"dev": "svelte-package -i src -o dist --watch",
|
|
19
|
+
"test": "vitest run",
|
|
20
|
+
"typecheck": "svelte-check --tsconfig tsconfig.json"
|
|
21
|
+
},
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"@dnd-block-tree/core": "^2.0.0"
|
|
24
|
+
},
|
|
25
|
+
"peerDependencies": {
|
|
26
|
+
"@dnd-kit/dom": "^0.3.0",
|
|
27
|
+
"@dnd-kit/svelte": "^0.3.0",
|
|
28
|
+
"svelte": "^5.29.0"
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"@dnd-kit/dom": "^0.3.2",
|
|
32
|
+
"@dnd-kit/svelte": "^0.3.2",
|
|
33
|
+
"@sveltejs/package": "^2.3.0",
|
|
34
|
+
"svelte": "^5.29.0",
|
|
35
|
+
"svelte-check": "^4.0.0",
|
|
36
|
+
"tslib": "^2.8.0",
|
|
37
|
+
"typescript": "^5.5.0",
|
|
38
|
+
"vitest": "^4.0.18"
|
|
39
|
+
},
|
|
40
|
+
"repository": {
|
|
41
|
+
"type": "git",
|
|
42
|
+
"url": "https://github.com/thesandybridge/dnd-block-tree",
|
|
43
|
+
"directory": "packages/svelte"
|
|
44
|
+
},
|
|
45
|
+
"license": "MIT",
|
|
46
|
+
"keywords": [
|
|
47
|
+
"dnd",
|
|
48
|
+
"drag-and-drop",
|
|
49
|
+
"block",
|
|
50
|
+
"tree",
|
|
51
|
+
"svelte",
|
|
52
|
+
"svelte5",
|
|
53
|
+
"dnd-kit",
|
|
54
|
+
"hierarchical"
|
|
55
|
+
]
|
|
56
|
+
}
|