@itfin/components 1.3.53 → 1.3.56
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/assets/scss/components/_datepicker.scss +1 -1
- package/src/components/datepicker/MonthPicker.vue +16 -1
- package/src/components/datepicker/index.stories.js +2 -0
- package/src/components/modal/Modal.vue +1 -1
- package/src/components/panels/PanelList.vue +73 -36
- package/src/components/table/TableBody.vue +11 -9
- package/src/components/table/TableGroup.vue +7 -9
- package/src/components/table/table2.scss +22 -12
- package/src/helpers/validators.spec.js +6 -6
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div class="itf-monthpicker" :class="{'with-addon addon-start': prependIcon}">
|
|
2
|
+
<div class="itf-monthpicker input-group" :class="{'with-addon addon-start': prependIcon, 'with-addon addon-end': clearable}">
|
|
3
3
|
<div class="addon" v-if="prependIcon">
|
|
4
4
|
<slot name="addon">
|
|
5
5
|
<itf-icon :name="prependIcon" />
|
|
@@ -16,6 +16,17 @@
|
|
|
16
16
|
:value="displayValue"
|
|
17
17
|
:placeholder="placeholder"
|
|
18
18
|
/>
|
|
19
|
+
<div class="addon-end" v-if="clearable && value">
|
|
20
|
+
<slot name="clear">
|
|
21
|
+
<itf-button
|
|
22
|
+
icon
|
|
23
|
+
small
|
|
24
|
+
@click="$emit('input', '')"
|
|
25
|
+
>
|
|
26
|
+
<itf-icon name="close" />
|
|
27
|
+
</itf-button>
|
|
28
|
+
</slot>
|
|
29
|
+
</div>
|
|
19
30
|
<div style="display: none">
|
|
20
31
|
<div ref="dropdown" class="itf-monthpicker__dropdown border rounded">
|
|
21
32
|
<div>
|
|
@@ -42,10 +53,12 @@ import { DateTime } from 'luxon';
|
|
|
42
53
|
import tippy from 'tippy.js';
|
|
43
54
|
import itfIcon from '../icon/Icon';
|
|
44
55
|
import itfDatePickerInline from './DatePickerInline.vue';
|
|
56
|
+
import itfButton from "@/components/button/Button.vue";
|
|
45
57
|
|
|
46
58
|
export default @Component({
|
|
47
59
|
name: 'itfMonthPicker',
|
|
48
60
|
components: {
|
|
61
|
+
itfButton,
|
|
49
62
|
itfIcon,
|
|
50
63
|
itfDatePickerInline
|
|
51
64
|
},
|
|
@@ -64,6 +77,8 @@ class itfMonthPicker extends Vue {
|
|
|
64
77
|
@Prop({ type: String, default: '' }) prependIcon;
|
|
65
78
|
@Prop({ type: String, default: 'bottom-start' }) placement;
|
|
66
79
|
|
|
80
|
+
@Prop(Boolean) clearable;
|
|
81
|
+
|
|
67
82
|
focused = false;
|
|
68
83
|
|
|
69
84
|
tooltip = null;
|
|
@@ -73,7 +73,7 @@ class itfModal extends Vue {
|
|
|
73
73
|
|
|
74
74
|
@Watch('value')
|
|
75
75
|
onVisibleChanged(newValue, oldValue) {
|
|
76
|
-
if (!this.modalEl || this.preventEvents || (typeof oldValue === 'undefined' && !newValue)) {
|
|
76
|
+
if (!this.modalEl || (this.preventEvents && oldValue !== true) || (typeof oldValue === 'undefined' && !newValue)) {
|
|
77
77
|
return;
|
|
78
78
|
}
|
|
79
79
|
if (newValue) {
|
|
@@ -114,6 +114,9 @@ interface IPanel {
|
|
|
114
114
|
once: (eventName: string, func: (event: string, ...args: any[]) => any) => void;
|
|
115
115
|
emit: (event: string, ...args: any[]) => void;
|
|
116
116
|
isMultiple: () => boolean;
|
|
117
|
+
fullsize: () => void;
|
|
118
|
+
getPayload: () => any;
|
|
119
|
+
setPayload: (value: any) => void;
|
|
117
120
|
__events: Record<string, ((event: string, ...args: any[]) => any)[]>;
|
|
118
121
|
}
|
|
119
122
|
|
|
@@ -136,8 +139,9 @@ export default class PanelList extends Vue {
|
|
|
136
139
|
|
|
137
140
|
created() {
|
|
138
141
|
if (this.firstPanel) {
|
|
139
|
-
this.
|
|
142
|
+
this.internalOpenPanel(this.firstPanel.title, this.firstPanel.icon, this.firstPanel.type, this.firstPanel.payload);
|
|
140
143
|
}
|
|
144
|
+
this.parsePanelHash();
|
|
141
145
|
}
|
|
142
146
|
|
|
143
147
|
get isOpenMultiple() {
|
|
@@ -181,8 +185,8 @@ export default class PanelList extends Vue {
|
|
|
181
185
|
this.panelsStack = newStack;
|
|
182
186
|
}
|
|
183
187
|
|
|
184
|
-
|
|
185
|
-
const newPanel:
|
|
188
|
+
internalOpenPanel(title: string, icon: string, type: string, payload: any, openIndex?: number) {
|
|
189
|
+
const newPanel:any = {
|
|
186
190
|
id: this.nextId++,
|
|
187
191
|
title,
|
|
188
192
|
icon,
|
|
@@ -190,7 +194,7 @@ export default class PanelList extends Vue {
|
|
|
190
194
|
payload,
|
|
191
195
|
isCollapsed: false,
|
|
192
196
|
isCloseable: true,
|
|
193
|
-
__events: {}
|
|
197
|
+
__events: {},
|
|
194
198
|
};
|
|
195
199
|
if (!this.panelsStack.length) {
|
|
196
200
|
newPanel.isCloseable = false;
|
|
@@ -200,42 +204,51 @@ export default class PanelList extends Vue {
|
|
|
200
204
|
newStack = newStack.slice(0, openIndex);
|
|
201
205
|
}
|
|
202
206
|
this.panelsStack = newStack;
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
newPanel.__events[eventName]
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
newPanel.off = (eventName, func: (event: string, ...args: any[]) => any) => {
|
|
216
|
-
if (newPanel.__events[eventName]) {
|
|
217
|
-
newPanel.__events[eventName] = newPanel.__events[eventName].filter(f => f !== func);
|
|
218
|
-
}
|
|
219
|
-
};
|
|
220
|
-
newPanel.once = (eventName, func: (event: string, ...args: any[]) => any) => {
|
|
221
|
-
const wrapper = (...args) => {
|
|
222
|
-
func(...args);
|
|
223
|
-
newPanel.off(eventName, wrapper);
|
|
207
|
+
return new Promise(res => {
|
|
208
|
+
this.$nextTick(() => { // щоб панелі змінювались при редагуванні
|
|
209
|
+
const n = newStack.length;
|
|
210
|
+
newPanel.emit = (event, ...args) => this.emitEvent(event, ...args);
|
|
211
|
+
newPanel.open = (type, visOptions, payload) => this.openPanel(visOptions.title, visOptions.icon, type, payload, n + 1);
|
|
212
|
+
newPanel.close = () => this.closePanel(newPanel);
|
|
213
|
+
newPanel.expand = () => this.expandPanel(newPanel);
|
|
214
|
+
newPanel.on = (eventName, func: (event: string, ...args: any[]) => any) => {
|
|
215
|
+
if (!newPanel.__events[eventName]) {
|
|
216
|
+
newPanel.__events[eventName] = [];
|
|
217
|
+
}
|
|
218
|
+
newPanel.__events[eventName].push(func);
|
|
224
219
|
};
|
|
225
|
-
newPanel.
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
220
|
+
newPanel.off = (eventName, func: (event: string, ...args: any[]) => any) => {
|
|
221
|
+
if (newPanel.__events[eventName]) {
|
|
222
|
+
newPanel.__events[eventName] = newPanel.__events[eventName].filter(f => f !== func);
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
newPanel.once = (eventName, func: (event: string, ...args: any[]) => any) => {
|
|
226
|
+
const wrapper = (...args) => {
|
|
227
|
+
func(eventName, ...args);
|
|
228
|
+
newPanel.off(eventName, wrapper);
|
|
229
|
+
};
|
|
230
|
+
newPanel.on(eventName, wrapper);
|
|
231
|
+
};
|
|
232
|
+
newPanel.isMultiple = () => this.isOpenMultiple;
|
|
233
|
+
newPanel.fullsize = () => this.fullsizePanel(newPanel);
|
|
234
|
+
newPanel.getPayload = () => newPanel.payload;
|
|
235
|
+
newPanel.setPayload = (value: any) => {
|
|
236
|
+
newPanel.payload = value;
|
|
237
|
+
this.setPanelHash()
|
|
238
|
+
}
|
|
239
|
+
newStack.push(newPanel);
|
|
240
|
+
this.panelsStack = newStack;
|
|
241
|
+
this.ensureOnlyTwoOpenPanels(newPanel.id);
|
|
242
|
+
return res(newPanel);
|
|
243
|
+
})
|
|
236
244
|
});
|
|
237
245
|
}
|
|
238
246
|
|
|
247
|
+
async openPanel(title: string, icon: string, type: string, payload: any, openIndex?: number) {
|
|
248
|
+
await this.internalOpenPanel(title, icon, type, payload, openIndex);
|
|
249
|
+
this.setPanelHash()
|
|
250
|
+
}
|
|
251
|
+
|
|
239
252
|
emitEvent(event: string, ...args: any[]) {
|
|
240
253
|
for (const panel of this.panelsStack) {
|
|
241
254
|
if (panel.__events[event]) {
|
|
@@ -258,6 +271,7 @@ export default class PanelList extends Vue {
|
|
|
258
271
|
this.panelsStack[openPanelIndex - 1].isCollapsed = false;
|
|
259
272
|
}
|
|
260
273
|
this.ensureOnlyTwoOpenPanels(openPanel.id);
|
|
274
|
+
this.setPanelHash()
|
|
261
275
|
}
|
|
262
276
|
|
|
263
277
|
fullsizePanel(panel: IPanel) {
|
|
@@ -267,5 +281,28 @@ export default class PanelList extends Vue {
|
|
|
267
281
|
}
|
|
268
282
|
this.panelsStack = newStack;
|
|
269
283
|
}
|
|
284
|
+
|
|
285
|
+
setPanelHash() {
|
|
286
|
+
const hash = this.panelsStack.map(panel => {
|
|
287
|
+
return `${panel.type}=${JSON.stringify(panel.payload || {})}`;
|
|
288
|
+
}).join('&');
|
|
289
|
+
this.$router.push({ hash });
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
async parsePanelHash() {
|
|
293
|
+
const hash = this.$route.hash;
|
|
294
|
+
if (hash) {
|
|
295
|
+
const panels = hash.slice(1).split('&').map(item => {
|
|
296
|
+
const [type, payload] = item.split('=');
|
|
297
|
+
return {
|
|
298
|
+
type,
|
|
299
|
+
payload: JSON.parse(decodeURIComponent(payload))
|
|
300
|
+
};
|
|
301
|
+
});
|
|
302
|
+
for (const panel of panels) {
|
|
303
|
+
await this.internalOpenPanel('', '', panel.type, panel.payload);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
}
|
|
270
307
|
}
|
|
271
308
|
</script>
|
|
@@ -26,16 +26,18 @@
|
|
|
26
26
|
<slot :name="name" v-bind="slotData || {}"/>
|
|
27
27
|
</template>
|
|
28
28
|
</itf-table-rows>
|
|
29
|
-
<div v-if="!rows.length" data-test="table-no-results" class="
|
|
30
|
-
<div class="table-
|
|
31
|
-
<div
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
<div class="table-
|
|
36
|
-
|
|
29
|
+
<div v-if="!rows.length" data-test="table-no-results" class="scroller">
|
|
30
|
+
<div class="table-view-item">
|
|
31
|
+
<div class="table-row-template">
|
|
32
|
+
<div accept-group="items" class="table-view-body-space"></div>
|
|
33
|
+
<div class="shadow-area"></div>
|
|
34
|
+
<div class="indicator sticky"></div>
|
|
35
|
+
<div class="table-item-inner">
|
|
36
|
+
<div class="table-view-item-value w-100 align-items-center p-3 no-results">
|
|
37
|
+
{{$t('components.table.noResults')}}
|
|
38
|
+
</div>
|
|
39
|
+
<div class="boundary right"></div>
|
|
37
40
|
</div>
|
|
38
|
-
<div class="boundary right"></div>
|
|
39
41
|
</div>
|
|
40
42
|
</div>
|
|
41
43
|
</div>
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
</div-->
|
|
8
8
|
|
|
9
9
|
<div data-test="table-group-wrapper" class="table-group-wrapper flex-grow-1 w-100 d-block"
|
|
10
|
-
:style="`--row-count: ${isShowTable ? rows.length : 0}`"
|
|
10
|
+
:style="`--row-count: ${isShowTable ? rows.length : 0}`">
|
|
11
11
|
<div data-test="table-group" class="position-relative">
|
|
12
12
|
<div :class="stickyId" class="sticky-group">
|
|
13
13
|
<div v-if="title" group="tablegroups" class="draggable-item"
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
</span>
|
|
23
23
|
<span class="d-flex align-items-center line-overflow group-header-value"
|
|
24
24
|
data-test="group-value-group-label-value">
|
|
25
|
-
<slot name="group-title" :rows="rows" :title="
|
|
25
|
+
<slot name="group-title" :rows="rows" :title="title">{{ title }}</slot>
|
|
26
26
|
</span>
|
|
27
27
|
</a>
|
|
28
28
|
</div>
|
|
@@ -132,13 +132,6 @@
|
|
|
132
132
|
</template>
|
|
133
133
|
<style lang="scss">
|
|
134
134
|
.itf-table-group {
|
|
135
|
-
--group-title-height: 40px;
|
|
136
|
-
--table-row-height: 36px;
|
|
137
|
-
--table-small-row-size: var(--table-row-height);
|
|
138
|
-
--shadow-area-width: 12px;
|
|
139
|
-
--indicator-area-width: 38px;
|
|
140
|
-
--hover-bg: var(--bs-tertiary-bg);
|
|
141
|
-
|
|
142
135
|
flex-direction: column;
|
|
143
136
|
min-width: 100%;
|
|
144
137
|
display: flex;
|
|
@@ -268,6 +261,11 @@
|
|
|
268
261
|
}
|
|
269
262
|
}
|
|
270
263
|
|
|
264
|
+
.sticky-group {
|
|
265
|
+
position: sticky;
|
|
266
|
+
top: 0;
|
|
267
|
+
z-index: 10;
|
|
268
|
+
}
|
|
271
269
|
.table-summary {
|
|
272
270
|
.shadow-area {
|
|
273
271
|
border-right: 0;
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
:root {
|
|
2
|
+
--itf-table-border-color: #e1e1e1;
|
|
3
|
+
--itf-table-header-bg: #f8f8f8;
|
|
4
|
+
--itf-table-selected-bg: #f0f0f0;
|
|
2
5
|
--itf-table-border-color: #dbddd1;
|
|
3
6
|
--itf-table-header-bg: #f9faf5;
|
|
4
7
|
--itf-table-hover-header-bg: var(--bs-tertiary-bg);
|
|
@@ -11,17 +14,24 @@
|
|
|
11
14
|
--itf-table-header-subtitle-color: #aeafaa;
|
|
12
15
|
--itf-table-summary-text: var(--bs-tertiary-color);
|
|
13
16
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
17
|
+
--group-title-height: 40px;
|
|
18
|
+
--table-row-height: 36px;
|
|
19
|
+
--table-small-row-size: var(--table-row-height);
|
|
20
|
+
--shadow-area-width: 12px;
|
|
21
|
+
--indicator-area-width: 38px;
|
|
22
|
+
--hover-bg: var(--bs-tertiary-bg);
|
|
23
|
+
}
|
|
24
|
+
// dark
|
|
25
|
+
body[data-theme="dark"] {
|
|
26
|
+
--itf-table-hover-bg: #393b41;
|
|
27
|
+
--itf-table-header-bg: #0f0f0f;
|
|
28
|
+
--itf-table-hover-header-bg: #252525;
|
|
29
|
+
--itf-table-border-color: var(--bs-card-border-color);
|
|
30
|
+
--itf-table-input-focus-border-color: #252525;
|
|
31
|
+
--itf-table-selected-bg: #011534;
|
|
32
|
+
--itf-table-summary-text: #82909d80;
|
|
33
|
+
}
|
|
34
|
+
.itf-table2 {
|
|
25
35
|
&.scrollable {
|
|
26
36
|
-webkit-overflow-scrolling: touch;
|
|
27
37
|
overflow: hidden scroll;
|
|
@@ -42,24 +42,24 @@ describe('Validators', () => {
|
|
|
42
42
|
expect(dateBeforeValidation()(null, $t)).toEqual(true);
|
|
43
43
|
expect(dateBeforeValidation()(undefined, $t)).toEqual(true);
|
|
44
44
|
expect(dateBeforeValidation('2020-01-02')('2020-01-01', $t)).toEqual(true);
|
|
45
|
-
expect(dateBeforeValidation('2020-01-01')('2020-01-02', $t)).toEqual('
|
|
46
|
-
expect(dateBeforeValidation('2020-01-01')('2020-01-01', $t)).toEqual('
|
|
45
|
+
expect(dateBeforeValidation('2020-01-01')('2020-01-02', $t)).toEqual('components.dateBefore');
|
|
46
|
+
expect(dateBeforeValidation('2020-01-01')('2020-01-01', $t)).toEqual('components.dateBefore');
|
|
47
47
|
});
|
|
48
48
|
|
|
49
49
|
test('dateAfterValidation', () => {
|
|
50
50
|
expect(dateAfterValidation()(0, $t)).toEqual(true);
|
|
51
51
|
expect(dateAfterValidation()(null, $t)).toEqual(true);
|
|
52
52
|
expect(dateAfterValidation()(undefined, $t)).toEqual(true);
|
|
53
|
-
expect(dateAfterValidation('2020-01-02')('2020-01-01', $t)).toEqual('
|
|
53
|
+
expect(dateAfterValidation('2020-01-02')('2020-01-01', $t)).toEqual('components.dateAfter');
|
|
54
54
|
expect(dateAfterValidation('2020-01-01')('2020-01-02', $t)).toEqual(true);
|
|
55
|
-
expect(dateAfterValidation('2020-01-01')('2020-01-01', $t)).toEqual('
|
|
55
|
+
expect(dateAfterValidation('2020-01-01')('2020-01-01', $t)).toEqual('components.dateAfter');
|
|
56
56
|
});
|
|
57
57
|
|
|
58
58
|
test('dateSameOrAfterValidation', () => {
|
|
59
59
|
expect(dateSameOrAfterValidation()(0, $t)).toEqual(true);
|
|
60
60
|
expect(dateSameOrAfterValidation()(null, $t)).toEqual(true);
|
|
61
61
|
expect(dateSameOrAfterValidation()(undefined, $t)).toEqual(true);
|
|
62
|
-
expect(dateSameOrAfterValidation('2020-01-02')('2020-01-01', $t)).toEqual('
|
|
62
|
+
expect(dateSameOrAfterValidation('2020-01-02')('2020-01-01', $t)).toEqual('components.dateSameOrAfter');
|
|
63
63
|
expect(dateSameOrAfterValidation('2020-01-01')('2020-01-02', $t)).toEqual(true);
|
|
64
64
|
expect(dateSameOrAfterValidation('2020-01-01')('2020-01-01', $t)).toEqual(true);
|
|
65
65
|
});
|
|
@@ -69,7 +69,7 @@ describe('Validators', () => {
|
|
|
69
69
|
expect(dateSameOrBeforeValidation()(null, $t)).toEqual(true);
|
|
70
70
|
expect(dateSameOrBeforeValidation()(undefined, $t)).toEqual(true);
|
|
71
71
|
expect(dateSameOrBeforeValidation('2020-01-02')('2020-01-01', $t)).toEqual(true);
|
|
72
|
-
expect(dateSameOrBeforeValidation('2020-01-01')('2020-01-02', $t)).toEqual('
|
|
72
|
+
expect(dateSameOrBeforeValidation('2020-01-01')('2020-01-02', $t)).toEqual('components.dateSameOrBefore');
|
|
73
73
|
expect(dateSameOrBeforeValidation('2020-01-01')('2020-01-01', $t)).toEqual(true);
|
|
74
74
|
});
|
|
75
75
|
|