@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
- <div class="tree" style="padding-left: {level === 0 ? level * 30 : level * 20}px;">
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
- <div class="folder" on:click={() => toggle(id, item)} on:keydown={() => {}} role="button" tabindex="0">
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 items={item.children} {showCount} {itemIcon} level={level + 1} on:itemClick />
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
- <div on:click={() => handleItemClick(item)} on:keydown={() => {}} role="button" tabindex="0">
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
  }, {}, {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coyalabs/bts-style",
3
- "version": "1.1.11",
3
+ "version": "1.1.13",
4
4
  "description": "BTS Theme Svelte component templates",
5
5
  "type": "module",
6
6
  "exports": {