@itfin/components 1.3.50 → 1.3.51

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.3.50",
3
+ "version": "1.3.51",
4
4
  "author": "Vitalii Savchuk <esvit666@gmail.com>",
5
5
  "scripts": {
6
6
  "serve": "vue-cli-service serve",
@@ -27,6 +27,9 @@
27
27
  :no-select-all="noSelectAll"
28
28
  :currencies="currencies"
29
29
  :currency="currency"
30
+ :subrows-property="subrowsProperty"
31
+ :indicator-type="indicatorType"
32
+ :expanded-all="expandedAll"
30
33
  @new="$emit('new', $event)"
31
34
  @add-column="$emit('add-column', $event)"
32
35
  >
@@ -70,6 +73,8 @@ class itfTable2 extends Vue {
70
73
  @Prop({ required: true, type: Array }) rows;
71
74
  @Prop({ type: String, default: null }) groupBy;
72
75
  @Prop({ type: String, default: null }) idProperty;
76
+ @Prop({ type: String, default: null }) subrowsProperty;
77
+ @Prop({ type: String, default: null, validator: (val) => ['order', 'checkbox', 'toggle', 'property'].includes(val) }) indicatorType;
73
78
  @Prop({ type: String, default: null }) stateName; // save state to storage
74
79
  @Prop({ type: Object, default: () => ({}) }) schema;
75
80
  @Prop() currency;
@@ -84,6 +89,7 @@ class itfTable2 extends Vue {
84
89
  @Prop(Boolean) noColumnMenu;
85
90
  @Prop(Boolean) noSelectAll;
86
91
  @Prop(Boolean) editable;
92
+ @Prop(Boolean) expandedAll;
87
93
 
88
94
  state = {
89
95
  selectedIds: [],
@@ -1,76 +1,31 @@
1
1
  <template>
2
-
3
- <div class="scroller">
4
- <div
5
- v-for="(item, n) in rows"
6
- :key="n"
7
- group="items"
8
- data-test="table-item"
9
- class="table-view-item grouped draggable-item"
10
- :class="{'selected': selectedIds.includes(item[idProperty])}"
2
+ <div>
3
+ <itf-table-rows
4
+ class="scroller"
5
+ :rows="rows"
6
+ :selected-ids="selectedIds"
7
+ :columns="columns"
8
+ :id-property="idProperty"
9
+ :subrows-property="subrowsProperty"
10
+ :show-add-column="showAddColumn"
11
+ :no-select-all="noSelectAll"
12
+ :editable="editable"
13
+ :currency="currency"
14
+ :currencies="currencies"
15
+ :indicatorType="indicatorType"
16
+ :expanded-ids="expandedIds"
17
+ :expanded-all="expandedAll"
18
+ @row-click="$emit('row-click', $event)"
19
+ @update="$emit('update', $event)"
20
+ @toggle="onToggle"
11
21
  >
12
- <div class="table-row-template">
13
- <div accept-group="items" class="table-view-body-space"></div>
14
- <div class="shadow-area">
15
- <div class="toggler-wrapper"></div>
16
- <div class="handle-wrapper hover-only">
17
- <a href="" class="context-menu-toggle table-item-options-menu">
18
- <div class="v-popper--has-tooltip drag-handle">
19
- <i data-test="table-item-options" class="ic-drag"></i>
20
- </div>
21
- </a>
22
- </div>
23
- </div>
24
- <div class="indicator sticky">
25
- <div class="fill table-view-row-count" :class="{'on-rest': !noSelectAll}">
26
- <span v-if="idProperty">{{ item[idProperty] }}</span>
27
- <span v-else>{{ (n + 1) }}</span>
28
- </div>
29
- <div v-if="!noSelectAll" class="fill on-hover">
30
- <itf-checkbox :value="item[idProperty]" />
31
- </div>
32
- </div>
33
- <div accept-group="items" class="table-item-inner" @click="$emit('row-click', item)">
34
- <template v-for="(column, k) in visibleAttributes">
35
- <div
36
- v-if="column.visible !== false"
37
- :data-column="k"
38
- :style="`width: ${column.width}px; max-width: ${column.width}px; left: ${column.left}px;`"
39
- :class="{'sticky': column.pinned, 'last-sticky-column': k === lastPinnedIndex, 'flex-grow-1': column.grow, 'px-2': !(column.editable && editable), 'editable': column.editable && editable}"
40
- class="table-view-item-value d-flex h-100">
41
- <slot :name="`column.${column.property}`" :editable="column.editable && editable" :item="item" :column="column" :update="(val) => updateValue(item, val, n, column)" :value="getValue(item, column)">
42
- <template v-if="column.editable && editable">
43
- <slot :name="`edit.${column.type}`" :update="(val) => updateValue(item, val, n, column)" :value="getValue(item, column)" :item="item" :column="column">
44
- <itf-text-field class="w-100" v-if="column.type === 'text'" :value="getValue(item, column)" @input="updateValue(item, $event, n, column)" />
45
- <itf-hours-field
46
- class="w-100"
47
- placeholder="00h 00m"
48
- v-else-if="column.type === 'time'"
49
- :hours="getValue(item, column)"
50
- @update:hours="updateValue(item, $event, n, column)"
51
- />
52
- <itf-textarea class="w-100" :rows="1" autogrow v-else-if="column.type === 'textarea'" :value="getValue(item, column)" @input="updateValue(item, $event, n, column)" />
53
- <itf-money-field class="w-100" currency-disabled :currency="currency" :currencies="currencies" v-else-if="column.type === 'money'" :value="getValue(item, column)" @input="updateValue(item, $event, n, column)" />
54
- <itf-select class="w-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>
55
- </slot>
56
- </template>
57
- <div v-else class="h-100 align-items-center d-flex w-100">
58
- <slot :name="`format.${column.type}`" :value="getValue(item, column)" :update="(value) => updateValue(item, value, n, column)" :item="item" :column="column">
59
- {{getValue(item, column)}}
60
- </slot>
61
- </div>
62
- </slot>
63
- </div>
64
- </template>
65
- <div v-if="showAddColumn" class="table-view-item-value extra bg-light"></div>
66
- <div class="boundary top"></div>
67
- <div class="boundary right"></div>
68
- <div class="boundary bottom"></div>
69
- <div class="boundary left"></div>
70
- </div>
71
- </div>
72
- </div>
73
-
22
+ <template v-for="(_, name) in $slots" #[name]="slotData">
23
+ <slot :name="name" v-bind="slotData || {}"/>
24
+ </template>
25
+ <template v-for="(_, name) in $scopedSlots" #[name]="slotData">
26
+ <slot :name="name" v-bind="slotData || {}"/>
27
+ </template>
28
+ </itf-table-rows>
74
29
  <div v-if="!rows.length" data-test="table-no-results" class="table-view-item">
75
30
  <div class="table-row-template">
76
31
  <div accept-group="items" class="table-view-body-space"></div>
@@ -208,63 +163,34 @@
208
163
  </style>
209
164
  <script>
210
165
  import { Vue, Component, Prop } from 'vue-property-decorator';
211
- import get from 'lodash/get';
212
- import set from 'lodash/set';
213
- // import { RecycleScroller } from 'vue-virtual-scroller'
214
- import itfCheckbox from '../checkbox/Checkbox.vue';
215
- import itfTextField from '../text-field/TextField.vue';
216
- import itfMoneyField from '../text-field/MoneyField.vue';
217
- import itfTextarea from '../text-field/Textarea.vue';
218
- import itfHoursField from '../text-field/HoursField.vue';
219
- import itfSelect from '../select/Select.vue';
220
- // import 'vue-virtual-scroller/dist/vue-virtual-scroller.css';
166
+ import itfTableRows from './TableRows.vue';
221
167
 
222
168
  export default @Component({
223
169
  name: 'itfTableBody',
224
170
  components: {
225
- itfCheckbox,
226
- itfMoneyField,
227
- itfHoursField,
228
- itfTextarea,
229
- itfTextField,
230
- itfSelect,
231
- // RecycleScroller
171
+ itfTableRows
232
172
  }
233
173
  })
234
174
  class itfTableBody extends Vue {
235
175
  @Prop() columns;
236
176
  @Prop() rows;
237
177
  @Prop() idProperty;
178
+ @Prop() subrowsProperty;
238
179
  @Prop(Boolean) showAddColumn;
239
180
  @Prop(Boolean) noSelectAll;
240
181
  @Prop(Boolean) editable;
182
+ @Prop(Boolean) expandedAll;
241
183
  @Prop() selectedIds;
242
184
  @Prop() currency;
243
185
  @Prop() currencies;
186
+ @Prop({ type: String, default: null }) indicatorType;
244
187
 
245
- getValue(item, column) {
246
- return get(item, column.property);
247
- }
188
+ expandedIds = [];
248
189
 
249
- get visibleAttributes() {
250
- return this.columns;
251
- }
252
-
253
- get lastPinnedIndex() {
254
- return this.columns.findIndex((column) => column.lastPinned);
255
- }
256
-
257
- updateValue(item, value, index, column) {
258
- const newItem = { ...item };
259
- if (newItem[column.property] !== value) {
260
- set(newItem, column.property, value);
261
- this.$emit('update', {
262
- index,
263
- item,
264
- value: newItem,
265
- column
266
- });
267
- }
190
+ onToggle(item) {
191
+ this.expandedIds = this.expandedIds.includes(item[this.idProperty])
192
+ ? this.expandedIds.filter((id) => id !== item[this.idProperty])
193
+ : [...this.expandedIds, item[this.idProperty]];
268
194
  }
269
195
  }
270
196
  </script>
@@ -55,6 +55,7 @@
55
55
  @update="$emit('update', $event)"
56
56
  @row-click="$emit('row-click', $event)"
57
57
  :id-property="idProperty"
58
+ :subrows-property="subrowsProperty"
58
59
  :rows="rows"
59
60
  :editable="editable"
60
61
  :currency="currency"
@@ -62,6 +63,8 @@
62
63
  :columns="visibleColumns"
63
64
  :no-select-all="noSelectAll"
64
65
  :selected-ids="selectedIds"
66
+ :indicatorType="indicatorType"
67
+ :expanded-all="expandedAll"
65
68
  :show-add-column="showAddColumn">
66
69
  <template v-for="(_, name) in $slots" #[name]="slotData">
67
70
  <slot :name="name" v-bind="slotData || {}"/>
@@ -323,6 +326,7 @@ class itfTableGroup extends Vue {
323
326
  @Prop() selectedIds;
324
327
  @Prop() title;
325
328
  @Prop() idProperty;
329
+ @Prop() subrowsProperty;
326
330
  @Prop() currency;
327
331
  @Prop() currencies;
328
332
  @Prop(Boolean) showGrouping;
@@ -335,6 +339,8 @@ class itfTableGroup extends Vue {
335
339
  @Prop(Boolean) noColumnMenu;
336
340
  @Prop(Boolean) noSelectAll;
337
341
  @Prop(Boolean) editable;
342
+ @Prop(Boolean) expandedAll;
343
+ @Prop({ type: String, default: null }) indicatorType;
338
344
  @Prop({type: String, default: function() { return this.$t('components.table.new'); } }) newLabel;
339
345
  @Prop({type: Object, default: () => ({})}) schema;
340
346
 
@@ -0,0 +1,191 @@
1
+ <template>
2
+ <div>
3
+ <template v-for="(item, n) in rows">
4
+ <div
5
+ :key="n"
6
+ group="items"
7
+ data-test="table-item"
8
+ class="table-view-item grouped draggable-item"
9
+ :class="{'selected': selectedIds.includes(item[idProperty])}"
10
+ >
11
+ <div class="table-row-template">
12
+ <div accept-group="items" class="table-view-body-space"></div>
13
+ <div class="shadow-area">
14
+ <div class="toggler-wrapper"></div>
15
+ <div class="handle-wrapper hover-only">
16
+ <a href="" class="context-menu-toggle table-item-options-menu">
17
+ <div class="v-popper--has-tooltip drag-handle">
18
+ <i data-test="table-item-options" class="ic-drag"></i>
19
+ </div>
20
+ </a>
21
+ </div>
22
+ </div>
23
+ <div class="indicator sticky">
24
+ <div class="fill table-view-row-count" :class="{'on-rest': !noSelectAll}">
25
+ <span v-if="indicatorType === 'order'">{{ (n + 1) }}</span>
26
+ <span v-else-if="indicatorType === 'property'">{{ item[idProperty] }}</span>
27
+ <a href="" @click.prevent.stop="$emit('toggle', item)" v-else-if="indicatorType === 'toggle'">
28
+ <template v-if="subrowsProperty && item[subrowsProperty] && item[subrowsProperty].length">
29
+ <template v-if="item[subrowsProperty] && item[subrowsProperty].length && !isExpanded(item)">
30
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-plus-square" viewBox="0 0 16 16">
31
+ <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"/>
32
+ <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"/>
33
+ </svg>
34
+ </template>
35
+ <template v-else>
36
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-square" viewBox="0 0 16 16">
37
+ <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"/>
38
+ </svg>
39
+ </template>
40
+ </template>
41
+ </a>
42
+ </div>
43
+ <div v-if="!noSelectAll" class="fill on-hover">
44
+ <itf-checkbox :value="item[idProperty]" />
45
+ </div>
46
+ </div>
47
+ <div accept-group="items" class="table-item-inner" @click="$emit('row-click', item)">
48
+ <template v-for="(column, k) in visibleAttributes">
49
+ <div
50
+ v-if="column.visible !== false"
51
+ :data-column="k"
52
+ :style="`width: ${column.width}px; max-width: ${column.width}px; left: ${column.left}px;`"
53
+ :class="{'sticky': column.pinned, 'last-sticky-column': k === lastPinnedIndex, 'flex-grow-1': column.grow, 'px-2': !(column.editable && editable), 'editable': column.editable && editable}"
54
+ class="table-view-item-value d-flex h-100">
55
+ <slot :name="`column.${column.property}`" :level="level" :editable="column.editable && editable" :item="item" :column="column" :update="(val) => updateValue(item, val, n, column)" :value="getValue(item, column)">
56
+ <template v-if="column.editable && editable">
57
+ <slot :name="`edit.${column.type}`" :level="level" :update="(val) => updateValue(item, val, n, column)" :value="getValue(item, column)" :item="item" :column="column">
58
+ <itf-text-field class="w-100" v-if="column.type === 'text'" :value="getValue(item, column)" @input="updateValue(item, $event, n, column)" />
59
+ <itf-hours-field
60
+ class="w-100"
61
+ placeholder="00h 00m"
62
+ v-else-if="column.type === 'time'"
63
+ :hours="getValue(item, column)"
64
+ @update:hours="updateValue(item, $event, n, column)"
65
+ />
66
+ <itf-textarea class="w-100" :rows="1" autogrow v-else-if="column.type === 'textarea'" :value="getValue(item, column)" @input="updateValue(item, $event, n, column)" />
67
+ <itf-money-field class="w-100" currency-disabled :currency="currency" :currencies="currencies" v-else-if="column.type === 'money'" :value="getValue(item, column)" @input="updateValue(item, $event, n, column)" />
68
+ <itf-select class="w-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>
69
+ </slot>
70
+ </template>
71
+ <div v-else class="h-100 align-items-center d-flex w-100">
72
+ <slot :name="`format.${column.type}`" :level="level" :value="getValue(item, column)" :update="(value) => updateValue(item, value, n, column)" :item="item" :column="column">
73
+ {{getValue(item, column)}}
74
+ </slot>
75
+ </div>
76
+ </slot>
77
+ </div>
78
+ </template>
79
+ <div v-if="showAddColumn" class="table-view-item-value extra bg-light"></div>
80
+ <div class="boundary top"></div>
81
+ <div class="boundary right"></div>
82
+ <div class="boundary bottom"></div>
83
+ <div class="boundary left"></div>
84
+ </div>
85
+ </div>
86
+ </div>
87
+ <template v-if="subrowsProperty && item[subrowsProperty] && item[subrowsProperty].length">
88
+ <itf-table-rows
89
+ v-show="isExpanded(item)"
90
+ :selected-ids="selectedIds"
91
+ :rows="item[subrowsProperty]"
92
+ :columns="columns"
93
+ :id-property="idProperty"
94
+ :subrows-property="subrowsProperty"
95
+ :show-add-column="showAddColumn"
96
+ :no-select-all="noSelectAll"
97
+ :editable="editable"
98
+ :currency="currency"
99
+ :currencies="currencies"
100
+ :indicator-type="indicatorType"
101
+ :level="level + 1"
102
+ :expanded-ids="expandedIds"
103
+ :expanded-all="expandedAll"
104
+ @toggle="$emit('toggle', $event)"
105
+ >
106
+ <template v-for="(_, name) in $slots" #[name]="slotData">
107
+ <slot :name="name" v-bind="slotData || {}" />
108
+ </template>
109
+ <template v-for="(_, name) in $scopedSlots" #[name]="slotData">
110
+ <slot :name="name" v-bind="slotData || {}" />
111
+ </template>
112
+ </itf-table-rows>
113
+ </template>
114
+ </template>
115
+ </div>
116
+ </template>
117
+ <script>
118
+ import { Vue, Component, Prop } from 'vue-property-decorator';
119
+ import get from 'lodash/get';
120
+ import set from 'lodash/set';
121
+ // import { RecycleScroller } from 'vue-virtual-scroller'
122
+ import itfCheckbox from '../checkbox/Checkbox.vue';
123
+ import itfTextField from '../text-field/TextField.vue';
124
+ import itfMoneyField from '../text-field/MoneyField.vue';
125
+ import itfTextarea from '../text-field/Textarea.vue';
126
+ import itfHoursField from '../text-field/HoursField.vue';
127
+ import itfSelect from '../select/Select.vue';
128
+ import itfTableBody from '@itfin/components/src/components/table/TableBody.vue';
129
+ // import 'vue-virtual-scroller/dist/vue-virtual-scroller.css';
130
+
131
+ export default @Component({
132
+ name: 'itfTableRows',
133
+ components: {
134
+ itfTableBody,
135
+ itfCheckbox,
136
+ itfMoneyField,
137
+ itfHoursField,
138
+ itfTextarea,
139
+ itfTextField,
140
+ itfSelect,
141
+ // RecycleScroller
142
+ }
143
+ })
144
+ class itfTableRows extends Vue {
145
+ @Prop() columns;
146
+ @Prop() rows;
147
+ @Prop() idProperty;
148
+ @Prop() subrowsProperty;
149
+ @Prop(Boolean) showAddColumn;
150
+ @Prop(Boolean) noSelectAll;
151
+ @Prop(Boolean) editable;
152
+ @Prop(Boolean) expandedAll;
153
+ @Prop() selectedIds;
154
+ @Prop() expandedIds;
155
+ @Prop() currency;
156
+ @Prop() currencies;
157
+ @Prop({ type: Number, default: 0 }) level;
158
+ @Prop({ type: String, default: null, validator: (val) => ['order', 'checkbox', 'toggle', 'property'].includes(val) }) indicatorType;
159
+
160
+ getValue(item, column) {
161
+ return get(item, column.property);
162
+ }
163
+
164
+ get visibleAttributes() {
165
+ return this.columns;
166
+ }
167
+
168
+ get lastPinnedIndex() {
169
+ return this.columns.findIndex((column) => column.lastPinned);
170
+ }
171
+
172
+ updateValue(item, value, index, column) {
173
+ const newItem = { ...item };
174
+ if (newItem[column.property] !== value) {
175
+ set(newItem, column.property, value);
176
+ this.$emit('update', {
177
+ index,
178
+ item,
179
+ value: newItem,
180
+ column
181
+ });
182
+ }
183
+ }
184
+
185
+ isExpanded(item) {
186
+ const isExpanded = this.expandedIds.includes(item[this.idProperty]);
187
+ console.info(isExpanded, this.expandedAll)
188
+ return this.expandedAll ? !isExpanded : isExpanded;
189
+ }
190
+ }
191
+ </script>