@itfin/components 1.2.96 → 1.2.98
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/package.json +9 -9
- package/src/assets/scss/_css_variables.scss +11 -0
- package/src/components/datepicker/DatePicker.vue +11 -0
- package/src/components/datepicker/DateRangePicker.vue +2 -0
- package/src/components/dropdown/Dropdown.vue +12 -1
- package/src/components/editable/EditableElement.vue +112 -0
- package/src/components/editable/index.stories.js +53 -0
- package/src/components/table/Sortable.js +288 -0
- package/src/components/table/Table2.vue +85 -20
- package/src/components/table/TableBody.vue +67 -25
- package/src/components/table/TableGroup.vue +171 -81
- package/src/components/table/TableHeader.vue +189 -58
- package/src/components/table/draggable.js +161 -0
- package/src/components/table/event.js +57 -0
- package/src/components/table/index.stories.js +80 -5
- package/src/locales/uk.js +36 -0
|
@@ -2,45 +2,91 @@
|
|
|
2
2
|
|
|
3
3
|
<div class="itf-table-header">
|
|
4
4
|
<div ref="container" class="table-row-template">
|
|
5
|
-
<div accept-group="items" class="table-view-body-space"></div>
|
|
6
|
-
<div class="
|
|
5
|
+
<div accept-group="items" class="table-view-body-space" v-dropzone="{ payload: 0 }"></div>
|
|
6
|
+
<div class="shadow-area"></div>
|
|
7
7
|
<div class="table-view-header-value reserved sticky"></div>
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
<template v-for="(column, n) in visibleAttributes">
|
|
10
|
+
<div
|
|
11
|
+
v-if="column.visible !== false"
|
|
12
|
+
:key="n"
|
|
13
|
+
data-test="table-header-column"
|
|
14
|
+
:data-column="n"
|
|
15
|
+
:data-id="column.Id"
|
|
16
|
+
:class="{'sticky': column.pinned, 'last-sticky-column': n === lastPinnedIndex}"
|
|
17
|
+
class="table-view-header-value"
|
|
18
|
+
:style="`width: ${column.width}px; left: ${column.left}px;`">
|
|
19
|
+
<div accept-group="tablecolumns"
|
|
20
|
+
class="table-view-header-space"
|
|
21
|
+
@enter="columnHighlight(n, 'enter')"
|
|
22
|
+
@leave="columnHighlight(n, 'leave')"
|
|
23
|
+
v-dropzone="{ payload: { index: n, attribute: column } }">
|
|
12
24
|
<div class="table-view-header-dropzone"></div>
|
|
13
25
|
</div>
|
|
14
|
-
<div group="tablecolumns"
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
26
|
+
<div group="tablecolumns"
|
|
27
|
+
class="table-header"
|
|
28
|
+
@drop="reorderColumns"
|
|
29
|
+
v-drag-handle
|
|
30
|
+
v-draggable="{ handle: true, payload: { index: n, item: column }, mirror: {yAxis:false} }">
|
|
31
|
+
<itf-dropdown text append-to-body shadow ref="dropdown" class="w-100">
|
|
32
|
+
<template #button>
|
|
33
|
+
<span :title="column.text">
|
|
34
|
+
<!-- <itf-icon name="type_select" :size="16" />-->
|
|
35
|
+
{{column.text}}
|
|
36
|
+
</span>
|
|
37
|
+
</template>
|
|
24
38
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
<ul class="dropdown-menu show ps-0" aria-labelledby="dropdownMenuOffset">
|
|
40
|
+
<li v-if="column.sortable">
|
|
41
|
+
<a class="dropdown-item d-flex align-items-center" href="javascript:;">
|
|
42
|
+
<itf-icon name="arrow_up" :size="16" class="me-1" />
|
|
43
|
+
Sort By Asc
|
|
44
|
+
</a>
|
|
45
|
+
</li>
|
|
46
|
+
<li v-if="column.sortable">
|
|
47
|
+
<a class="dropdown-item d-flex align-items-center" href="javascript:;">
|
|
48
|
+
<itf-icon name="arrow_down" :size="16" class="me-1" />
|
|
49
|
+
Sort By Desc
|
|
50
|
+
</a>
|
|
51
|
+
</li>
|
|
52
|
+
<li v-if="column.groupable">
|
|
53
|
+
<a class="dropdown-item d-flex align-items-center" href="javascript:;">
|
|
54
|
+
<itf-icon name="episodes" :size="16" class="me-1" />
|
|
55
|
+
Group By
|
|
56
|
+
</a>
|
|
57
|
+
</li>
|
|
58
|
+
<li>
|
|
59
|
+
<a class="dropdown-item d-flex align-items-center" href="javascript:;" @click="togglePinned(n)">
|
|
60
|
+
<itf-icon :name="column.pinned ? 'checkbox_checked' : 'checkbox_empty'" :size="16" class="me-1" />
|
|
61
|
+
<span v-if="column.pinned">Unpin Column</span>
|
|
62
|
+
<span v-else>Pin Column</span>
|
|
63
|
+
</a>
|
|
64
|
+
</li>
|
|
65
|
+
<li>
|
|
66
|
+
<a class="dropdown-item d-flex align-items-center" href="javascript:;" @click="hideColumn(n)">
|
|
67
|
+
<itf-icon name="eye_no" :size="16" class="me-1" />
|
|
68
|
+
Hide
|
|
69
|
+
</a>
|
|
70
|
+
</li>
|
|
71
|
+
</ul>
|
|
72
|
+
</itf-dropdown>
|
|
73
|
+
</div>
|
|
74
|
+
<div v-if="n === sortedColumns.length - 1"
|
|
75
|
+
@enter="columnHighlightLast('enter')"
|
|
76
|
+
@leave="columnHighlightLast('leave')"
|
|
77
|
+
accept-group="tablecolumns"
|
|
78
|
+
class="table-view-header-space right"
|
|
79
|
+
v-dropzone="{payload:{ last: true }}">
|
|
80
|
+
<div class="table-view-header-dropzone"></div>
|
|
41
81
|
</div>
|
|
82
|
+
<div v-if="columnResizing" ref="resizeHandle" class="resize-handle"></div>
|
|
42
83
|
</div>
|
|
43
|
-
</
|
|
84
|
+
</template>
|
|
85
|
+
<div v-if="showAddColumn" class="table-view-header-value">
|
|
86
|
+
<span class="table-header table-header-add-column" data-test="table-header-add-column" @click.prevent="$emit('add-column')">
|
|
87
|
+
<itf-icon name="plus" />
|
|
88
|
+
</span>
|
|
89
|
+
</div>
|
|
44
90
|
</div>
|
|
45
91
|
</div>
|
|
46
92
|
|
|
@@ -50,15 +96,22 @@
|
|
|
50
96
|
position: sticky;
|
|
51
97
|
top: 0;
|
|
52
98
|
z-index: calc(var(--row-count) + 1);
|
|
99
|
+
border-top: 1px solid var(--bs-border-color);
|
|
53
100
|
|
|
101
|
+
.table-header.draggable-mirror{
|
|
102
|
+
z-index: 100000001;
|
|
103
|
+
background: rgba(235,237,239,0.75);
|
|
104
|
+
}
|
|
54
105
|
.table-row-template {
|
|
55
106
|
display: flex;
|
|
56
107
|
align-items: stretch;
|
|
57
108
|
height: var(--table-small-row-size);
|
|
109
|
+
user-select: none;
|
|
58
110
|
}
|
|
59
111
|
.table-view-header-value {
|
|
112
|
+
cursor: pointer;
|
|
60
113
|
align-items: center;
|
|
61
|
-
height:
|
|
114
|
+
height: var(--table-row-height);
|
|
62
115
|
white-space: nowrap;
|
|
63
116
|
border-top: 0;
|
|
64
117
|
border-left: 0;
|
|
@@ -67,9 +120,12 @@
|
|
|
67
120
|
border-style: solid;
|
|
68
121
|
position: relative;
|
|
69
122
|
display: flex;
|
|
70
|
-
|
|
71
|
-
border-
|
|
72
|
-
|
|
123
|
+
min-width: var(--table-min-width);
|
|
124
|
+
border-right-color: var(--bs-border-color);
|
|
125
|
+
border-bottom-color: var(--bs-border-color);
|
|
126
|
+
background-color: var(--bs-body-bg);
|
|
127
|
+
//background-color: rgb(238 238 238 / 1);
|
|
128
|
+
font-weight: 500;
|
|
73
129
|
|
|
74
130
|
&.reserved {
|
|
75
131
|
left: var(--shadow-area-width);
|
|
@@ -91,11 +147,14 @@
|
|
|
91
147
|
padding-right: 0.75rem;
|
|
92
148
|
gap: 0.25rem;
|
|
93
149
|
align-items: center;
|
|
94
|
-
|
|
150
|
+
|
|
151
|
+
&.table-header-add-column {
|
|
152
|
+
text-overflow: clip;
|
|
153
|
+
}
|
|
95
154
|
}
|
|
96
155
|
.resize-handle {
|
|
97
156
|
width: 4px;
|
|
98
|
-
height:
|
|
157
|
+
height: var(--table-row-height);
|
|
99
158
|
position: absolute;
|
|
100
159
|
right: -2px;
|
|
101
160
|
top: 0;
|
|
@@ -111,7 +170,6 @@
|
|
|
111
170
|
}
|
|
112
171
|
}
|
|
113
172
|
.context-menu-toggle {
|
|
114
|
-
display: flex;
|
|
115
173
|
flex: 1 1 auto;
|
|
116
174
|
text-overflow: ellipsis;
|
|
117
175
|
white-space: nowrap;
|
|
@@ -134,6 +192,18 @@
|
|
|
134
192
|
z-index: 100;
|
|
135
193
|
width: 2px;
|
|
136
194
|
margin-left: -1px;
|
|
195
|
+
|
|
196
|
+
&.right {
|
|
197
|
+
left: auto;
|
|
198
|
+
right: 0;
|
|
199
|
+
top: 0;
|
|
200
|
+
}
|
|
201
|
+
&.active {
|
|
202
|
+
display: block;
|
|
203
|
+
&.over {
|
|
204
|
+
background: #47BEFF;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
137
207
|
}
|
|
138
208
|
.draggable-mirror {
|
|
139
209
|
opacity: .5;
|
|
@@ -163,11 +233,13 @@
|
|
|
163
233
|
import { Vue, Component, Prop, PropSync } from 'vue-property-decorator';
|
|
164
234
|
import itfButton from '../button/Button.vue';
|
|
165
235
|
import itfIcon from '../icon/Icon.vue';
|
|
166
|
-
import { Draggable
|
|
236
|
+
import { Draggable } from './draggable';
|
|
237
|
+
import itfDropdown from '../dropdown/Dropdown.vue';
|
|
167
238
|
|
|
168
239
|
export default @Component({
|
|
169
240
|
name: 'itfTableHeader',
|
|
170
241
|
components: {
|
|
242
|
+
itfDropdown,
|
|
171
243
|
itfButton,
|
|
172
244
|
itfIcon
|
|
173
245
|
}
|
|
@@ -176,22 +248,60 @@ class itfTable extends Vue {
|
|
|
176
248
|
@PropSync('columns', { type: Array, default: () => ([]) }) sortedColumns;
|
|
177
249
|
@Prop(Boolean) columnSorting;
|
|
178
250
|
@Prop(Boolean) columnResizing;
|
|
251
|
+
@Prop(Boolean) showAddColumn;
|
|
179
252
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
253
|
+
get visibleAttributes() {
|
|
254
|
+
return this.sortedColumns;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
get lastPinnedIndex() {
|
|
258
|
+
return this.sortedColumns.findIndex((column) => column.lastPinned);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
onSort(items) {
|
|
262
|
+
console.info(items);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
reorderColumns({ detail }) {
|
|
266
|
+
const { index: fromIndex } = detail.draggablePayload;
|
|
267
|
+
const { index: toIndex, last } = detail.dropzonePayload;
|
|
268
|
+
const newValue = [...this.sortedColumns];
|
|
269
|
+
const [removed] = newValue.splice(fromIndex, 1);
|
|
270
|
+
let putIndex = (removed.pinned && toIndex > this.lastPinnedIndex + 1) ? this.lastPinnedIndex : toIndex;
|
|
271
|
+
if (!removed.pinned && toIndex <= this.lastPinnedIndex) {
|
|
272
|
+
putIndex = this.lastPinnedIndex + 1;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
if (last) {
|
|
276
|
+
newValue.push(removed);
|
|
277
|
+
} else {
|
|
278
|
+
newValue.splice((fromIndex < putIndex) ? putIndex - 1 : putIndex, 0, removed);
|
|
279
|
+
}
|
|
280
|
+
this.$emit('sort:columns', newValue);
|
|
281
|
+
if (last) {
|
|
282
|
+
this.columnHighlightLast('leave');
|
|
283
|
+
} else {
|
|
284
|
+
this.columnHighlight(toIndex, 'leave');
|
|
285
|
+
}
|
|
286
|
+
for (const dropdown of this.$refs.dropdown) {
|
|
287
|
+
dropdown.hide();
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
columnHighlight(index, state) {
|
|
292
|
+
Array.from(document.querySelectorAll(`[data-column="${index}"]`)).forEach(t=>{
|
|
293
|
+
state === "enter" ? t.classList.add("highlight-drop-column") : t.classList.remove("highlight-drop-column")
|
|
188
294
|
});
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
295
|
+
}
|
|
296
|
+
columnHighlightLast(state) {
|
|
297
|
+
Array.from(document.querySelectorAll(`[data-column="${this.sortedColumns.length - 1}"]`)).forEach(t=>{
|
|
298
|
+
if (state === "enter") {
|
|
299
|
+
t.classList.add("highlight-drop-column");
|
|
300
|
+
t.classList.add("right");
|
|
301
|
+
} else {
|
|
302
|
+
t.classList.remove("highlight-drop-column");
|
|
303
|
+
t.classList.remove("right");
|
|
304
|
+
}
|
|
195
305
|
});
|
|
196
306
|
}
|
|
197
307
|
|
|
@@ -205,16 +315,18 @@ class itfTable extends Vue {
|
|
|
205
315
|
const startX = event.pageX;
|
|
206
316
|
const index = column.getAttribute('data-column');
|
|
207
317
|
const columns = body.querySelectorAll(`[data-column="${index}"]`);
|
|
318
|
+
let newWidth;
|
|
208
319
|
const mouseMoveHandler = (event) => {
|
|
209
320
|
const delta = event.pageX - startX;
|
|
321
|
+
newWidth = Math.max(columnWidth + delta, 100);
|
|
210
322
|
columns.forEach((column) => {
|
|
211
|
-
column.style.width = `${
|
|
323
|
+
column.style.width = `${newWidth}px`;
|
|
212
324
|
});
|
|
213
|
-
this.changeColumn(index, { width: columnWidth + delta });
|
|
214
325
|
};
|
|
215
326
|
const mouseUpHandler = () => {
|
|
216
327
|
document.removeEventListener('mousemove', mouseMoveHandler);
|
|
217
328
|
document.removeEventListener('mouseup', mouseUpHandler);
|
|
329
|
+
this.changeColumn(index, { width: newWidth });
|
|
218
330
|
};
|
|
219
331
|
document.addEventListener('mousemove', mouseMoveHandler);
|
|
220
332
|
document.addEventListener('mouseup', mouseUpHandler);
|
|
@@ -222,9 +334,15 @@ class itfTable extends Vue {
|
|
|
222
334
|
});
|
|
223
335
|
}
|
|
224
336
|
|
|
337
|
+
beforeDestroy() {
|
|
338
|
+
if (this.columnSorting) {
|
|
339
|
+
Draggable.removeContainer(this.$refs.container);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
225
343
|
mounted() {
|
|
226
344
|
if (this.columnSorting) {
|
|
227
|
-
this.
|
|
345
|
+
Draggable.addContainer(this.$refs.container);
|
|
228
346
|
}
|
|
229
347
|
if (this.columnResizing) {
|
|
230
348
|
this.initResizing();
|
|
@@ -232,7 +350,20 @@ class itfTable extends Vue {
|
|
|
232
350
|
}
|
|
233
351
|
|
|
234
352
|
changeColumn(index, params) {
|
|
235
|
-
|
|
353
|
+
this.$refs.dropdown[index].hide();
|
|
354
|
+
let newValue = [...this.sortedColumns];
|
|
355
|
+
const newItem = { ...newValue[index] };
|
|
356
|
+
Object.assign(newItem, params);
|
|
357
|
+
newValue[index] = newItem;
|
|
358
|
+
this.$emit('update:columns', newValue);
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
hideColumn(index) {
|
|
362
|
+
this.changeColumn(index, { visible: false });
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
togglePinned(index) {
|
|
366
|
+
this.changeColumn(index, { pinned: !this.sortedColumns[index].pinned });
|
|
236
367
|
}
|
|
237
368
|
}
|
|
238
369
|
</script>
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import Vue from 'vue';
|
|
2
|
+
import { Draggable } from '@shopify/draggable';
|
|
3
|
+
import DraggableEvent from './event';
|
|
4
|
+
|
|
5
|
+
const DRAGGABLE_CLASS = 'draggable-item'
|
|
6
|
+
const DRAG_HANDLE_CLASS = 'drag-handle'
|
|
7
|
+
const SORTABLE_ATTRIBUTES = ['drag-ignore-handle', 'scrollable'];
|
|
8
|
+
|
|
9
|
+
const draggableNode = new Draggable([], {
|
|
10
|
+
draggableClass: DRAGGABLE_CLASS,
|
|
11
|
+
dragHandleClass: DRAG_HANDLE_CLASS,
|
|
12
|
+
delay: 200,
|
|
13
|
+
tresholdDistance: 2,
|
|
14
|
+
draggable: `.${DRAGGABLE_CLASS}`,
|
|
15
|
+
handle: `.${DRAG_HANDLE_CLASS}`,
|
|
16
|
+
ignoreHandleClassList: SORTABLE_ATTRIBUTES,
|
|
17
|
+
mirror: {
|
|
18
|
+
yAxis: false,
|
|
19
|
+
constrainDimensions: !0
|
|
20
|
+
},
|
|
21
|
+
scrollable: {
|
|
22
|
+
speed: 20,
|
|
23
|
+
sensitivity: 80
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
export {draggableNode as Draggable};
|
|
28
|
+
|
|
29
|
+
Vue.directive('DragHandle', {
|
|
30
|
+
inserted(el) {
|
|
31
|
+
if (el.getAttribute("drag-disabled") !== "true") {
|
|
32
|
+
el.classList.add(DRAG_HANDLE_CLASS);
|
|
33
|
+
} else {
|
|
34
|
+
el.classList.remove(DRAG_HANDLE_CLASS);
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
update(el) {
|
|
38
|
+
if (el.getAttribute("drag-disabled") !== "true") {
|
|
39
|
+
el.classList.add(DRAG_HANDLE_CLASS);
|
|
40
|
+
} else {
|
|
41
|
+
el.classList.remove(DRAG_HANDLE_CLASS);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
Vue.directive("dropzone", {
|
|
47
|
+
inserted(el, {value}) {
|
|
48
|
+
// console.log('dropzone');
|
|
49
|
+
el.over = false;
|
|
50
|
+
el.dropzonePayload = value.payload;
|
|
51
|
+
el.dropCondition = value.condition;
|
|
52
|
+
|
|
53
|
+
el.dropzoneDragMove = event => {
|
|
54
|
+
// console.log('dropzone event', event);
|
|
55
|
+
el.initialized || (el.initialized = !0,
|
|
56
|
+
el.getAttribute("accept-group").split(",").includes(event.group) && (el.classList.add("active"),
|
|
57
|
+
draggableNode.on("drag:move", el.onDragMoveReal),
|
|
58
|
+
el.event = event))
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
el.onDragMoveReal = event => {
|
|
62
|
+
const { target } = event.sensorEvent;
|
|
63
|
+
if (target === el || el.contains(target)) {
|
|
64
|
+
el.over === false && (!el.dropCondition || el.dropCondition({
|
|
65
|
+
dropzonePayload: el.dropzonePayload,
|
|
66
|
+
draggablePayload: el.event.data.draggablePayload
|
|
67
|
+
})) && (el.dispatchEvent(new Event("enter")), el.classList.add("over"), el.over = !0)
|
|
68
|
+
} else {
|
|
69
|
+
el.over === !0 && (el.dispatchEvent(new Event("leave")), el.classList.remove("over"), el.over = !1);
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
el.onDragStop = (event) => {
|
|
74
|
+
if (draggableNode.off("drag:move", el.onDragMoveReal),
|
|
75
|
+
el.classList.remove("active"),
|
|
76
|
+
el.initialized = false,
|
|
77
|
+
!el.over) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
el.classList.remove("over");
|
|
81
|
+
el.over = false;
|
|
82
|
+
const detail = {
|
|
83
|
+
...el.event.data,
|
|
84
|
+
// dropzonePayload: p()(el.dropzonePayload),
|
|
85
|
+
dropzonePayload: el.dropzonePayload,
|
|
86
|
+
newComponent: el
|
|
87
|
+
};
|
|
88
|
+
el.dispatchEvent(new CustomEvent("receive", {detail}));
|
|
89
|
+
el.event.sourceComponent.dispatchEvent(new CustomEvent("drop", {detail}));
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
draggableNode.on("vue:drag:move", el.dropzoneDragMove).on("drag:stop", el.onDragStop),
|
|
93
|
+
draggableNode.dragging && el.dropzoneDragMove(draggableNode.lastEvent)
|
|
94
|
+
},
|
|
95
|
+
update(el, {value}) {
|
|
96
|
+
el.dropzonePayload = value.payload
|
|
97
|
+
},
|
|
98
|
+
unbind(el) {
|
|
99
|
+
draggableNode.off("vue:drag:move", el.dropzoneDragMove).off("drag:stop", el.onDragStop).off("drag:move", el.onDragMoveReal)
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
Vue.directive("draggable", {
|
|
104
|
+
inserted(el, {value}) {
|
|
105
|
+
// console.log('directive - draggable');
|
|
106
|
+
el.currentDraggablePayload = value?.payload;
|
|
107
|
+
el.classList.add(draggableNode.options.draggableClass);
|
|
108
|
+
value?.handle && el.classList.add(draggableNode.options.dragHandleClass);
|
|
109
|
+
value?.mirror && (el.dataset.draggableMirror = JSON.stringify(value.mirror));
|
|
110
|
+
|
|
111
|
+
el.onDragStart = event => {
|
|
112
|
+
// console.log('drag start', el.currentDraggablePayload)
|
|
113
|
+
if (draggableNode.options.ignoreHandleClassList.some(M => event.sensorEvent.target.classList.contains(M))) {
|
|
114
|
+
event.cancel();
|
|
115
|
+
return
|
|
116
|
+
}
|
|
117
|
+
if (el === event.originalEvent.target.closest("." + draggableNode.options.draggableClass)) {
|
|
118
|
+
if (event.originalEvent.target.tagName === "INPUT") {
|
|
119
|
+
event.cancel();
|
|
120
|
+
return
|
|
121
|
+
}
|
|
122
|
+
el.draggablePayload = el.currentDraggablePayload;
|
|
123
|
+
draggableNode.on("drag:move", el.dragMove);
|
|
124
|
+
draggableNode.on("drag:stop", el.dragStop);
|
|
125
|
+
el.dispatchEvent(new Event("drag-start"));
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
el.dragMove = () => {
|
|
130
|
+
// console.log('onDragMove')
|
|
131
|
+
const D = new DraggableEvent({
|
|
132
|
+
draggablePayload: el.draggablePayload,
|
|
133
|
+
sourceComponent: el,
|
|
134
|
+
group: el.getAttribute("group")
|
|
135
|
+
});
|
|
136
|
+
draggableNode.trigger(D);
|
|
137
|
+
draggableNode.lastEvent = D;
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
el.dragStop = () => {
|
|
141
|
+
draggableNode.off("drag:move", el.dragMove);
|
|
142
|
+
draggableNode.off("drag:stop", el.dragStop);
|
|
143
|
+
}
|
|
144
|
+
draggableNode.on("drag:start", el.onDragStart);
|
|
145
|
+
},
|
|
146
|
+
update(el, { value }) {
|
|
147
|
+
el.classList.add(draggableNode.options.draggableClass);
|
|
148
|
+
el.currentDraggablePayload = value?.payload;
|
|
149
|
+
value?.mirror && (el.dataset.draggableMirror = JSON.stringify(value.mirror));
|
|
150
|
+
if (value?.handle) {
|
|
151
|
+
el.classList.add(draggableNode.options.dragHandleClass);
|
|
152
|
+
} else {
|
|
153
|
+
el.classList.remove(draggableNode.options.dragHandleClass);
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
unbind(el) {
|
|
157
|
+
draggableNode.off("drag:start", el.onDragStart);
|
|
158
|
+
draggableNode.off("drag:move", el.dragMove);
|
|
159
|
+
draggableNode.off("drag:stop", el.dragStop);
|
|
160
|
+
}
|
|
161
|
+
})
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
const CANCELED = Symbol("canceled");
|
|
2
|
+
|
|
3
|
+
export
|
|
4
|
+
class CancelableEvent {
|
|
5
|
+
static type = "event";
|
|
6
|
+
|
|
7
|
+
static cancelable = false;
|
|
8
|
+
|
|
9
|
+
constructor(f) {
|
|
10
|
+
this[CANCELED] = false,
|
|
11
|
+
this.data = f
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
get type() {
|
|
15
|
+
return this.constructor.type
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
get cancelable() {
|
|
19
|
+
return this.constructor.cancelable
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
cancel() {
|
|
23
|
+
this[CANCELED] = true
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
canceled() {
|
|
27
|
+
return !!this[CANCELED]
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
clone(f) {
|
|
31
|
+
return new this.constructor({
|
|
32
|
+
...this.data,
|
|
33
|
+
...f
|
|
34
|
+
})
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export default
|
|
39
|
+
class DraggableEvent extends CancelableEvent {
|
|
40
|
+
static type = "vue:drag:move";
|
|
41
|
+
|
|
42
|
+
get sourceComponent() {
|
|
43
|
+
return this.data.sourceComponent
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
get group() {
|
|
47
|
+
return this.data.group
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
get item() {
|
|
51
|
+
return this.data.item
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
get draggablePayload() {
|
|
55
|
+
return this.data.draggablePayload
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -81,17 +81,24 @@ storiesOf('Common', module)
|
|
|
81
81
|
},
|
|
82
82
|
data() {
|
|
83
83
|
return {
|
|
84
|
-
list: Array.from({length:
|
|
84
|
+
list: Array.from({length: 20}).map((_, i) => ({
|
|
85
85
|
Id: i,
|
|
86
|
-
text:
|
|
86
|
+
text: `Рахунок ✅`,
|
|
87
87
|
Name: `Item #${i}`
|
|
88
|
-
})),
|
|
88
|
+
})).concat(Array.from({length: 20}).map((_, i) => ({
|
|
89
|
+
Id: i,
|
|
90
|
+
text: `Рахунок ❌`,
|
|
91
|
+
Name: `Item #${i}`
|
|
92
|
+
}))),
|
|
89
93
|
columns: [{
|
|
90
94
|
text: 'Рахунок',
|
|
91
95
|
name: 'Account',
|
|
92
96
|
width: 200,
|
|
93
97
|
min: 250,
|
|
94
|
-
max: 250
|
|
98
|
+
max: 250,
|
|
99
|
+
sortable: true,
|
|
100
|
+
groupable: true,
|
|
101
|
+
pinned: true
|
|
95
102
|
}, {
|
|
96
103
|
text: 'Dr',
|
|
97
104
|
name: 'Total',
|
|
@@ -101,6 +108,67 @@ storiesOf('Common', module)
|
|
|
101
108
|
],
|
|
102
109
|
width: 200,
|
|
103
110
|
min: 150,
|
|
111
|
+
max: 150,
|
|
112
|
+
pinned: true
|
|
113
|
+
}, {
|
|
114
|
+
text: 'Cr 1',
|
|
115
|
+
name: 'Total',
|
|
116
|
+
Type: 'select',
|
|
117
|
+
Options: [
|
|
118
|
+
{ Id: 1, Name: 'test' }
|
|
119
|
+
],
|
|
120
|
+
width: 200,
|
|
121
|
+
min: 150,
|
|
122
|
+
max: 150
|
|
123
|
+
}, {
|
|
124
|
+
text: 'Cr 2',
|
|
125
|
+
name: 'Total',
|
|
126
|
+
Type: 'select',
|
|
127
|
+
Options: [
|
|
128
|
+
{ Id: 1, Name: 'test' }
|
|
129
|
+
],
|
|
130
|
+
width: 200,
|
|
131
|
+
min: 150,
|
|
132
|
+
max: 150
|
|
133
|
+
}, {
|
|
134
|
+
text: 'Cr 3',
|
|
135
|
+
name: 'Total',
|
|
136
|
+
Type: 'select',
|
|
137
|
+
Options: [
|
|
138
|
+
{ Id: 1, Name: 'test' }
|
|
139
|
+
],
|
|
140
|
+
width: 200,
|
|
141
|
+
min: 150,
|
|
142
|
+
max: 150
|
|
143
|
+
}, {
|
|
144
|
+
text: 'Cr 4',
|
|
145
|
+
name: 'Total',
|
|
146
|
+
Type: 'select',
|
|
147
|
+
Options: [
|
|
148
|
+
{ Id: 1, Name: 'test' }
|
|
149
|
+
],
|
|
150
|
+
width: 200,
|
|
151
|
+
min: 150,
|
|
152
|
+
max: 150
|
|
153
|
+
}, {
|
|
154
|
+
text: 'Cr',
|
|
155
|
+
name: 'Total',
|
|
156
|
+
Type: 'select',
|
|
157
|
+
Options: [
|
|
158
|
+
{ Id: 1, Name: 'test' }
|
|
159
|
+
],
|
|
160
|
+
width: 200,
|
|
161
|
+
min: 150,
|
|
162
|
+
max: 150
|
|
163
|
+
}, {
|
|
164
|
+
text: 'Cr',
|
|
165
|
+
name: 'Total',
|
|
166
|
+
Type: 'select',
|
|
167
|
+
Options: [
|
|
168
|
+
{ Id: 1, Name: 'test' }
|
|
169
|
+
],
|
|
170
|
+
width: 200,
|
|
171
|
+
min: 150,
|
|
104
172
|
max: 150
|
|
105
173
|
}, {
|
|
106
174
|
text: 'Cr',
|
|
@@ -115,6 +183,11 @@ storiesOf('Common', module)
|
|
|
115
183
|
}]
|
|
116
184
|
}
|
|
117
185
|
},
|
|
186
|
+
methods: {
|
|
187
|
+
onAdd() {
|
|
188
|
+
console.info('add')
|
|
189
|
+
}
|
|
190
|
+
},
|
|
118
191
|
template: `<div>
|
|
119
192
|
<p>You need wrap whole application with this tag</p>
|
|
120
193
|
|
|
@@ -131,7 +204,9 @@ storiesOf('Common', module)
|
|
|
131
204
|
|
|
132
205
|
<h3>Example</h3>
|
|
133
206
|
|
|
134
|
-
<itf-table2
|
|
207
|
+
<itf-table2
|
|
208
|
+
group-by="text"
|
|
209
|
+
:columns.sync="columns" :rows="list" column-sorting column-resizing show-add-column show-grouping @add-column="onAdd">
|
|
135
210
|
<template #column.Account="{ item }">
|
|
136
211
|
{{item.text}}
|
|
137
212
|
</template>
|