grav-svelte 0.0.35 → 0.0.37

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.
@@ -16,10 +16,18 @@ import ImageModal from "./ImageModal.svelte";
16
16
  export let todosLosRegistros: any[] = [];
17
17
  export let tableHeaders: TableHeader[];
18
18
  export let loading: boolean = false;
19
+ export let dragEnabled: boolean = false;
20
+ export let orderField: string = 'inOrden';
19
21
 
20
22
  let selectedAscOrDesc = "asc";
21
23
  let selectedSort = "";
22
24
  let selectedRowId: string | number | null = null;
25
+
26
+ // Drag and drop variables
27
+ let draggedIndex: number | null = null;
28
+ let dragOverIndex: number | null = null;
29
+ let isDragging = false;
30
+ let reorderedItems: any[] = [];
23
31
 
24
32
  function handleRowClick(id: string | number) {
25
33
  selectedRowId = selectedRowId === id ? null : id;
@@ -43,6 +51,90 @@ import ImageModal from "./ImageModal.svelte";
43
51
  closeModal("crud-image-modal");
44
52
  openModal("crud-image-modal", ImageModal, { src });
45
53
  }
54
+
55
+ // Drag and drop functions
56
+ function handleDragStart(event: DragEvent, index: number) {
57
+ if (!dragEnabled) return;
58
+
59
+ draggedIndex = index;
60
+ isDragging = true;
61
+
62
+ if (event.dataTransfer) {
63
+ event.dataTransfer.effectAllowed = 'move';
64
+ event.dataTransfer.setData('text/html', '');
65
+ }
66
+ }
67
+
68
+ function handleDragOver(event: DragEvent, index: number) {
69
+ if (!dragEnabled || draggedIndex === null) return;
70
+
71
+ event.preventDefault();
72
+ dragOverIndex = index;
73
+
74
+ if (event.dataTransfer) {
75
+ event.dataTransfer.dropEffect = 'move';
76
+ }
77
+ }
78
+
79
+ function handleDragLeave() {
80
+ dragOverIndex = null;
81
+ }
82
+
83
+ function handleDrop(event: DragEvent, dropIndex: number) {
84
+ if (!dragEnabled || draggedIndex === null || draggedIndex === dropIndex) {
85
+ resetDragState();
86
+ return;
87
+ }
88
+
89
+ event.preventDefault();
90
+
91
+ // Create a new array with reordered items
92
+ const newItems = [...todosLosRegistros];
93
+ const draggedItem = newItems[draggedIndex];
94
+
95
+ // Remove the dragged item from its original position
96
+ newItems.splice(draggedIndex, 1);
97
+
98
+ // Insert the dragged item at the new position
99
+ newItems.splice(dropIndex, 0, draggedItem);
100
+
101
+ // Update the order values and track changes
102
+ const changes: any[] = [];
103
+
104
+ newItems.forEach((item, index) => {
105
+ const newOrder = index + 1;
106
+ const originalOrder = item[orderField];
107
+
108
+ if (originalOrder !== newOrder) {
109
+ changes.push({
110
+ ...item,
111
+ [orderField]: newOrder
112
+ });
113
+ }
114
+
115
+ // Update the item's order in the array
116
+ item[orderField] = newOrder;
117
+ });
118
+
119
+ // Update the items array
120
+ todosLosRegistros = newItems;
121
+ reorderedItems = changes;
122
+
123
+ // Emit the reorder event
124
+ dispatch("reorderChange", { reorderedItems: changes });
125
+
126
+ resetDragState();
127
+ }
128
+
129
+ function handleDragEnd() {
130
+ resetDragState();
131
+ }
132
+
133
+ function resetDragState() {
134
+ draggedIndex = null;
135
+ dragOverIndex = null;
136
+ isDragging = false;
137
+ }
46
138
  </script>
47
139
 
48
140
  <div class="table-container">
@@ -50,10 +142,34 @@ import ImageModal from "./ImageModal.svelte";
50
142
  <table class="data-table" bind:this={tablaExport}>
51
143
  <thead class="table-header">
52
144
  <tr>
