@itfin/components 1.4.0 → 1.4.2

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@itfin/components",
3
- "version": "1.4.0",
3
+ "version": "1.4.2",
4
4
  "author": "Vitalii Savchuk <esvit666@gmail.com>",
5
5
  "scripts": {
6
6
  "serve": "vue-cli-service serve",
@@ -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;
@@ -35,8 +35,10 @@
35
35
  <div class="itf-table2__header-title d-flex w-100 align-items-center" :title="getTitle(column.title)">
36
36
  <itf-icon class="itf-table2__header-icon" new v-if="column.icon" :name="column.icon"></itf-icon>
37
37
  <div class="flex-grow-1 w-100 itf-table2__title-container d-flex align-items-center" :class="{'justify-content-end': column.align === 'end'}">
38
- <div class="itf-table2__title text-truncate">{{getTitle(column.title)}}</div>
39
- <div v-if="column.prefix" class="itf-table2__subtitle text-truncate" v-text="column.prefix" />
38
+ <div class="itf-table2__title text-truncate">
39
+ {{getTitle(column.title)}}
40
+ <div v-if="column.prefix" class="itf-table2__subtitle text-truncate" :class="{'text-end': column.align === 'end'}" v-text="column.prefix" />
41
+ </div>
40
42
  </div>
41
43
  </div>
42
44
  <itf-icon v-if="sortColumnParams[column.property]" :name="sortColumnParams[column.property] === 'asc' ? 'sort-asc' : 'sort-desc'" new :size="20" class="ms-1" />
@@ -194,6 +196,7 @@ class itfTableHeader extends Vue {
194
196
  @Prop(Boolean) noColumnMenu;
195
197
  @Prop(Boolean) noSelectAll;
196
198
  @Prop(Boolean) editable;
199
+ @Prop(Boolean) sortAsString;
197
200
  @Prop() idProperty;
198
201
  @Prop() indicatorType;
199
202
 
@@ -411,8 +414,10 @@ class itfTableHeader extends Vue {
411
414
  }
412
415
 
413
416
  sortBy(column, order) {
414
- let sort = order === 'desc' ? `-${column.property}` : column.property;
415
- console.info(sort);
417
+ let sort = { [column.property]: order };
418
+ if (this.sortAsString) {
419
+ sort = order === 'desc' ? `-${column.property}` : column.property;
420
+ }
416
421
  this.$emit('update:sorting', sort);
417
422
  }
418
423
  }
@@ -25,6 +25,22 @@
25
25
  <span v-if="indicatorType === 'order'">{{ (n + 1) }}</span>
26
26
  <span v-else-if="indicatorType === 'property'">{{ item[idProperty] }}</span>
27
27
  <span v-else-if="indicatorType === 'checkbox'"><itf-checkbox :value="item[idProperty]" /></span>
28
+ <a href="" @click.prevent.stop="$emit('toggle', item)" v-else-if="indicatorType === 'toggle'">
29
+ <template v-if="subrowsProperty && item[subrowsProperty] && item[subrowsProperty].length">
30
+ <template v-if="item[subrowsProperty] && item[subrowsProperty].length && !isExpanded(item)">
31
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-plus-square" viewBox="0 0 16 16">
32
+ <path d="M14 1a1 1 0 0 1 1 1v12a1 1 0 0 1-1 1H2a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1zM2 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2z"/>
33
+ <path d="M8 4a.5.5 0 0 1 .5.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3A.5.5 0 0 1 8 4"/>
34
+ </svg>
35
+ </template>
36
+ <template v-else>
37
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-dash-square" viewBox="0 0 16 16">
38
+ <path d="M14 1a1 1 0 0 1 1 1v12a1 1 0 0 1-1 1H2a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1zM2 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2z"/>
39
+ <path d="M4 8a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7A.5.5 0 0 1 4 8"/>
40
+ </svg>
41
+ </template>
42
+ </template>
43
+ </a>
28
44
  </div>
29
45
  </div>
30
46
  <div accept-group="items" class="table-item-inner" @click="$emit('row-click', item)">
@@ -33,9 +49,9 @@
33
49
  v-if="column.visible !== false"
34
50
  :data-column="k"
35
51
  :style="`width: ${column.width}px; max-width: ${column.width}px; left: ${column.left}px;`"
36
- :class="{'justify-content-end': column.align === 'end', 'sticky': column.pinned, 'last-sticky-column': k === lastPinnedIndex, 'editable': column.editable && editable}"
52
+ :class="{'sticky': column.pinned, 'last-sticky-column': k === lastPinnedIndex, 'editable': column.editable && editable}"
37
53
  class="table-view-item-value d-flex h-100">
38
- <div class="table-view-item-value-content" :class="{'px-2': !(column.editable && editable)}">
54
+ <div class="table-view-item-value-content align-items-center" :class="{'justify-content-end': column.align === 'end', 'px-2': !(column.editable && editable)}">
39
55
  <slot
40
56
  :name="`column.${column.property}`"
41
57
  :toggle="() => $emit('toggle', item)"
@@ -58,11 +74,11 @@
58
74
  <itf-select class="w-100 h-100" v-else-if="column.type === 'select'" :reduce="(item) => item.value" :value="getValue(item, column)" @input="updateValue(item, $event, n, column)" :options="column.options"></itf-select>
59
75
  </slot>
60
76
  </template>
61
- <div v-else class="h-100 align-items-center d-flex w-100">
77
+ <span v-else class="text-truncate">
62
78
  <slot :name="`format.${column.type}`" :toggle="() => $emit('toggle', item)" :level="level" :value="getValue(item, column)" :update="(value) => updateValue(item, value, n, column)" :item="item" :column="column">
63
79
  {{getValue(item, column)}}
64
80
  </slot>
65
- </div>
81
+ </span>
66
82
  </slot>
67
83
  </div>
68
84
  </div>
@@ -189,7 +205,7 @@ class itfTableRows extends Vue {
189
205
  }
190
206
 
191
207
  isActive(id) {
192
- if (!this.idProperty) {
208
+ if (!this.idProperty || !this.active) {
193
209
  return false;
194
210
  }
195
211
  if (Array.isArray(this.active)) {
@@ -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: #8E97A5;
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;
@@ -452,6 +452,7 @@ body[data-theme="dark"] {
452
452
  position: relative;
453
453
  z-index: 2;
454
454
  width: 100%;
455
+ display: flex;
455
456
  height: 100%;
456
457
  background: var(--itf-table2-row-bg)
457
458
  }
@@ -1,9 +1,9 @@
1
1
  <template>
2
2
 
3
- <div class="itf-text-field input-group form-control p-0" :class="{ 'is-invalid': isInvalid(), 'is-valid': isSuccess() }">
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="input-group-text" v-if="prependIcon">
6
- <itf-icon :size="small ? 18 : 20" :name="prependIcon"/>
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
- <template v-if="clearable && value">
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
- </template>
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 typeof this.invalid !== 'undefined' ? this.invalid : (this.itemLabel && this.itemLabel.isHasError());
81
+ return this.itemLabel && this.itemLabel.isHasError();
86
82
  }
87
83
 
88
84
  isSuccess() {
89
- return typeof this.valid !== 'undefined' ? this.valid : (this.itemLabel && this.itemLabel.isHasSuccess());
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 && schema" shadow append-to-context :button-options="{ default: true, icon: true }" class="h-100" autoclose="outside">
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 schema.properties" :key="n" href="" @click.stop.prevent="$refs.table.toggleVisibility(property.property)" class="dropdown-item justify-content-between d-flex gap-3">
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="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
- created() {
146
- const defaultSize = localStorage.getItem('sizePerPage') ?? 20;
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
- const { page, size, sorting } = this.panel.getPayload() ?? {};
149
- this.page = page ?? 1;
150
- this.size = size ?? defaultSize;
151
- this.sorting = sorting ?? this.defaultSorting;
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
- const target = {};
225
- sources.forEach(source => {
226
- if (source && typeof source === 'object') {
227
- Object.entries(source).forEach(([key, value]) => {
228
- if (value !== undefined) {
229
- target[key] = value;
230
- }
231
- });
232
- }
233
- });
234
- return target;
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>