@itfin/components 1.2.85 → 1.2.87
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 +4 -3
- package/src/components/customize/PropertiesEditMenu.vue +53 -0
- package/src/components/customize/PropertiesItemsMenu.vue +33 -0
- package/src/components/customize/PropertiesList.vue +179 -0
- package/src/components/customize/PropertiesPopupMenu.vue +46 -0
- package/src/components/customize/PropertyInlineEdit.vue +46 -0
- package/src/components/customize/index.stories.js +65 -0
- package/src/components/dropdown/Dropdown.vue +8 -19
- package/src/components/icon/components/type_checkbox.vue +2 -0
- package/src/components/icon/components/type_date.vue +2 -0
- package/src/components/icon/components/type_email.vue +2 -0
- package/src/components/icon/components/type_file.vue +2 -0
- package/src/components/icon/components/type_formula.vue +2 -0
- package/src/components/icon/components/type_id.vue +2 -0
- package/src/components/icon/components/type_multiselect.vue +2 -0
- package/src/components/icon/components/type_number.vue +2 -0
- package/src/components/icon/components/type_person.vue +2 -0
- package/src/components/icon/components/type_phone.vue +2 -0
- package/src/components/icon/components/type_relation.vue +2 -0
- package/src/components/icon/components/type_select.vue +2 -0
- package/src/components/icon/components/type_status.vue +2 -0
- package/src/components/icon/components/type_text.vue +2 -0
- package/src/components/icon/components/type_time.vue +2 -0
- package/src/components/icon/components/type_url.vue +2 -0
- package/src/components/icon/components/type_user.vue +2 -0
- package/src/components/icon/icons/type_checkbox.svg +1 -0
- package/src/components/icon/icons/type_date.svg +1 -0
- package/src/components/icon/icons/type_email.svg +1 -0
- package/src/components/icon/icons/type_file.svg +1 -0
- package/src/components/icon/icons/type_formula.svg +1 -0
- package/src/components/icon/icons/type_id.svg +1 -0
- package/src/components/icon/icons/type_multiselect.svg +1 -0
- package/src/components/icon/icons/type_number.svg +1 -0
- package/src/components/icon/icons/type_person.svg +1 -0
- package/src/components/icon/icons/type_phone.svg +1 -0
- package/src/components/icon/icons/type_relation.svg +1 -0
- package/src/components/icon/icons/type_select.svg +1 -0
- package/src/components/icon/icons/type_status.svg +1 -0
- package/src/components/icon/icons/type_text.svg +1 -0
- package/src/components/icon/icons/type_time.svg +1 -0
- package/src/components/icon/icons/type_url.svg +1 -0
- package/src/components/icon/icons/type_user.svg +1 -0
- package/src/components/icon/icons.js +295 -278
- package/src/components/modal/DeleteConfirmModal.vue +78 -0
- package/src/components/modal/ItemEditor.vue +217 -0
- package/src/components/modal/Modal.vue +15 -13
- package/src/components/modal/index.stories.js +15 -10
- package/src/components/popover/ConfirmPopover.vue +1 -1
- package/src/components/popover/DeleteConfirmPopover.vue +39 -0
- package/src/components/popover/IconPopover.vue +136 -0
- package/src/components/popover/SelectPopover.vue +127 -0
- package/src/components/popover/index.stories.js +26 -10
- package/src/components/sortable/AutoScroll.vue +142 -0
- package/src/components/sortable/Sortable.scss +93 -0
- package/src/components/sortable/Sortable.vue +399 -0
- package/src/components/sortable/sortable-item-list/axis.js +9 -0
- package/src/components/sortable/sortable-item-list/mocked-sortable-item-list.js +415 -0
- package/src/components/sortable/sortable-item-list/original-sortable-item-list.js +105 -0
- package/src/components/sortable/utils/event-outside.js +30 -0
- package/src/components/sortable/utils/get-relative-position.js +41 -0
- package/src/components/sortable/utils/sort-item-list.js +13 -0
- package/src/components/sortable/utils/stop-event.js +16 -0
- package/src/components/sortable/utils/vibrate.js +18 -0
- package/src/components/text-field/MoneyField.vue +112 -0
- package/src/components/text-field/index.stories.js +53 -0
- package/src/directives/tooltip.js +1 -1
- package/src/locales/en.js +28 -0
|
@@ -0,0 +1,399 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div
|
|
3
|
+
class="itf-sortable"
|
|
4
|
+
@keydown.enter="onKeydownEnter"
|
|
5
|
+
@keydown.space="onKeydownEnter"
|
|
6
|
+
@keydown.down="onKeydownDown"
|
|
7
|
+
@keydown.right="onKeydownDown"
|
|
8
|
+
@keydown.up="onKeydownUp"
|
|
9
|
+
@keydown.left="onKeydownUp"
|
|
10
|
+
@keydown.escape="onKeydownEscape"
|
|
11
|
+
@keydown.tab="onKeydownEscape"
|
|
12
|
+
@mousedown="onMouseDown"
|
|
13
|
+
@click="onMouseClick"
|
|
14
|
+
@dblclick="onMouseClick"
|
|
15
|
+
@touchstart="onTouchStart"
|
|
16
|
+
@touchcancel="onTouchCancel"
|
|
17
|
+
@mouseup="onMouseUp"
|
|
18
|
+
@touchend="onTouchEnd"
|
|
19
|
+
@mouseover="onMouseOver"
|
|
20
|
+
@mouseout="onMouseOut"
|
|
21
|
+
@mousemove="onMouseMove"
|
|
22
|
+
@touchmove="onTouchMove"
|
|
23
|
+
@dropoutside="onDropOutside"
|
|
24
|
+
>
|
|
25
|
+
<auto-scroll
|
|
26
|
+
ref="autoscroll"
|
|
27
|
+
:disabled="!isSortingInProgress || !autoScroll"
|
|
28
|
+
:parent-selector="autoScroll === 'window' ? null : autoScroll"
|
|
29
|
+
class="autoscroll"
|
|
30
|
+
>
|
|
31
|
+
<div
|
|
32
|
+
ref="originalList"
|
|
33
|
+
class="itf-sortable-list itf-sortable-list-original"
|
|
34
|
+
:class="listClass"
|
|
35
|
+
>
|
|
36
|
+
<!-- @slot Slot for typeahead -->
|
|
37
|
+
<slot />
|
|
38
|
+
</div>
|
|
39
|
+
<ul
|
|
40
|
+
ref="mockedList"
|
|
41
|
+
class="itf-sortable-list itf-sortable-list-mocked hidden"
|
|
42
|
+
:class="listClass"
|
|
43
|
+
/>
|
|
44
|
+
</auto-scroll>
|
|
45
|
+
</div>
|
|
46
|
+
</template>
|
|
47
|
+
<script>
|
|
48
|
+
import autoScroll from './AutoScroll.vue';
|
|
49
|
+
import { onDropOutside } from './utils/event-outside';
|
|
50
|
+
import OriginalSortableItemList from './sortable-item-list/original-sortable-item-list';
|
|
51
|
+
import MockedSortableItemList, { ATTRIBUTE_SKIP_SORTING } from './sortable-item-list/mocked-sortable-item-list';
|
|
52
|
+
import sortItemList from './utils/sort-item-list';
|
|
53
|
+
import vibrate from './utils/vibrate';
|
|
54
|
+
import stopEvent from './utils/stop-event';
|
|
55
|
+
import { AXIS } from './sortable-item-list/axis';
|
|
56
|
+
import './Sortable.scss';
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Sortable component to reorder LI elements in a UL item list.
|
|
60
|
+
* Each sortable element should have attribute sortable="true" in case
|
|
61
|
+
* if `require-sortable-attribute="true"` then sorted element
|
|
62
|
+
* or its part should have `sortable` attribute
|
|
63
|
+
* if `sortable-skip="true"` then sorting is ignored for that element
|
|
64
|
+
*/
|
|
65
|
+
export default {
|
|
66
|
+
name: 'itfSortable',
|
|
67
|
+
components: {
|
|
68
|
+
autoScroll
|
|
69
|
+
},
|
|
70
|
+
props: {
|
|
71
|
+
/**
|
|
72
|
+
* Items to sort
|
|
73
|
+
*/
|
|
74
|
+
value: {
|
|
75
|
+
type: Array,
|
|
76
|
+
default: /* istanbul ignore next */ () => []
|
|
77
|
+
},
|
|
78
|
+
/**
|
|
79
|
+
* Axis to sort: x, y, xy
|
|
80
|
+
*/
|
|
81
|
+
axis: {
|
|
82
|
+
type: String,
|
|
83
|
+
default: AXIS.xy,
|
|
84
|
+
validator (value) {
|
|
85
|
+
return [AXIS.x, AXIS.y, AXIS.xy].includes(value);
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
/**
|
|
89
|
+
* Sorting is not allowed if true
|
|
90
|
+
*/
|
|
91
|
+
readOnly: {
|
|
92
|
+
type: Boolean,
|
|
93
|
+
default: false
|
|
94
|
+
},
|
|
95
|
+
/**
|
|
96
|
+
* Auto scroll during sorting is available if set.
|
|
97
|
+
* Value `window` manages scrolling for window,
|
|
98
|
+
* else treated as an html selector for its parent to scroll.
|
|
99
|
+
*/
|
|
100
|
+
autoScroll: {
|
|
101
|
+
type: String,
|
|
102
|
+
default: null
|
|
103
|
+
},
|
|
104
|
+
/**
|
|
105
|
+
* Sorting is allowed if an element has attribute `sortable/data-sortable` = `true`
|
|
106
|
+
*/
|
|
107
|
+
requireSortableAttribute: {
|
|
108
|
+
type: Boolean,
|
|
109
|
+
default: false
|
|
110
|
+
},
|
|
111
|
+
/**
|
|
112
|
+
* Sortable list class name
|
|
113
|
+
*/
|
|
114
|
+
listClass: {
|
|
115
|
+
type: String,
|
|
116
|
+
default: null
|
|
117
|
+
},
|
|
118
|
+
/**
|
|
119
|
+
* Item cursor class name
|
|
120
|
+
*/
|
|
121
|
+
cursorClass: {
|
|
122
|
+
type: String,
|
|
123
|
+
default: null
|
|
124
|
+
},
|
|
125
|
+
/**
|
|
126
|
+
* Item cursor selector
|
|
127
|
+
*/
|
|
128
|
+
cursorSelector: {
|
|
129
|
+
type: String,
|
|
130
|
+
default: null
|
|
131
|
+
}
|
|
132
|
+
},
|
|
133
|
+
data () {
|
|
134
|
+
return {
|
|
135
|
+
originalItemList: new OriginalSortableItemList(),
|
|
136
|
+
mockedItemList: new MockedSortableItemList(),
|
|
137
|
+
isSortingInProgress: false
|
|
138
|
+
};
|
|
139
|
+
},
|
|
140
|
+
watch: {
|
|
141
|
+
readOnly (newValue) {
|
|
142
|
+
if (newValue) {
|
|
143
|
+
this.cancelSorting(null);
|
|
144
|
+
}
|
|
145
|
+
},
|
|
146
|
+
axis (newValue) {
|
|
147
|
+
this.mockedItemList.setAxis(newValue);
|
|
148
|
+
}
|
|
149
|
+
},
|
|
150
|
+
mounted () {
|
|
151
|
+
this.originalItemList.setContainer(this.$refs.originalList);
|
|
152
|
+
this.mockedItemList.setContainer(this.$refs.mockedList);
|
|
153
|
+
this.mockedItemList.setAxis(this.axis);
|
|
154
|
+
this.onDropOutsideRelease = onDropOutside(this.$el, event =>
|
|
155
|
+
this.onDropOutside(event)
|
|
156
|
+
);
|
|
157
|
+
},
|
|
158
|
+
beforeDestroy () {
|
|
159
|
+
this.onDropOutsideRelease();
|
|
160
|
+
},
|
|
161
|
+
methods: {
|
|
162
|
+
onKeydownEnter (event) {
|
|
163
|
+
if (this.isSortingInProgress) {
|
|
164
|
+
this.finishSorting(true);
|
|
165
|
+
return stopEvent(event);
|
|
166
|
+
}
|
|
167
|
+
if (this.isSortingAvailable(event.target)) {
|
|
168
|
+
this.startSorting(event);
|
|
169
|
+
setTimeout(() => this.scrollToCursorItem(), 100);
|
|
170
|
+
return stopEvent(event);
|
|
171
|
+
}
|
|
172
|
+
return null;
|
|
173
|
+
},
|
|
174
|
+
onKeydownDown (event) {
|
|
175
|
+
if (this.isSortingInProgress) {
|
|
176
|
+
if (this.mockedItemList.moveDown()) {
|
|
177
|
+
this.scrollToCursorItem();
|
|
178
|
+
this.emitChangeEvent('keydown-down');
|
|
179
|
+
}
|
|
180
|
+
return stopEvent(event);
|
|
181
|
+
}
|
|
182
|
+
return null;
|
|
183
|
+
},
|
|
184
|
+
onKeydownUp (event) {
|
|
185
|
+
if (this.isSortingInProgress) {
|
|
186
|
+
this.mockedItemList.moveUp();
|
|
187
|
+
this.scrollToCursorItem();
|
|
188
|
+
this.emitChangeEvent('keydown-up');
|
|
189
|
+
return stopEvent(event);
|
|
190
|
+
}
|
|
191
|
+
return null;
|
|
192
|
+
},
|
|
193
|
+
onKeydownEscape (event) {
|
|
194
|
+
if (this.isSortingInProgress) {
|
|
195
|
+
this.cancelSorting(this.mockedItemList.getFromPosition());
|
|
196
|
+
return stopEvent(event);
|
|
197
|
+
}
|
|
198
|
+
return null;
|
|
199
|
+
},
|
|
200
|
+
onMouseDown (event) {
|
|
201
|
+
if (!this.isSortingInProgress && this.isSortingAvailable(event.target)) {
|
|
202
|
+
this.startSorting(event);
|
|
203
|
+
return stopEvent(event);
|
|
204
|
+
}
|
|
205
|
+
return null;
|
|
206
|
+
},
|
|
207
|
+
onMouseClick () {
|
|
208
|
+
this.cancelSorting(null);
|
|
209
|
+
},
|
|
210
|
+
onTouchStart (event) {
|
|
211
|
+
if (this.isSortingAvailable(event.target)) {
|
|
212
|
+
this.startSorting(event);
|
|
213
|
+
if (this.isSortingInProgress) {
|
|
214
|
+
vibrate();
|
|
215
|
+
return stopEvent(event);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
return null;
|
|
219
|
+
},
|
|
220
|
+
onTouchCancel (event) {
|
|
221
|
+
if (this.isSortingInProgress) {
|
|
222
|
+
return stopEvent(event);
|
|
223
|
+
}
|
|
224
|
+
return null;
|
|
225
|
+
},
|
|
226
|
+
onMouseUp (event) {
|
|
227
|
+
if (this.isSortingInProgress) {
|
|
228
|
+
this.finishSorting();
|
|
229
|
+
return stopEvent(event);
|
|
230
|
+
}
|
|
231
|
+
return null;
|
|
232
|
+
},
|
|
233
|
+
onTouchEnd (event) {
|
|
234
|
+
if (this.isSortingInProgress) {
|
|
235
|
+
this.finishSorting();
|
|
236
|
+
vibrate();
|
|
237
|
+
return stopEvent(event);
|
|
238
|
+
}
|
|
239
|
+
return null;
|
|
240
|
+
},
|
|
241
|
+
onMouseOver (event) {
|
|
242
|
+
if (this.isSortingInProgress) {
|
|
243
|
+
return stopEvent(event);
|
|
244
|
+
}
|
|
245
|
+
return null;
|
|
246
|
+
},
|
|
247
|
+
onMouseOut (event) {
|
|
248
|
+
if (this.isSortingInProgress) {
|
|
249
|
+
return stopEvent(event);
|
|
250
|
+
}
|
|
251
|
+
return null;
|
|
252
|
+
},
|
|
253
|
+
onMouseMove (event) {
|
|
254
|
+
if (this.isSortingInProgress) {
|
|
255
|
+
this.performSorting(event);
|
|
256
|
+
this.emitChangeEvent('mousemove');
|
|
257
|
+
return stopEvent(event);
|
|
258
|
+
}
|
|
259
|
+
return null;
|
|
260
|
+
},
|
|
261
|
+
onTouchMove (event) {
|
|
262
|
+
if (this.isSortingInProgress) {
|
|
263
|
+
this.performSorting(event);
|
|
264
|
+
this.emitChangeEvent('touchmove');
|
|
265
|
+
return stopEvent(event);
|
|
266
|
+
}
|
|
267
|
+
return null;
|
|
268
|
+
},
|
|
269
|
+
onDropOutside (event) {
|
|
270
|
+
if (this.isSortingInProgress) {
|
|
271
|
+
this.cancelSorting(null);
|
|
272
|
+
return stopEvent(event);
|
|
273
|
+
}
|
|
274
|
+
return null;
|
|
275
|
+
},
|
|
276
|
+
scrollToCursorItem () {
|
|
277
|
+
this.$refs.autoscroll.autoScroll(
|
|
278
|
+
this.mockedItemList.getCursorPageX(),
|
|
279
|
+
this.mockedItemList.getCursorPageY(),
|
|
280
|
+
false
|
|
281
|
+
);
|
|
282
|
+
},
|
|
283
|
+
startSorting (event) {
|
|
284
|
+
const { target } = event;
|
|
285
|
+
this.cancelSorting(null);
|
|
286
|
+
if (
|
|
287
|
+
!this.readOnly &&
|
|
288
|
+
this.originalItemList.isSortable(target, this.requireSortableAttribute)
|
|
289
|
+
) {
|
|
290
|
+
const itemElement = this.originalItemList.getSortItem(target);
|
|
291
|
+
const position = this.originalItemList.getItemIndexByElement(
|
|
292
|
+
itemElement
|
|
293
|
+
);
|
|
294
|
+
if (position >= 0) {
|
|
295
|
+
/**
|
|
296
|
+
* Start sorting
|
|
297
|
+
* @param {number} position Start position to sort
|
|
298
|
+
* @param {Event} event Event
|
|
299
|
+
*/
|
|
300
|
+
this.$emit('sortable-start', position, event);
|
|
301
|
+
this.mockSortingList(position, event);
|
|
302
|
+
this.isSortingInProgress = true;
|
|
303
|
+
this.changeEventSign = null;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
},
|
|
307
|
+
performSorting (event) {
|
|
308
|
+
if (this.isSortingInProgress) {
|
|
309
|
+
this.mockedItemList.move(event);
|
|
310
|
+
}
|
|
311
|
+
},
|
|
312
|
+
finishSorting (setFocus = false) {
|
|
313
|
+
if (this.isSortingInProgress) {
|
|
314
|
+
const from = this.mockedItemList.getFromPosition();
|
|
315
|
+
const to = this.mockedItemList.getToPosition();
|
|
316
|
+
const callback = itemList => sortItemList(itemList, from, to);
|
|
317
|
+
if (this.mockedItemList.isSorted()) {
|
|
318
|
+
this.mockedItemList.finishSorting();
|
|
319
|
+
const items = callback(this.value);
|
|
320
|
+
/**
|
|
321
|
+
* Change model value
|
|
322
|
+
*/
|
|
323
|
+
this.$emit('input', items);
|
|
324
|
+
/**
|
|
325
|
+
* Sort happened
|
|
326
|
+
* @param {Function} callback Callback to sort an array with one argument.
|
|
327
|
+
* If sorting through v-model is not enough
|
|
328
|
+
* @param {number} from From position
|
|
329
|
+
* @param {number} to From position
|
|
330
|
+
*/
|
|
331
|
+
this.$emit('sort', callback, from, to);
|
|
332
|
+
this.$emit('sortable-finish');
|
|
333
|
+
}
|
|
334
|
+
const focusItemPosition = setFocus ? to : null;
|
|
335
|
+
setTimeout(() => this.restoreOriginalList(focusItemPosition), 10);
|
|
336
|
+
this.isSortingInProgress = false;
|
|
337
|
+
}
|
|
338
|
+
},
|
|
339
|
+
mockSortingList (fromPosition, event) {
|
|
340
|
+
this.originalItemList.hide();
|
|
341
|
+
this.mockedItemList.reset();
|
|
342
|
+
this.originalItemList.cloneTo(this.mockedItemList.getContainer());
|
|
343
|
+
this.mockedItemList.createCursorItem(
|
|
344
|
+
fromPosition,
|
|
345
|
+
event,
|
|
346
|
+
this.cursorClass,
|
|
347
|
+
this.cursorSelector
|
|
348
|
+
);
|
|
349
|
+
},
|
|
350
|
+
restoreOriginalList (positionToFocus) {
|
|
351
|
+
this.originalItemList.restore(positionToFocus);
|
|
352
|
+
this.mockedItemList.hide();
|
|
353
|
+
},
|
|
354
|
+
cancelSorting (positionToFocus) {
|
|
355
|
+
if (this.isSortingInProgress) {
|
|
356
|
+
this.restoreOriginalList(positionToFocus);
|
|
357
|
+
this.isSortingInProgress = false;
|
|
358
|
+
/**
|
|
359
|
+
* Cancel sorting
|
|
360
|
+
*/
|
|
361
|
+
this.$emit('sortable-cancel');
|
|
362
|
+
/**
|
|
363
|
+
* Finish sorting
|
|
364
|
+
*/
|
|
365
|
+
this.$emit('sortable-finish');
|
|
366
|
+
}
|
|
367
|
+
},
|
|
368
|
+
emitChangeEvent (source) {
|
|
369
|
+
const sign = [
|
|
370
|
+
this.mockedItemList.getFromPosition(),
|
|
371
|
+
this.mockedItemList.getToPosition(),
|
|
372
|
+
source
|
|
373
|
+
].join('!');
|
|
374
|
+
if (this.changeEventSign !== sign) {
|
|
375
|
+
/**
|
|
376
|
+
* Change sorting
|
|
377
|
+
* @param {number} from From position
|
|
378
|
+
* @param {number} to To position
|
|
379
|
+
* @param {string} source Source
|
|
380
|
+
*/
|
|
381
|
+
this.$emit(
|
|
382
|
+
'sortable-change',
|
|
383
|
+
this.mockedItemList.getFromPosition(),
|
|
384
|
+
this.mockedItemList.getToPosition(),
|
|
385
|
+
source
|
|
386
|
+
);
|
|
387
|
+
this.changeEventSign = sign;
|
|
388
|
+
}
|
|
389
|
+
},
|
|
390
|
+
isSortingAvailable (element) {
|
|
391
|
+
const sortableSkip = element.closest(`[${ATTRIBUTE_SKIP_SORTING}]`);
|
|
392
|
+
if (sortableSkip) {
|
|
393
|
+
return false;
|
|
394
|
+
}
|
|
395
|
+
return !sortableSkip || !this.mockedItemList.isToSkip(sortableSkip);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
};
|
|
399
|
+
</script>
|