145
+ {#if dragEnabled}
146
+ <th class="table-header-cell drag-header borderleft non-sortable">
147
+ <div class="drag-handle-header">
148
+ <svg
149
+ xmlns="http://www.w3.org/2000/svg"
150
+ width="16"
151
+ height="16"
152
+ viewBox="0 0 24 24"
153
+ fill="none"
154
+ stroke="currentColor"
155
+ stroke-width="2"
156
+ stroke-linecap="round"
157
+ stroke-linejoin="round"
158
+ >
159
+ <circle cx="9" cy="12" r="1"></circle>
160
+ <circle cx="9" cy="5" r="1"></circle>
161
+ <circle cx="9" cy="19" r="1"></circle>
162
+ <circle cx="15" cy="12" r="1"></circle>
163
+ <circle cx="15" cy="5" r="1"></circle>
164
+ <circle cx="15" cy="19" r="1"></circle>
165
+ </svg>
166
+ </div>
167
+ </th>
168
+ {/if}
53
169
  {#each tableHeaders as tableHeader, index}
54
170
  {#if tableHeader.biSort == false}
55
171
  <th
56
- class="table-header-cell {index == 0
172
+ class="table-header-cell {index == 0 && !dragEnabled
57
173
  ? 'borderleft'
58
174
  : ''} non-sortable"
59
175
  style="text-align: {tableHeader.align ?? 'center'}"
@@ -63,7 +179,7 @@ import ImageModal from "./ImageModal.svelte";
63
179
  {:else}
64
180
  <th
65
181
  on:click={() => dispatchSort(tableHeader.campo)}
66
- class="table-header-cell {index == 0
182
+ class="table-header-cell {index == 0 && !dragEnabled
67
183
  ? 'borderleft'
68
184
  : ''} sortable"
69
185
  style="text-align: {tableHeader.align ?? 'left'}"
@@ -122,13 +238,47 @@ import ImageModal from "./ImageModal.svelte";
122
238
  <tr
123
239
  class="table-row {selectedRowId === index
124
240
  ? 'selected'
241
+ : ''} {dragEnabled ? 'draggable-row' : ''} {draggedIndex === index
242
+ ? 'dragging'
243
+ : ''} {dragOverIndex === index
244
+ ? 'drag-over'
125
245
  : ''}"
246
+ draggable={dragEnabled}
126
247
  on:click={() => handleRowClick(index)}
248
+ on:dragstart={(e) => handleDragStart(e, index)}
249
+ on:dragover={(e) => handleDragOver(e, index)}
250
+ on:dragleave={handleDragLeave}
251
+ on:drop={(e) => handleDrop(e, index)}
252
+ on:dragend={handleDragEnd}
127
253
  >
254
+ {#if dragEnabled}
255
+ <td class="table-cell drag-handle-cell sticky-cell">
256
+ <div class="drag-handle" title="Drag to reorder">
257
+ <svg
258
+ xmlns="http://www.w3.org/2000/svg"
259
+ width="16"
260
+ height="16"
261
+ viewBox="0 0 24 24"
262
+ fill="none"
263
+ stroke="currentColor"
264
+ stroke-width="2"
265
+ stroke-linecap="round"
266
+ stroke-linejoin="round"
267
+ >
268
+ <circle cx="9" cy="12" r="1"></circle>
269
+ <circle cx="9" cy="5" r="1"></circle>
270
+ <circle cx="9" cy="19" r="1"></circle>
271
+ <circle cx="15" cy="12" r="1"></circle>
272
+ <circle cx="15" cy="5" r="1"></circle>
273
+ <circle cx="15" cy="19" r="1"></circle>
274
+ </svg>
275
+ </div>
276
+ </td>
277
+ {/if}
128
278
  {#each tableHeaders as tableBodyItem, i}
129
279
  {#if tableBodyItem.tipo == "Text"}
130
280
  <td
131
- class="table-cell {i == 0
281
+ class="table-cell {i == 0 && !dragEnabled
132
282
  ? 'sticky-cell'
133
283
  : ''}"
134
284
  >
@@ -143,7 +293,7 @@ import ImageModal from "./ImageModal.svelte";
143
293
  </td>
144
294
  {:else if tableBodyItem.tipo == "Number"}
145
295
  <td
146
- class="table-cell {i == 0
296
+ class="table-cell {i == 0 && !dragEnabled
147
297
  ? 'sticky-cell'
148
298
  : ''}"
149
299
  >
@@ -158,7 +308,7 @@ import ImageModal from "./ImageModal.svelte";
158
308
  </td>
159
309
  {:else if tableBodyItem.tipo == "Bool"}
160
310
  <td
161
- class="table-cell {i == 0
311
+ class="table-cell {i == 0 && !dragEnabled
162
312
  ? 'sticky-cell'
163
313
  : ''}"
