@itfin/components 1.4.0 → 1.4.1
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/filter/FilterPanel.vue +3 -2
- package/src/components/icon/components/nomi-export.vue +4 -0
- package/src/components/icon/components/nomi-lock.vue +4 -0
- package/src/components/table/Table2.vue +2 -0
- package/src/components/table/TableGroup.vue +3 -0
- package/src/components/table/TableHeader.vue +5 -2
- package/src/components/table/table2.scss +1 -1
- package/src/components/text-field/TextField.vue +8 -12
- package/src/components/view/View.vue +48 -27
- package/src/components/table/TableRow.vue +0 -221
package/package.json
CHANGED
|
@@ -128,8 +128,9 @@ class FilterPanel extends Vue {
|
|
|
128
128
|
if (this.endpoint) {
|
|
129
129
|
this.loading = true;
|
|
130
130
|
await this.$try(async () => {
|
|
131
|
-
const {filters} = await this.$axios.$get(this.endpoint);
|
|
131
|
+
const {filters, tableSchema} = await this.$axios.$get(this.endpoint);
|
|
132
132
|
this.filters = filters;
|
|
133
|
+
this.$emit('set-table-schema', tableSchema);
|
|
133
134
|
this.loadFiltersValue();
|
|
134
135
|
});
|
|
135
136
|
this.loading = false;
|
|
@@ -253,7 +254,7 @@ class FilterPanel extends Vue {
|
|
|
253
254
|
if (value.value && value.value.length > 1) {
|
|
254
255
|
value.label = `${value.label} та ще ${value.value.length - 1}`;
|
|
255
256
|
}
|
|
256
|
-
value.isDefault = facet.options.defaultValue ? JSON.stringify(value.value) === JSON.stringify(facet.options.defaultValue.value) : false;
|
|
257
|
+
value.isDefault = facet.options.defaultValue && value.value.length === 1 ? JSON.stringify(value.value[0]) === JSON.stringify(facet.options.defaultValue.value) : false;
|
|
257
258
|
} else if (facet.type === 'amount') {
|
|
258
259
|
if (value.value === null || (Array.isArray(value.value) && value.value.every(v => v === null))) {
|
|
259
260
|
value.value = facet.options.defaultValue.value;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
<template><svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<path fill-rule="evenodd" clip-rule="evenodd" d="M11.4 5V8C11.4 8.88366 12.1163 9.6 13 9.6H16V15.7372L15.8527 15.5899C15.2279 14.9651 14.2148 14.9651 13.59 15.5899C12.9651 16.2148 12.9651 17.2278 13.59 17.8527L14.7373 19H7C6.44772 19 6 18.5523 6 18V6C6 5.44772 6.44772 5 7 5H11.4ZM12.6 5.6V8C12.6 8.22091 12.7791 8.4 13 8.4H15.4L12.6 5.6ZM18.1456 20.1456C18.0881 20.2031 18.0218 20.2465 17.951 20.2758C17.8803 20.3051 17.8027 20.3213 17.7213 20.3213C17.6401 20.323 17.4416 20.2901 17.2971 20.1456L14.2971 17.1456C14.0627 16.9113 14.0627 16.5314 14.2971 16.297C14.5314 16.0627 14.9113 16.0627 15.1456 16.297L17.1213 18.2728V13.7213C17.1213 13.3899 17.39 13.1213 17.7213 13.1213C18.0527 13.1213 18.3213 13.3899 18.3213 13.7213V18.2728L20.2971 16.297C20.5314 16.0627 20.9113 16.0627 21.1456 16.297C21.3799 16.5314 21.3799 16.9113 21.1456 17.1456L18.1456 20.1456Z" fill="currentColor"/>
|
|
3
|
+
</svg>
|
|
4
|
+
</template>
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
<template><svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<path fill-rule="evenodd" clip-rule="evenodd" d="M12 4.3999C13.9882 4.3999 15.6 6.01168 15.6 7.9999V10.0489C16.033 10.1018 16.3329 10.2114 16.5607 10.4392C17 10.8786 17 11.5857 17 12.9999V14.9999C17 16.4141 17 17.1212 16.5607 17.5606C16.1213 17.9999 15.4142 17.9999 14 17.9999H10C8.58579 17.9999 7.87868 17.9999 7.43934 17.5606C7 17.1212 7 16.4141 7 14.9999V12.9999C7 11.5857 7 10.8786 7.43934 10.4392C7.66715 10.2114 7.96695 10.1018 8.4 10.0489L8.4 7.9999C8.4 6.01168 10.0118 4.3999 12 4.3999ZM14.4 7.9999V10.0003C14.2733 9.99991 14.1401 9.99991 14 9.99991H10C9.85987 9.99991 9.72668 9.99991 9.6 10.0003L9.6 7.9999C9.6 6.67442 10.6745 5.5999 12 5.5999C13.3255 5.5999 14.4 6.67442 14.4 7.9999ZM12.6 12.9999C12.6 12.6685 12.3314 12.3999 12 12.3999C11.6686 12.3999 11.4 12.6685 11.4 12.9999V14.9999C11.4 15.3313 11.6686 15.5999 12 15.5999C12.3314 15.5999 12.6 15.3313 12.6 14.9999V12.9999Z" fill="currentColor"/>
|
|
3
|
+
</svg>
|
|
4
|
+
</template>
|
|
@@ -56,6 +56,7 @@
|
|
|
56
56
|
:sticky-header="stickyHeader"
|
|
57
57
|
:editable-property="editableProperty"
|
|
58
58
|
:sorting.sync="_sorting"
|
|
59
|
+
:sort-as-string="sortAsString"
|
|
59
60
|
:active="active"
|
|
60
61
|
@update:expanded-ids="$emit('update:expanded-ids', $event)"
|
|
61
62
|
@new="$emit('new', $event)"
|
|
@@ -102,6 +103,7 @@ export default @Component({
|
|
|
102
103
|
})
|
|
103
104
|
class itfTable2 extends Vue {
|
|
104
105
|
// @Prop({ required: true, type: Array }) columns;
|
|
106
|
+
@Prop(Boolean) sortAsString;
|
|
105
107
|
@Prop({ required: true, type: Array }) rows;
|
|
106
108
|
@Prop({ type: String, default: null }) groupBy;
|
|
107
109
|
@Prop({ type: String, default: null }) idProperty;
|
|
@@ -39,6 +39,7 @@
|
|
|
39
39
|
:show-add-column="showAddColumn"
|
|
40
40
|
:show-actions="showActions"
|
|
41
41
|
:id-property="idProperty"
|
|
42
|
+
:sort-as-string="sortAsString"
|
|
42
43
|
:rows="rows"
|
|
43
44
|
:schema="schema"
|
|
44
45
|
:editable="editable"
|
|
@@ -66,6 +67,7 @@
|
|
|
66
67
|
:editable="editable"
|
|
67
68
|
:currency="currency"
|
|
68
69
|
:currencies="currencies"
|
|
70
|
+
:sort-as-string="sortAsString"
|
|
69
71
|
:columns="visibleColumns"
|
|
70
72
|
:no-select-all="noSelectAll"
|
|
71
73
|
:selected-ids="selectedIds"
|
|
@@ -378,6 +380,7 @@ class itfTableGroup extends Vue {
|
|
|
378
380
|
@Prop(Boolean) expandedAll;
|
|
379
381
|
@Prop(Boolean) striped;
|
|
380
382
|
@Prop(Boolean) stickyHeader;
|
|
383
|
+
@Prop(Boolean) sortAsString;
|
|
381
384
|
@Prop() indicatorWidth;
|
|
382
385
|
@Prop() shadowWidth;
|
|
383
386
|
@Prop() cssProperty;
|
|
@@ -194,6 +194,7 @@ class itfTableHeader extends Vue {
|
|
|
194
194
|
@Prop(Boolean) noColumnMenu;
|
|
195
195
|
@Prop(Boolean) noSelectAll;
|
|
196
196
|
@Prop(Boolean) editable;
|
|
197
|
+
@Prop(Boolean) sortAsString;
|
|
197
198
|
@Prop() idProperty;
|
|
198
199
|
@Prop() indicatorType;
|
|
199
200
|
|
|
@@ -411,8 +412,10 @@ class itfTableHeader extends Vue {
|
|
|
411
412
|
}
|
|
412
413
|
|
|
413
414
|
sortBy(column, order) {
|
|
414
|
-
let sort =
|
|
415
|
-
|
|
415
|
+
let sort = { [column.property]: order };
|
|
416
|
+
if (this.sortAsString) {
|
|
417
|
+
sort = order === 'desc' ? `-${column.property}` : column.property;
|
|
418
|
+
}
|
|
416
419
|
this.$emit('update:sorting', sort);
|
|
417
420
|
}
|
|
418
421
|
}
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
--itf-table-alt-bg: #F9FAFB;
|
|
8
8
|
--itf-table-alt-selected-bg: #eff1f3;
|
|
9
9
|
--itf-table-header-bg: #f5f7f8;
|
|
10
|
-
--itf-table-header-color: #
|
|
10
|
+
--itf-table-header-color: #575b63;
|
|
11
11
|
--itf-table-mirror-bg: #F2F4F7;
|
|
12
12
|
--itf-table-border-color: transparent; //var(--itf-table-header-bg);
|
|
13
13
|
--itf-table-header-border-color: #8E97A533;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
|
|
3
|
-
<div class="itf-text-field input-group
|
|
3
|
+
<div class="itf-text-field input-group" :class="{ 'with-addon addon-start': prependIcon, 'with-addon addon-end': clearable }">
|
|
4
4
|
<slot name="addon">
|
|
5
|
-
<div class="
|
|
6
|
-
<itf-icon :
|
|
5
|
+
<div class="addon" v-if="prependIcon">
|
|
6
|
+
<itf-icon :name="prependIcon"/>
|
|
7
7
|
</div>
|
|
8
8
|
</slot>
|
|
9
9
|
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
ref="input"
|
|
12
12
|
autocomplete="off"
|
|
13
13
|
:placeholder="placeholder"
|
|
14
|
-
:class="{ 'form-control-sm': small }"
|
|
14
|
+
:class="{ 'is-invalid': isInvalid(), 'is-valid': isSuccess(), 'form-control-sm': small }"
|
|
15
15
|
class="itf-text-field__input form-control"
|
|
16
16
|
:type="type"
|
|
17
17
|
:value="value"
|
|
@@ -24,13 +24,12 @@
|
|
|
24
24
|
@blur="$emit('blur', $event)"
|
|
25
25
|
@focus="$emit('focus', $event)"
|
|
26
26
|
@change="$emit('change', $event.target.value)"
|
|
27
|
-
:maxlength="maxlength"
|
|
28
27
|
:min="min"
|
|
29
28
|
:max="max"
|
|
30
29
|
:step="step"
|
|
31
30
|
/>
|
|
32
31
|
|
|
33
|
-
<
|
|
32
|
+
<div class="addon-end" v-if="clearable && value">
|
|
34
33
|
<slot name="clear">
|
|
35
34
|
<itf-button
|
|
36
35
|
icon
|
|
@@ -40,7 +39,7 @@
|
|
|
40
39
|
<itf-icon name="close" />
|
|
41
40
|
</itf-button>
|
|
42
41
|
</slot>
|
|
43
|
-
</
|
|
42
|
+
</div>
|
|
44
43
|
</div>
|
|
45
44
|
|
|
46
45
|
</template>
|
|
@@ -65,13 +64,10 @@ class itfTextField extends Vue {
|
|
|
65
64
|
@Prop() step;
|
|
66
65
|
@Prop() min;
|
|
67
66
|
@Prop() max;
|
|
68
|
-
@Prop() maxlength;
|
|
69
67
|
@Prop(Boolean) clearable;
|
|
70
68
|
@Prop(Boolean) disabled;
|
|
71
69
|
@Prop(Boolean) readonly;
|
|
72
70
|
@Prop(Boolean) small;
|
|
73
|
-
@Prop(Boolean) invalid;
|
|
74
|
-
@Prop(Boolean) valid;
|
|
75
71
|
@Prop({ type: String, default: 'text' }) type;
|
|
76
72
|
@Prop({ type: [Number, String], default: 0 }) delayInput;
|
|
77
73
|
|
|
@@ -82,11 +78,11 @@ class itfTextField extends Vue {
|
|
|
82
78
|
}
|
|
83
79
|
|
|
84
80
|
isInvalid() {
|
|
85
|
-
return
|
|
81
|
+
return this.itemLabel && this.itemLabel.isHasError();
|
|
86
82
|
}
|
|
87
83
|
|
|
88
84
|
isSuccess() {
|
|
89
|
-
return
|
|
85
|
+
return this.itemLabel && this.itemLabel.isHasSuccess();
|
|
90
86
|
}
|
|
91
87
|
|
|
92
88
|
insertTextToCurrentPosition(text) {
|
|
@@ -4,22 +4,22 @@
|
|
|
4
4
|
<itf-filter-panel
|
|
5
5
|
:search-placeholder="searchPlaceholder"
|
|
6
6
|
search
|
|
7
|
-
:mini="panel.isMultiple()"
|
|
8
7
|
class="py-2 px-3"
|
|
9
8
|
:endpoint="filtersEndpoint"
|
|
10
9
|
:panel="panel"
|
|
11
10
|
v-model="filter"
|
|
12
11
|
@input="onFilterSet"
|
|
12
|
+
@set-table-schema="setTableSchema"
|
|
13
13
|
>
|
|
14
14
|
<template #after-filter-btn>
|
|
15
|
-
<itf-dropdown v-if="$refs.table &&
|
|
15
|
+
<itf-dropdown v-if="$refs.table && tableSchema" shadow append-to-context :button-options="{ default: true, icon: true }" class="h-100" autoclose="outside">
|
|
16
16
|
<template #button>
|
|
17
17
|
<itf-icon new name="table-view" />
|
|
18
18
|
</template>
|
|
19
19
|
<div class="dropdown-header">
|
|
20
20
|
{{ $t('components.table.columns') }}
|
|
21
21
|
</div>
|
|
22
|
-
<a v-for="(property, n) of
|
|
22
|
+
<a v-for="(property, n) of tableSchema.properties" :key="n" href="" @click.stop.prevent="$refs.table.toggleVisibility(property.property)" class="dropdown-item justify-content-between d-flex gap-3">
|
|
23
23
|
<div class="d-flex align-items-center gap-1">
|
|
24
24
|
<itf-icon v-if="property.icon" :size="24" new :name="property.icon" />
|
|
25
25
|
{{getTitle(property.title)}}
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
:state-name="stateName"
|
|
57
57
|
id-property="id"
|
|
58
58
|
:rows="items"
|
|
59
|
-
:schema="
|
|
59
|
+
:schema="tableSchema"
|
|
60
60
|
:sorting="sorting"
|
|
61
61
|
:active="activeIds"
|
|
62
62
|
:show-actions="showActions"
|
|
@@ -120,7 +120,8 @@ class itfView extends Vue {
|
|
|
120
120
|
|
|
121
121
|
@Prop({ type: Boolean }) loading;
|
|
122
122
|
@Prop({ type: Array }) filters;
|
|
123
|
-
@Prop({ type: Object, required: true }) schema;
|
|
123
|
+
// @Prop({ type: Object, required: true }) schema;
|
|
124
|
+
@Prop({ type: Object }) schema;
|
|
124
125
|
// @Prop({ default: 20 }) size;
|
|
125
126
|
// @Prop({ default: 1 }) page;
|
|
126
127
|
@Prop(String) defaultSorting;
|
|
@@ -141,14 +142,30 @@ class itfView extends Vue {
|
|
|
141
142
|
filter = {};
|
|
142
143
|
loadingData = false;
|
|
143
144
|
activeIds = [];
|
|
145
|
+
tableColumns = [];
|
|
144
146
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
+
get tableSchema() {
|
|
148
|
+
console.log(123, this.tableColumns, this.schema)
|
|
149
|
+
// return this.tableColumns || this.schema;
|
|
150
|
+
if (this.tableColumns) {
|
|
151
|
+
return {
|
|
152
|
+
properties: this.tableColumns
|
|
153
|
+
}
|
|
154
|
+
} else if (this.schema) {
|
|
155
|
+
return this.schema
|
|
156
|
+
} else {
|
|
157
|
+
return {}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
147
160
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
161
|
+
created() {
|
|
162
|
+
// const defaultSize = localStorage.getItem('sizePerPage') ?? 20;
|
|
163
|
+
//
|
|
164
|
+
// const { page, size, sorting } = this.panel.getPayload() ?? {};
|
|
165
|
+
// this.page = page ?? 1;
|
|
166
|
+
// this.size = size ?? defaultSize;
|
|
167
|
+
// this.sorting = sorting ?? this.defaultSorting;
|
|
168
|
+
this.sorting = this.defaultSorting;
|
|
152
169
|
}
|
|
153
170
|
|
|
154
171
|
mounted() {
|
|
@@ -218,27 +235,31 @@ class itfView extends Vue {
|
|
|
218
235
|
}
|
|
219
236
|
|
|
220
237
|
setPanelPayload(payload) {
|
|
221
|
-
this.panel.setPayload(assignWithoutUndefined(this.panel.getPayload(), payload));
|
|
222
|
-
|
|
223
|
-
function assignWithoutUndefined(...sources) {
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
}
|
|
238
|
+
// this.panel.setPayload(assignWithoutUndefined(this.panel.getPayload(), payload));
|
|
239
|
+
//
|
|
240
|
+
// function assignWithoutUndefined(...sources) {
|
|
241
|
+
// const target = {};
|
|
242
|
+
// sources.forEach(source => {
|
|
243
|
+
// if (source && typeof source === 'object') {
|
|
244
|
+
// Object.entries(source).forEach(([key, value]) => {
|
|
245
|
+
// if (value !== undefined) {
|
|
246
|
+
// target[key] = value;
|
|
247
|
+
// }
|
|
248
|
+
// });
|
|
249
|
+
// }
|
|
250
|
+
// });
|
|
251
|
+
// return target;
|
|
252
|
+
// }
|
|
236
253
|
}
|
|
237
254
|
|
|
238
255
|
onFilterSet(filter) {
|
|
239
256
|
this.page = 1;
|
|
240
|
-
this.setPanelPayload({ ...filter, page: 1 });
|
|
257
|
+
// this.setPanelPayload({ ...filter, page: 1 });
|
|
241
258
|
this.loadData();
|
|
242
259
|
}
|
|
260
|
+
|
|
261
|
+
setTableSchema(tableSchema) {
|
|
262
|
+
this.tableColumns = tableSchema;
|
|
263
|
+
}
|
|
243
264
|
}
|
|
244
265
|
</script>
|
|
@@ -1,221 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
|
|
3
|
-
<div
|
|
4
|
-
class="table-row-template flex items-stretch" view-settings="[object Object]">
|
|
5
|
-
<div accept-group="items" class="table-view-body-space"
|
|
6
|
-
></div>
|
|
7
|
-
<div class="bg-light dark:bg-light-invert shadow-area">
|
|
8
|
-
<div class="toggler-wrapper"><!----></div>
|
|
9
|
-
<div class="handle-wrapper hover-only"><a
|
|
10
|
-
href="" class="context-menu-toggle table-item-options-menu"
|
|
11
|
-
>
|
|
12
|
-
<div class="v-popper--has-tooltip drag-handle"><i
|
|
13
|
-
data-test="table-item-options"
|
|
14
|
-
class="ic-drag"></i>
|
|
15
|
-
</div> <!----></a></div>
|
|
16
|
-
</div>
|
|
17
|
-
<div class="indicator">
|
|
18
|
-
<div class="fill on-rest table-view-row-count"><span
|
|
19
|
-
>1</span></div>
|
|
20
|
-
<div class="fill on-hover"><a
|
|
21
|
-
href=""
|
|
22
|
-
data-test="table-item-expand"><i
|
|
23
|
-
class="ic-expand"></i></a>
|
|
24
|
-
<div class="top"><a
|
|
25
|
-
data-test="table-row-generator" href=""><i
|
|
26
|
-
class="ic-plus"></i></a>
|
|
27
|
-
</div>
|
|
28
|
-
<div class=""><a
|
|
29
|
-
data-test="table-row-generator"
|
|
30
|
-
href=""><i
|
|
31
|
-
class="ic-plus"></i></a></div>
|
|
32
|
-
</div>
|
|
33
|
-
</div>
|
|
34
|
-
<div accept-group="items" class="hbox table-item-inner">
|
|
35
|
-
<div data-column="0" class="sticky last-sticky-column"
|
|
36
|
-
style="width: 240px; left: 83px;">
|
|
37
|
-
<div
|
|
38
|
-
class="table-view-item-value flex relative h-full border-b border-r border-gray bg-white dark:bg-white-invert dark:border-gray-invert hover:bg-light dark:hover:bg-gray-invert items-stretch"
|
|
39
|
-
>
|
|
40
|
-
<div
|
|
41
|
-
class="flex-auto flex gap-2 items-start p-3 show-hidden-hover overflow-hidden">
|
|
42
|
-
<a href=""
|
|
43
|
-
class="context-menu-toggle h-full line-overflow cursor-pointer flex-auto"><span>
|
|
44
|
-
Jun 30th
|
|
45
|
-
</span> <!----></a> <!---->
|
|
46
|
-
<div class="flex items-center justify-end hover-show"><a href="" tabindex="0"
|
|
47
|
-
class="text-sm p-2 ic-exit"></a>
|
|
48
|
-
</div>
|
|
49
|
-
</div>
|
|
50
|
-
</div>
|
|
51
|
-
</div>
|
|
52
|
-
<div data-column="1" class="" style="width: 400px;">
|
|
53
|
-
<div
|
|
54
|
-
class="table-view-item-value flex relative h-full border-b border-r border-gray bg-white dark:bg-white-invert dark:border-gray-invert hover:bg-light dark:hover:bg-gray-invert items-stretch"
|
|
55
|
-
><textarea
|
|
56
|
-
data-test="table-text-value" rows="2" type="text"
|
|
57
|
-
wrap="hard"
|
|
58
|
-
class="h-full px-3 input-inline text-value w-full hide-scrollbar !leading-[35px] whitespace-nowrap"></textarea>
|
|
59
|
-
</div>
|
|
60
|
-
</div>
|
|
61
|
-
<div data-column="2" class="" style="width: 240px;">
|
|
62
|
-
<div
|
|
63
|
-
class="table-view-item-value flex relative h-full border-b border-r border-gray bg-white dark:bg-white-invert dark:border-gray-invert hover:bg-light dark:hover:bg-gray-invert items-stretch"
|
|
64
|
-
>
|
|
65
|
-
<div
|
|
66
|
-
class="flex-auto flex gap-2 items-start p-3 show-hidden-hover overflow-hidden">
|
|
67
|
-
<a href=""
|
|
68
|
-
class="context-menu-toggle h-full line-overflow cursor-pointer flex-auto"><span>
|
|
69
|
-
Jul 13th
|
|
70
|
-
</span> <!----></a> <!---->
|
|
71
|
-
<div class="flex items-center justify-end hover-show"><a href="" tabindex="0"
|
|
72
|
-
class="text-sm p-2 ic-exit"></a>
|
|
73
|
-
</div>
|
|
74
|
-
</div>
|
|
75
|
-
</div>
|
|
76
|
-
</div>
|
|
77
|
-
<div data-column="3" class="" style="width: 120px;">
|
|
78
|
-
<div
|
|
79
|
-
class="table-view-item-value flex relative h-full border-b border-r border-gray bg-white dark:bg-white-invert dark:border-gray-invert hover:bg-light dark:hover:bg-gray-invert items-stretch"
|
|
80
|
-
><a href=""
|
|
81
|
-
class="context-menu-toggle table-value-label flex flex-auto p-3 w-full"><span
|
|
82
|
-
class="table-value-label-selected w-full h-full vbox"><span
|
|
83
|
-
class="flex gap-2 hide-scrollbar overflow-auto"><span
|
|
84
|
-
title="Upcoming"
|
|
85
|
-
class="label-value"
|
|
86
|
-
style="--label-color: #A7E6FF; --label-text: #4C4E69;">
|
|
87
|
-
Upcoming
|
|
88
|
-
<!----></span></span></span> <!----></a></div>
|
|
89
|
-
</div>
|
|
90
|
-
<div
|
|
91
|
-
class="extra border-b border-r border-gray dark:border-gray-invert"></div>
|
|
92
|
-
<div class="boundary top"></div>
|
|
93
|
-
<div class="boundary right"></div>
|
|
94
|
-
<div class="boundary bottom"></div>
|
|
95
|
-
<div class="boundary left"></div> <!----></div>
|
|
96
|
-
</div>
|
|
97
|
-
|
|
98
|
-
</template>
|
|
99
|
-
<script>
|
|
100
|
-
import { Vue, Component, Prop, PropSync } from 'vue-property-decorator';
|
|
101
|
-
import itfButton from '../button/Button.vue';
|
|
102
|
-
import itfIcon from '../icon/Icon.vue';
|
|
103
|
-
|
|
104
|
-
export default @Component({
|
|
105
|
-
name: 'itfTable',
|
|
106
|
-
components: {
|
|
107
|
-
itfButton,
|
|
108
|
-
itfIcon,
|
|
109
|
-
}
|
|
110
|
-
})
|
|
111
|
-
class itfTable extends Vue {
|
|
112
|
-
@PropSync('sorting', { type: Object, default: () => ({}) }) sortedColumns;
|
|
113
|
-
@Prop({ required: true, type: Array }) columns;
|
|
114
|
-
@Prop({ required: true, type: Array }) rows;
|
|
115
|
-
@Prop({ default: false, type: Boolean }) stickyHeader;
|
|
116
|
-
@Prop({ default: false, type: Boolean }) stickyColumn;
|
|
117
|
-
@Prop({ default: false, type: Boolean }) stickyLastColumn;
|
|
118
|
-
@Prop({ default: false, type: Boolean }) loading;
|
|
119
|
-
@Prop({ default: false, type: Boolean }) striped;
|
|
120
|
-
@Prop({ default: false, type: Boolean }) hoverable;
|
|
121
|
-
@Prop({ default: false, type: Boolean }) small;
|
|
122
|
-
|
|
123
|
-
sortDirection = 'asc';
|
|
124
|
-
scrolledX = false;
|
|
125
|
-
scrolledEnd = false;
|
|
126
|
-
scrolledY = false;
|
|
127
|
-
stickyObserver = null;
|
|
128
|
-
|
|
129
|
-
scrollFunc = null;
|
|
130
|
-
|
|
131
|
-
mounted() {
|
|
132
|
-
if (this.$refs.scrollContainer && this.$refs.scrollContainer2) {
|
|
133
|
-
this.scrollFunc = initSyncScroll(this.$refs.scrollContainer, this.$refs.scrollContainer2, (isEnd) => {
|
|
134
|
-
this.scrolledX = true;
|
|
135
|
-
this.scrolledEnd = isEnd;
|
|
136
|
-
}, () => {
|
|
137
|
-
this.scrolledX = false;
|
|
138
|
-
});
|
|
139
|
-
} else {
|
|
140
|
-
setTimeout(() => {
|
|
141
|
-
this.scrollFunc = initSyncScroll(this.$refs.scrollContainer, this.$refs.scrollContainer2, (isEnd) => {
|
|
142
|
-
this.scrolledX = true;
|
|
143
|
-
this.scrolledEnd = isEnd;
|
|
144
|
-
}, () => {
|
|
145
|
-
this.scrolledX = false;
|
|
146
|
-
});
|
|
147
|
-
}, 1000);
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
if (this.$refs.stickyHeader) {
|
|
151
|
-
this.stickyObserver = new IntersectionObserver(([e]) => {
|
|
152
|
-
return this.scrolledY = e.intersectionRatio < 1;
|
|
153
|
-
}, {
|
|
154
|
-
rootMargin: `-${this.$refs.stickyHeader.offsetHeight + 5}px 0px 0px 0px`,
|
|
155
|
-
threshold: [1]
|
|
156
|
-
});
|
|
157
|
-
this.stickyObserver.observe(this.$refs.stickyHeader);
|
|
158
|
-
}
|
|
159
|
-
function initSyncScroll(el1, el2, stuck, unstuck) {
|
|
160
|
-
function isScrolledEnd(el) {
|
|
161
|
-
return el.scrollWidth === el.getBoundingClientRect().width // якщо контейнер менший ширини екрану
|
|
162
|
-
|| el.scrollLeft === el.scrollWidth - el.getBoundingClientRect().width; // якщо контейнер більший ширини екрану
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
function func1() {
|
|
166
|
-
el2.scrollLeft = el1.scrollLeft;
|
|
167
|
-
if (el1.scrollLeft > 0) {
|
|
168
|
-
stuck(isScrolledEnd(el1));
|
|
169
|
-
} else {
|
|
170
|
-
unstuck();
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
function func2() {
|
|
175
|
-
el1.scrollLeft = el2.scrollLeft;
|
|
176
|
-
if (el2.scrollLeft > 0) {
|
|
177
|
-
stuck(isScrolledEnd(el2));
|
|
178
|
-
} else {
|
|
179
|
-
unstuck();
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
if (isScrolledEnd(el1)) {
|
|
184
|
-
stuck(true);
|
|
185
|
-
unstuck();
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
el1.addEventListener('scroll', func1);
|
|
189
|
-
el2.addEventListener('scroll', func2);
|
|
190
|
-
|
|
191
|
-
return [func1, func2];
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
beforeDestroy() {
|
|
196
|
-
if (this.scrollFunc) {
|
|
197
|
-
const [func1, func2] = this.scrollFunc;
|
|
198
|
-
this.$refs.scrollContainer.removeEventListener('scroll', func1);
|
|
199
|
-
this.$refs.scrollContainer2.removeEventListener('scroll', func2);
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
get columnsGridStyle() {
|
|
204
|
-
return this.columns.map((column) => {
|
|
205
|
-
if (column.min) {
|
|
206
|
-
return `minmax(${column.min}px, ${column.max ? `${column.max}px` : 'auto'})`;
|
|
207
|
-
}
|
|
208
|
-
return `${column.fraction || 1}fr`;
|
|
209
|
-
}).join(' ');
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
sortBy(column, index) {
|
|
213
|
-
if (!column.sortable) {
|
|
214
|
-
return;
|
|
215
|
-
}
|
|
216
|
-
const { name } = this.columns[index];
|
|
217
|
-
const direction = this.sortedColumns[name] === 'asc' ? 'desc' : 'asc';
|
|
218
|
-
this.sortedColumns = { [name]: direction };
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
</script>
|