@coyalabs/bts-style 1.1.11 → 1.1.13
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.
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
const dispatch = createEventDispatcher();
|
|
8
8
|
|
|
9
|
-
/** @type {{ name: string, type: 'file' | 'folder', children?: any[] }[]} */
|
|
9
|
+
/** @type {{ name: string, type: 'file' | 'folder', children?: any[], data?: any }[]} */
|
|
10
10
|
export let items = [];
|
|
11
11
|
|
|
12
12
|
/** @type {boolean} */
|
|
@@ -21,8 +21,15 @@
|
|
|
21
21
|
/** @type {boolean} */
|
|
22
22
|
export let topFoldersExpanded = false;
|
|
23
23
|
|
|
24
|
+
/** @type {boolean} - Enable drag and drop */
|
|
25
|
+
export let draggable = false;
|
|
26
|
+
|
|
27
|
+
/** @type {string} - Current folder path for nested items */
|
|
28
|
+
export let currentPath = '';
|
|
29
|
+
|
|
24
30
|
let expanded = new Set();
|
|
25
31
|
let mounted = false;
|
|
32
|
+
let dragOverFolder = null;
|
|
26
33
|
|
|
27
34
|
// Initialize expanded state before mount (no animation)
|
|
28
35
|
if (topFoldersExpanded && level === 0) {
|
|
@@ -54,6 +61,90 @@
|
|
|
54
61
|
function handleItemClick(item) {
|
|
55
62
|
dispatch('itemClick', { item, type: 'file' });
|
|
56
63
|
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Handle drag start on a file item
|
|
67
|
+
* @param {DragEvent} e
|
|
68
|
+
* @param {any} item
|
|
69
|
+
*/
|
|
70
|
+
function handleDragStart(e, item) {
|
|
71
|
+
if (!draggable || item.type !== 'file') return;
|
|
72
|
+
e.dataTransfer.effectAllowed = 'move';
|
|
73
|
+
e.dataTransfer.setData('application/json', JSON.stringify({
|
|
74
|
+
name: item.name,
|
|
75
|
+
data: item.data,
|
|
76
|
+
sourcePath: currentPath
|
|
77
|
+
}));
|
|
78
|
+
dispatch('dragStart', { item, sourcePath: currentPath });
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Handle drag over a folder
|
|
83
|
+
* @param {DragEvent} e
|
|
84
|
+
* @param {any} item
|
|
85
|
+
*/
|
|
86
|
+
function handleDragOver(e, item) {
|
|
87
|
+
if (!draggable) return;
|
|
88
|
+
e.preventDefault();
|
|
89
|
+
e.dataTransfer.dropEffect = 'move';
|
|
90
|
+
if (item.type === 'folder') {
|
|
91
|
+
dragOverFolder = item.name;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Handle drag leave
|
|
97
|
+
*/
|
|
98
|
+
function handleDragLeave() {
|
|
99
|
+
dragOverFolder = null;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Handle drop on a folder
|
|
104
|
+
* @param {DragEvent} e
|
|
105
|
+
* @param {any} targetItem
|
|
106
|
+
*/
|
|
107
|
+
function handleDrop(e, targetItem) {
|
|
108
|
+
if (!draggable) return;
|
|
109
|
+
e.preventDefault();
|
|
110
|
+
dragOverFolder = null;
|
|
111
|
+
|
|
112
|
+
try {
|
|
113
|
+
const data = JSON.parse(e.dataTransfer.getData('application/json'));
|
|
114
|
+
const targetPath = targetItem.type === 'folder'
|
|
115
|
+
? (currentPath ? `${currentPath}/${targetItem.name}` : targetItem.name)
|
|
116
|
+
: currentPath;
|
|
117
|
+
|
|
118
|
+
dispatch('itemDrop', {
|
|
119
|
+
item: data,
|
|
120
|
+
sourcePath: data.sourcePath,
|
|
121
|
+
targetPath: targetPath
|
|
122
|
+
});
|
|
123
|
+
} catch (err) {
|
|
124
|
+
console.error('Drop failed:', err);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Handle drop on root (current level)
|
|
130
|
+
* @param {DragEvent} e
|
|
131
|
+
*/
|
|
132
|
+
function handleRootDrop(e) {
|
|
133
|
+
if (!draggable) return;
|
|
134
|
+
e.preventDefault();
|
|
135
|
+
dragOverFolder = null;
|
|
136
|
+
|
|
137
|
+
try {
|
|
138
|
+
const data = JSON.parse(e.dataTransfer.getData('application/json'));
|
|
139
|
+
dispatch('itemDrop', {
|
|
140
|
+
item: data,
|
|
141
|
+
sourcePath: data.sourcePath,
|
|
142
|
+
targetPath: currentPath
|
|
143
|
+
});
|
|
144
|
+
} catch (err) {
|
|
145
|
+
console.error('Drop failed:', err);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
57
148
|
|
|
58
149
|
/**
|
|
59
150
|
* Get the current expanded state
|
|
@@ -117,17 +208,44 @@
|
|
|
117
208
|
});
|
|
118
209
|
return count;
|
|
119
210
|
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Build path for nested folder
|
|
214
|
+
* @param {string} folderName
|
|
215
|
+
* @returns {string}
|
|
216
|
+
*/
|
|
217
|
+
function buildChildPath(folderName) {
|
|
218
|
+
return currentPath ? `${currentPath}/${folderName}` : folderName;
|
|
219
|
+
}
|
|
120
220
|
</script>
|
|
121
221
|
|
|
122
|
-
|
|
222
|
+
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
|
223
|
+
<div
|
|
224
|
+
class="tree"
|
|
225
|
+
style="padding-left: {level === 0 ? level * 30 : level * 20}px;"
|
|
226
|
+
on:dragover={draggable ? (e) => { e.preventDefault(); } : undefined}
|
|
227
|
+
on:drop={draggable ? handleRootDrop : undefined}
|
|
228
|
+
>
|
|
123
229
|
{#each items as item, i}
|
|
124
230
|
{@const id = `${level}-${i}`}
|
|
125
231
|
{@const open = expanded.has(id)}
|
|
126
232
|
{@const isLast = i === items.length - 1}
|
|
127
233
|
{@const isNested = level > 0}
|
|
234
|
+
{@const isDragOver = dragOverFolder === item.name}
|
|
128
235
|
|
|
129
236
|
{#if item.type === 'folder'}
|
|
130
|
-
|
|
237
|
+
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
|
238
|
+
<div
|
|
239
|
+
class="folder"
|
|
240
|
+
class:drag-over={isDragOver}
|
|
241
|
+
on:click={() => toggle(id, item)}
|
|
242
|
+
on:keydown={() => {}}
|
|
243
|
+
on:dragover={draggable ? (e) => handleDragOver(e, item) : undefined}
|
|
244
|
+
on:dragleave={draggable ? handleDragLeave : undefined}
|
|
245
|
+
on:drop={draggable ? (e) => handleDrop(e, item) : undefined}
|
|
246
|
+
role="button"
|
|
247
|
+
tabindex="0"
|
|
248
|
+
>
|
|
131
249
|
<Button
|
|
132
250
|
theme="primary"
|
|
133
251
|
icon={icons.folder}
|
|
@@ -143,11 +261,31 @@
|
|
|
143
261
|
</div>
|
|
144
262
|
{#if open && item.children}
|
|
145
263
|
<div transition:slide={{ duration: mounted ? 150 : 0 }}>
|
|
146
|
-
<svelte:self
|
|
264
|
+
<svelte:self
|
|
265
|
+
items={item.children}
|
|
266
|
+
{showCount}
|
|
267
|
+
{itemIcon}
|
|
268
|
+
level={level + 1}
|
|
269
|
+
{draggable}
|
|
270
|
+
currentPath={buildChildPath(item.name)}
|
|
271
|
+
on:itemClick
|
|
272
|
+
on:itemDrop
|
|
273
|
+
on:dragStart
|
|
274
|
+
/>
|
|
147
275
|
</div>
|
|
148
276
|
{/if}
|
|
149
277
|
{:else}
|
|
150
|
-
|
|
278
|
+
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
|
279
|
+
<div
|
|
280
|
+
class="file-item"
|
|
281
|
+
class:dragging={draggable}
|
|
282
|
+
draggable={draggable}
|
|
283
|
+
on:dragstart={draggable ? (e) => handleDragStart(e, item) : undefined}
|
|
284
|
+
on:click={() => handleItemClick(item)}
|
|
285
|
+
on:keydown={() => {}}
|
|
286
|
+
role="button"
|
|
287
|
+
tabindex="0"
|
|
288
|
+
>
|
|
151
289
|
<Button
|
|
152
290
|
theme="secondary"
|
|
153
291
|
icon={itemIcon}
|
|
@@ -172,9 +310,24 @@
|
|
|
172
310
|
}
|
|
173
311
|
.folder {
|
|
174
312
|
cursor: pointer;
|
|
313
|
+
transition: transform 0.15s ease, opacity 0.15s ease;
|
|
314
|
+
}
|
|
315
|
+
.folder.drag-over {
|
|
316
|
+
transform: scale(1.02);
|
|
317
|
+
opacity: 0.8;
|
|
175
318
|
}
|
|
176
319
|
.folder :global(.count) {
|
|
177
320
|
margin-left: 5px;
|
|
178
321
|
opacity: 0.5;
|
|
179
322
|
}
|
|
323
|
+
.file-item {
|
|
324
|
+
transition: opacity 0.15s ease;
|
|
325
|
+
}
|
|
326
|
+
.file-item.dragging {
|
|
327
|
+
cursor: grab;
|
|
328
|
+
}
|
|
329
|
+
.file-item.dragging:active {
|
|
330
|
+
cursor: grabbing;
|
|
331
|
+
opacity: 0.6;
|
|
332
|
+
}
|
|
180
333
|
</style>
|
|
@@ -4,17 +4,22 @@ type TreeDirectory = SvelteComponent<{
|
|
|
4
4
|
name: string;
|
|
5
5
|
type: "file" | "folder";
|
|
6
6
|
children?: any[] | undefined;
|
|
7
|
+
data?: any;
|
|
7
8
|
}[] | undefined;
|
|
8
9
|
showCount?: boolean | undefined;
|
|
9
10
|
itemIcon?: string | null | undefined;
|
|
10
11
|
level?: number | undefined;
|
|
11
12
|
topFoldersExpanded?: boolean | undefined;
|
|
13
|
+
draggable?: boolean | undefined;
|
|
14
|
+
currentPath?: string | undefined;
|
|
12
15
|
getState?: (() => string[]) | undefined;
|
|
13
16
|
setState?: ((state: string[]) => void) | undefined;
|
|
14
17
|
expandAll?: (() => void) | undefined;
|
|
15
18
|
collapseAll?: (() => void) | undefined;
|
|
16
19
|
}, {
|
|
17
20
|
itemClick: CustomEvent<any>;
|
|
21
|
+
dragStart: CustomEvent<any>;
|
|
22
|
+
itemDrop: CustomEvent<any>;
|
|
18
23
|
} & {
|
|
19
24
|
[evt: string]: CustomEvent<any>;
|
|
20
25
|
}, {}> & {
|
|
@@ -30,17 +35,22 @@ declare const TreeDirectory: $$__sveltets_2_IsomorphicComponent<{
|
|
|
30
35
|
name: string;
|
|
31
36
|
type: "file" | "folder";
|
|
32
37
|
children?: any[];
|
|
38
|
+
data?: any;
|
|
33
39
|
}[] | undefined;
|
|
34
40
|
showCount?: boolean | undefined;
|
|
35
41
|
itemIcon?: string | null | undefined;
|
|
36
42
|
level?: number | undefined;
|
|
37
43
|
topFoldersExpanded?: boolean | undefined;
|
|
44
|
+
draggable?: boolean | undefined;
|
|
45
|
+
currentPath?: string | undefined;
|
|
38
46
|
getState?: (() => string[]) | undefined;
|
|
39
47
|
setState?: ((state: string[]) => void) | undefined;
|
|
40
48
|
expandAll?: (() => void) | undefined;
|
|
41
49
|
collapseAll?: (() => void) | undefined;
|
|
42
50
|
}, {
|
|
43
51
|
itemClick: CustomEvent<any>;
|
|
52
|
+
dragStart: CustomEvent<any>;
|
|
53
|
+
itemDrop: CustomEvent<any>;
|
|
44
54
|
} & {
|
|
45
55
|
[evt: string]: CustomEvent<any>;
|
|
46
56
|
}, {}, {
|