164
314
  >
@@ -177,7 +327,7 @@ import ImageModal from "./ImageModal.svelte";
177
327
  </td>
178
328
  {:else if tableBodyItem.tipo == "Image"}
179
329
  <td
180
- class="table-cell {i == 0
330
+ class="table-cell {i == 0 && !dragEnabled
181
331
  ? 'sticky-cell'
182
332
  : ''}"
183
333
  >
@@ -203,7 +353,7 @@ import ImageModal from "./ImageModal.svelte";
203
353
  {:else if !loading}
204
354
  <tbody>
205
355
  <tr>
206
- <td colspan={tableHeaders.length} class="no-data">
356
+ <td colspan={tableHeaders.length + (dragEnabled ? 1 : 0)} class="no-data">
207
357
  No hay datos disponibles
208
358
  </td>
209
359
  </tr>
@@ -410,4 +560,103 @@ import ImageModal from "./ImageModal.svelte";
410
560
  object-fit: contain;
411
561
  margin: auto;
412
562
  }
563
+
564
+ /* Drag and drop styles */
565
+ .drag-header {
566
+ width: 40px;
567
+ text-align: center;
568
+ cursor: default;
569
+ }
570
+
571
+ .drag-handle-header {
572
+ display: flex;
573
+ align-items: center;
574
+ justify-content: center;
575
+ color: #9ca3af;
576
+ }
577
+
578
+ .drag-handle-cell {
579
+ width: 40px;
580
+ text-align: center;
581
+ padding: 0.5rem;
582
+ cursor: grab;
583
+ border-right: 1px solid #e0e0e0;
584
+ }
585
+
586
+ .drag-handle {
587
+ display: flex;
588
+ align-items: center;
589
+ justify-content: center;
590
+ color: #9ca3af;
591
+ transition: color 0.2s;
592
+ padding: 0.25rem;
593
+ }
594
+
595
+ .drag-handle:hover {
596
+ color: #6b7280;
597
+ }
598
+
599
+ .draggable-row {
600
+ transition: all 0.3s ease;
601
+ }
602
+
603
+ .draggable-row:hover .drag-handle {
604
+ color: #4b5563;
605
+ }
606
+
607
+ .draggable-row.dragging {
608
+ opacity: 0.5;
609
+ transform: scale(0.98);
610
+ box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.2);
611
+ background-color: #f9fafb;
612
+ cursor: grabbing;
613
+ }
614
+
615
+ .draggable-row.dragging .drag-handle {
616
+ cursor: grabbing;
617
+ }
618
+
619
+ .draggable-row.drag-over {
620
+ background-color: #e0f2fe;
621
+ border-top: 2px solid #0284c7;
622
+ border-bottom: 2px solid #0284c7;
623
+ box-shadow: 0 4px 8px -2px rgba(2, 132, 199, 0.2);
624
+ }
625
+
626
+ .draggable-row.drag-over .sticky-cell {
627
+ background-color: #e0f2fe;
628
+ }
629
+
630
+ .draggable-row.drag-over .drag-handle-cell {
631
+ background-color: #e0f2fe;
632
+ }
633
+
634
+ .draggable-row.selected.drag-over {
635
+ background-color: #bfdbfe;
636
+ }
637
+
638
+ .draggable-row.selected.drag-over .sticky-cell {
639
+ background-color: #bfdbfe;
640
+ }
641
+
642
+ .draggable-row.selected.drag-over .drag-handle-cell {
643
+ background-color: #bfdbfe;
644
+ }
645
+
646
+ /* Ensure sticky cells follow drag states */
647
+ .draggable-row.dragging .sticky-cell {
648
+ background-color: #f9fafb;
649
+ }
650
+
651
+ .draggable-row.dragging .drag-handle-cell {
652
+ background-color: #f9fafb;
653
+ }
654
+
655
+ .draggable-row:hover .drag-handle-cell {
656
+ background-color: #f5f5f5;
657
+ }
658
+
659
+ .draggable-row.selected .drag-handle-cell {
660
+ background-color: #e8e8e8;
661
+ }
413
662
  </style>
