@itfin/components 1.2.99 → 1.2.101
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 +1 -1
- package/src/components/app/ToastContainer.vue +1 -1
- package/src/components/app/ToastMessage.vue +1 -1
- package/src/components/kanban/Board.vue +25 -34
- package/src/components/kanban/BoardColumn.vue +3 -8
- package/src/components/kanban/index.stories.js +1 -1
- package/src/components/kanban/styles.scss +6 -3
- package/src/components/text-field/HoursField.vue +50 -0
- package/src/components/text-field/index.stories.js +8 -3
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div class="itf-toast-message toast" :class="{'show': visible, [typeClass]: true}" role="alert" aria-live="assertive" aria-atomic="true">
|
|
2
|
+
<div class="itf-toast-message toast d-print-none" :class="{'show': visible, [typeClass]: true}" role="alert" aria-live="assertive" aria-atomic="true">
|
|
3
3
|
<div class="toast-header" v-if="title || $slots.title" :class="{[typeClass]: true}">
|
|
4
4
|
<template v-if="iconImg || $slots.icon">
|
|
5
5
|
<img v-if="iconImg" :src="iconImg" class="rounded me-2" />
|
|
@@ -66,7 +66,6 @@ import loading from '../../directives/loading';
|
|
|
66
66
|
import itfForm from '../form/Form';
|
|
67
67
|
import itfEditButton from '../editable/EditButton.vue';
|
|
68
68
|
import createDraggable from '../sortable/draggable';
|
|
69
|
-
import { debounce } from '../../helpers/debounce';
|
|
70
69
|
|
|
71
70
|
const { Node, ...draggableDirectives } = createDraggable();
|
|
72
71
|
|
|
@@ -101,7 +100,6 @@ class Board extends Vue {
|
|
|
101
100
|
}
|
|
102
101
|
|
|
103
102
|
mounted() {
|
|
104
|
-
this.itemStatusChanged = debounce(this.emitItemStatusChanged, 10);
|
|
105
103
|
if (this.columnSorting) {
|
|
106
104
|
Node.addContainer(this.$refs.container);
|
|
107
105
|
}
|
|
@@ -188,43 +186,36 @@ class Board extends Vue {
|
|
|
188
186
|
|
|
189
187
|
items[itemIndex] = newItem;
|
|
190
188
|
|
|
191
|
-
|
|
192
|
-
this.itemStatusChanged(items[itemIndex], column, items, () => {
|
|
193
|
-
const toIndex = this.lastUpdatedIndex; // беремо індекс з пам'яті, бо викликів може бути два, але індекс тільки в картці, якщо нема, то це колонка
|
|
194
|
-
this.lastUpdatedIndex = undefined; // обнуляємо, щоб при наступному перетягувані вже не брало його
|
|
195
|
-
const newOrders = [...this.columnOrders];
|
|
196
|
-
let sorting = newOrders.find((c) => c.Id === column.Id);
|
|
197
|
-
if (!sorting) {
|
|
198
|
-
sorting = { Id: column.Id, ItemIds: [] };
|
|
199
|
-
newOrders.push(sorting)
|
|
200
|
-
}
|
|
201
|
-
let fromSorting = newOrders.find((c) => c.Id === fromColumn.Id);
|
|
202
|
-
if (!fromSorting) {
|
|
203
|
-
fromSorting = { Id: fromColumn.Id, ItemIds: [] };
|
|
204
|
-
newOrders.push(fromSorting)
|
|
205
|
-
}
|
|
206
|
-
// update from
|
|
207
|
-
fromSorting.ItemIds = this.groupedItems[fromColumn.Id].map((i) => i.Id).filter((t) => t !== newItem.Id);
|
|
208
|
-
|
|
209
|
-
// update to
|
|
210
|
-
const items = [...this.groupedItems[column.Id]];
|
|
211
|
-
let placeIndex = last ? items.length : toIndex;
|
|
212
|
-
if (typeof placeIndex === 'undefined') { // ідекса може не бути, якщо на колонку переносять, тоді в кінець
|
|
213
|
-
placeIndex = items.length;
|
|
214
|
-
}
|
|
215
|
-
const itemsInColumn = items.map((t) => t.Id).filter((t) => t !== newItem.Id);
|
|
216
|
-
itemsInColumn.splice(placeIndex, 0, newItem.Id);
|
|
189
|
+
const newOrders = [...this.columnOrders];
|
|
217
190
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
191
|
+
let sorting = newOrders.find((c) => c.Id === column.Id);
|
|
192
|
+
if (!sorting) {
|
|
193
|
+
sorting = { Id: column.Id, ItemIds: [] };
|
|
194
|
+
newOrders.push(sorting)
|
|
195
|
+
}
|
|
196
|
+
let fromSorting = newOrders.find((c) => c.Id === fromColumn.Id);
|
|
197
|
+
if (!fromSorting) {
|
|
198
|
+
fromSorting = { Id: fromColumn.Id, ItemIds: [] };
|
|
199
|
+
newOrders.push(fromSorting)
|
|
200
|
+
}
|
|
201
|
+
// update from
|
|
202
|
+
fromSorting.ItemIds = this.groupedItems[fromColumn.Id].map((i) => i.Id).filter((t) => t !== newItem.Id);
|
|
203
|
+
|
|
204
|
+
// update to
|
|
205
|
+
const columnItems = [...this.groupedItems[column.Id]];
|
|
206
|
+
let placeIndex = last ? columnItems.length : toIndex;
|
|
207
|
+
if (typeof placeIndex === 'undefined') { // ідекса може не бути, якщо на колонку переносять, тоді в кінець
|
|
208
|
+
placeIndex = columnItems.length;
|
|
209
|
+
}
|
|
210
|
+
const itemsInColumn = columnItems.map((t) => t.Id).filter((t) => t !== newItem.Id);
|
|
211
|
+
itemsInColumn.splice(placeIndex, 0, newItem.Id);
|
|
222
212
|
|
|
223
|
-
|
|
224
|
-
updateOrder();
|
|
213
|
+
sorting.ItemIds = itemsInColumn;
|
|
225
214
|
|
|
226
215
|
this.$emit('update:item', [item, column]);
|
|
227
216
|
this.$emit('update:items', items);
|
|
217
|
+
|
|
218
|
+
this.$emit('update:columnOrders', newOrders);
|
|
228
219
|
}
|
|
229
220
|
}
|
|
230
221
|
</script>
|
|
@@ -1,18 +1,12 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="itf-board-column-wrapper">
|
|
3
|
-
<itf-button block small class="text-muted">
|
|
3
|
+
<itf-button v-if="showAddButton" block small class="text-muted">
|
|
4
4
|
<itf-icon name="plus" />
|
|
5
5
|
|
|
6
6
|
Add entry
|
|
7
7
|
</itf-button>
|
|
8
8
|
|
|
9
|
-
<div class="itf-board-cards-wrapper"
|
|
10
|
-
ref="container"
|
|
11
|
-
accept-group="board-cards"
|
|
12
|
-
@enter="cardHighlight(0, 'enter', 'drop')"
|
|
13
|
-
@leave="cardHighlight(0, 'leave', 'drop')"
|
|
14
|
-
v-dropzone="{ payload: { column } }"
|
|
15
|
-
>
|
|
9
|
+
<div class="itf-board-cards-wrapper" ref="container">
|
|
16
10
|
<template v-if="!items.length">
|
|
17
11
|
<slot name="empty"></slot>
|
|
18
12
|
</template>
|
|
@@ -81,6 +75,7 @@ class BoardColumn extends Vue {
|
|
|
81
75
|
@Prop() title;
|
|
82
76
|
@Prop() column;
|
|
83
77
|
@Prop(Array) items;
|
|
78
|
+
@Prop(Boolean) showAddButton;
|
|
84
79
|
@Prop(Boolean) cardSorting;
|
|
85
80
|
|
|
86
81
|
beforeDestroy() {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
:root {
|
|
2
|
-
--itf-board-column-hover-color:
|
|
2
|
+
--itf-board-column-hover-color: rgba(0, 0, 0, .05);
|
|
3
3
|
--itf-board-column-width: 300px;
|
|
4
4
|
--itf-board-placeholder-color: #47BEFF;
|
|
5
5
|
--itf-board-placeholder-border-color: #0567eb;
|
|
@@ -13,11 +13,13 @@
|
|
|
13
13
|
--itf-board-placeholder-border-color: #FFCC00;
|
|
14
14
|
--itf-board-placeholder-bg-color: #383b41;
|
|
15
15
|
--itf-board-card-bg-color: #313337;
|
|
16
|
+
|
|
17
|
+
.itf-board {
|
|
18
|
+
--bs-border-color: #424448;
|
|
19
|
+
}
|
|
16
20
|
}
|
|
17
21
|
|
|
18
22
|
.itf-board {
|
|
19
|
-
--bs-border-color: #424448;
|
|
20
|
-
|
|
21
23
|
display: flex;
|
|
22
24
|
flex-wrap: nowrap;
|
|
23
25
|
flex-direction: column;
|
|
@@ -106,6 +108,7 @@
|
|
|
106
108
|
.itf-board-column {
|
|
107
109
|
position: relative;
|
|
108
110
|
width: var(--itf-board-column-width);
|
|
111
|
+
min-width: var(--itf-board-column-width);
|
|
109
112
|
border-radius: 0 0 var(--bs-border-radius) var(--bs-border-radius);
|
|
110
113
|
|
|
111
114
|
&__title {
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
|
|
3
|
+
<itf-text-field
|
|
4
|
+
ref="input"
|
|
5
|
+
v-bind="$props"
|
|
6
|
+
@input="onValueChange"
|
|
7
|
+
/>
|
|
8
|
+
|
|
9
|
+
</template>
|
|
10
|
+
<script>
|
|
11
|
+
import { Vue, Component, Model, Inject, Prop } from 'vue-property-decorator';
|
|
12
|
+
import itfTextField from './TextField.vue';
|
|
13
|
+
import {parseHours} from "@/helpers/formatters";
|
|
14
|
+
|
|
15
|
+
export default @Component({
|
|
16
|
+
name: 'itfHoursField',
|
|
17
|
+
components: {
|
|
18
|
+
itfTextField
|
|
19
|
+
}
|
|
20
|
+
})
|
|
21
|
+
class itfHoursField extends Vue {
|
|
22
|
+
@Inject({ default: null }) itemLabel;
|
|
23
|
+
@Model('input') value;
|
|
24
|
+
@Prop() hours;
|
|
25
|
+
@Prop(String) prependIcon;
|
|
26
|
+
@Prop(String) placeholder;
|
|
27
|
+
@Prop() step;
|
|
28
|
+
@Prop() min;
|
|
29
|
+
@Prop() max;
|
|
30
|
+
@Prop(Boolean) clearable;
|
|
31
|
+
@Prop(Boolean) disabled;
|
|
32
|
+
@Prop(Boolean) readonly;
|
|
33
|
+
@Prop({ type: String, default: 'text' }) type;
|
|
34
|
+
@Prop({ type: [Number, String], default: 0 }) delayInput;
|
|
35
|
+
|
|
36
|
+
onValueChange(text) {
|
|
37
|
+
const hours = parseHours(text);
|
|
38
|
+
this.$emit('update:hours', hours);
|
|
39
|
+
this.$emit('input', text);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
focus() {
|
|
43
|
+
this.$refs.input.focus();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
blur() {
|
|
47
|
+
this.$refs.input.blur();
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
</script>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { storiesOf } from '@storybook/vue';
|
|
2
2
|
import itfMoneyField from './MoneyField.vue';
|
|
3
|
+
import itfHoursField from './HoursField.vue';
|
|
3
4
|
import itfForm from '../form/Form.vue';
|
|
4
5
|
import itfButton from '../button/Button.vue';
|
|
5
6
|
import itfIcon from '../icon/Icon.vue';
|
|
@@ -14,7 +15,8 @@ storiesOf('Common', module)
|
|
|
14
15
|
itfForm,
|
|
15
16
|
itfButton,
|
|
16
17
|
itfLabel,
|
|
17
|
-
itfMoneyField
|
|
18
|
+
itfMoneyField,
|
|
19
|
+
itfHoursField
|
|
18
20
|
},
|
|
19
21
|
data() {
|
|
20
22
|
return {
|
|
@@ -25,6 +27,8 @@ storiesOf('Common', module)
|
|
|
25
27
|
{ Id: 4, Symbol: 'ERO', Code: 'EUR', Title: 'Euroooo' },
|
|
26
28
|
{ Id: 3, Symbol: ".د.ب", Code: 'AED', Title: 'Emirati Dirham' },
|
|
27
29
|
],
|
|
30
|
+
hoursStr: '10h 10m',
|
|
31
|
+
hours: 0,
|
|
28
32
|
currency: null
|
|
29
33
|
}
|
|
30
34
|
},
|
|
@@ -43,11 +47,12 @@ storiesOf('Common', module)
|
|
|
43
47
|
|
|
44
48
|
<itf-app ref="app">
|
|
45
49
|
|
|
46
|
-
{{
|
|
47
|
-
{{currency}}
|
|
50
|
+
{{hours}}
|
|
48
51
|
|
|
49
52
|
<itf-money-field v-model="value" :currencies="currencies" :currency.sync="currency" />
|
|
50
53
|
|
|
54
|
+
<itf-hours-field v-model="hoursStr" :hours.sync="hours" />
|
|
55
|
+
|
|
51
56
|
</itf-app>
|
|
52
57
|
</div>`,
|
|
53
58
|
}));
|