@@ -5,10 +5,13 @@ declare const __propDef: {
5
5
  todosLosRegistros?: any[];
6
6
  tableHeaders: TableHeader[];
7
7
  loading?: boolean;
8
+ dragEnabled?: boolean;
9
+ orderField?: string;
8
10
  };
9
11
  events: {
10
12
  rowClick: CustomEvent<any>;
11
13
  selectedSort: CustomEvent<any>;
14
+ reorderChange: CustomEvent<any>;
12
15
  } & {
13
16
  [evt: string]: CustomEvent<any>;
14
17
  };
@@ -25,7 +25,7 @@
25
25
  on:mouseenter={() => (showTooltip = button.tooltip)}
26
26
  on:mouseleave={() => (showTooltip = "")}
27
27
  type="button"
28
- class="action-buttons-group {i == 0 ? 'rounded-left' : i == visibleButtons.length - 1 ? 'rounded-right' : ''} {button.color}"
28
+ class="action-buttons-group {visibleButtons.length === 1 ? 'rounded-left rounded-right' : i == 0 ? 'rounded-left' : i == visibleButtons.length - 1 ? 'rounded-right' : ''} {button.color}"
29
29
  >
30
30
  <i class={button.icon}> </i>
31
31
  </button>
@@ -18,10 +18,13 @@ import { ModalContainer } from "../Modals/index.js";
18
18
  export let showAddButton: boolean = true;
19
19
  export let showImportButton: boolean = true;
20
20
  export let Titulo_Crud: string;
21
+ export let dragEnabled: boolean = false;
22
+ export let orderField: string = 'inOrden';
21
23
 
22
24
  // Event handlers from parent
23
25
  export let onFilter: (filters: FiltrosI[]) => void;
24
26
  export let onAdd: () => void;
27
+ export let onReorder: (reorderedItems: any[]) => void = () => {};
25
28
 
26
29
  function handleFiltroAplicado() {
27
30
  onFilter(Filtros);
@@ -65,6 +68,16 @@ import { ModalContainer } from "../Modals/index.js";
65
68
  createPDF(table);
66
69
  }
67
70
  }
71
+
72
+ interface ReorderEvent {
73
+ detail: {
74
+ reorderedItems: any[];
75
+ };
76
+ }
77
+
78
+ function handleReorder(event: ReorderEvent) {
79
+ onReorder(event.detail.reorderedItems);
80
+ }
68
81
  </script>
69
82
 
70
83
  <div class="crud-wrapper">
@@ -81,7 +94,10 @@ import { ModalContainer } from "../Modals/index.js";
81
94
  tableHeaders={tableH}
82
95
  todosLosRegistros={todosLosObjetos}
83
96
  on:selectedSort={handleSort}
97
+ on:reorderChange={handleReorder}
84
98
  {loading}
99
+ {dragEnabled}
100
+ {orderField}
85
101
  />
86
102
  <PaginationCrud
87
103
  perPage={PageSize}
@@ -14,8 +14,11 @@ declare const __propDef: {
14
14
  showAddButton?: boolean;
15
15
  showImportButton?: boolean;
16
16
  Titulo_Crud: string;
17
+ dragEnabled?: boolean;
18
+ orderField?: string;
17
19
  onFilter: (filters: FiltrosI[]) => void;
18
20
  onAdd: () => void;
21
+ onReorder?: (reorderedItems: any[]) => void;
19
22
  };
20
23
  events: {
21
24
  [evt: string]: CustomEvent<any>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "grav-svelte",
3
- "version": "0.0.35",
3
+ "version": "0.0.37",
4
4
  "description": "A collection of Svelte components",
5
5
  "license": "MIT",
6
6
  "scripts": {