@itfin/components 1.2.97 → 1.2.99

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.
@@ -2,45 +2,91 @@
2
2
 
3
3
  <div class="itf-table-header">
4
4
  <div ref="container" class="table-row-template">
5
- <div accept-group="items" class="table-view-body-space"></div>
6
- <div class="tw-bg-light dark:tw-bg-light-invert shadow-area"></div>
5
+ <div accept-group="items" class="table-view-body-space" v-dropzone="{ payload: 0 }"></div>
6
+ <div class="shadow-area"></div>
7
7
  <div class="table-view-header-value reserved sticky"></div>
8
8
 
9
- <div v-for="(column, n) in sortedColumns" :key="n" data-test="table-header-column" :data-column="n" :data-id="column.Id"
10
- class="table-view-header-value" :style="`width: ${column.width}px; left: 0px;`">
11
- <div accept-group="tablecolumns" class="table-view-header-space">
9
+ <template v-for="(column, n) in visibleAttributes">
10
+ <div
11
+ v-if="column.visible !== false"
12
+ :key="n"
13
+ data-test="table-header-column"
14
+ :data-column="n"
15
+ :data-id="column.Id"
16
+ :class="{'sticky': column.pinned, 'last-sticky-column': n === lastPinnedIndex}"
17
+ class="table-view-header-value"
18
+ :style="`width: ${column.width}px; left: ${column.left}px;`">
19
+ <div accept-group="tablecolumns"
20
+ class="table-view-header-space"
21
+ @enter="columnHighlight(n, 'enter')"
22
+ @leave="columnHighlight(n, 'leave')"
23
+ v-dropzone="{ payload: { index: n, attribute: column } }">
12
24
  <div class="table-view-header-dropzone"></div>
13
25
  </div>
14
- <div group="tablecolumns" class="table-header draggable-item drag-handle">
15
- <span href="" class="context-menu-toggle flex-auto line-overflow">
16
- <span :title="column.text">
17
- <!-- <itf-icon name="type_select" :size="16" />-->
18
- {{column.text}}
19
- </span>
20
- </span>
21
- </div>
22
- <div v-if="columnResizing" ref="resizeHandle" class="resize-handle"></div>
23
- </div>
26
+ <div group="tablecolumns"
27
+ class="table-header"
28
+ @drop="reorderColumns"
29
+ v-drag-handle
30
+ v-draggable="{ handle: true, payload: { index: n, item: column }, mirror: {yAxis:false} }">
31
+ <itf-dropdown text append-to-body shadow ref="dropdown" class="w-100">
32
+ <template #button>
33
+ <span :title="column.text">
34
+ <!-- <itf-icon name="type_select" :size="16" />-->
35
+ {{column.text}}
36
+ </span>
37
+ </template>
24
38
 
25
- <!--div class="table-view-header-value">
26
- <div class="attribute-creator">
27
- <div data-test="dropdown"
28
- class="dropdown-body tw-relative tw-cursor-pointer tw-w-full">
29
- <div tabindex="0" data-test="dropdown-toggle">
30
- <div class="hbox tw-flex-auto tw-items-center tw-justify-center">
31
- <a href="" data-test="table-header-add-column" class="tw-text-blue tw-mx-4">
32
- <span class="ic-plus"></span>
33
- Add column
34
- </a>
35
- </div>
36
- </div>
37
- <span style="display: none;">
38
- <div class="context-modal-backdrop"></div>
39
- <div class="context-modal tw-min-w-[280px]"></div>
40
- </span>
39
+ <ul class="dropdown-menu show ps-0" aria-labelledby="dropdownMenuOffset">
40
+ <li v-if="column.sortable">
41
+ <a class="dropdown-item d-flex align-items-center" href="javascript:;">
42
+ <itf-icon name="arrow_up" :size="16" class="me-1" />
43
+ Sort By Asc
44
+ </a>
45
+ </li>
46
+ <li v-if="column.sortable">
47
+ <a class="dropdown-item d-flex align-items-center" href="javascript:;">
48
+ <itf-icon name="arrow_down" :size="16" class="me-1" />
49
+ Sort By Desc
50
+ </a>
51
+ </li>
52
+ <li v-if="column.groupable">
53
+ <a class="dropdown-item d-flex align-items-center" href="javascript:;">
54
+ <itf-icon name="episodes" :size="16" class="me-1" />
55
+ Group By
56
+ </a>
57
+ </li>
58
+ <li>
59
+ <a class="dropdown-item d-flex align-items-center" href="javascript:;" @click="togglePinned(n)">
60
+ <itf-icon :name="column.pinned ? 'checkbox_checked' : 'checkbox_empty'" :size="16" class="me-1" />
61
+ <span v-if="column.pinned">Unpin Column</span>
62
+ <span v-else>Pin Column</span>
63
+ </a>
64
+ </li>
65
+ <li>
66
+ <a class="dropdown-item d-flex align-items-center" href="javascript:;" @click="hideColumn(n)">
67
+ <itf-icon name="eye_no" :size="16" class="me-1" />
68
+ Hide
69
+ </a>
70
+ </li>
71
+ </ul>
72
+ </itf-dropdown>
73
+ </div>
74
+ <div v-if="n === sortedColumns.length - 1"
75
+ @enter="columnHighlightLast('enter')"
76
+ @leave="columnHighlightLast('leave')"
77
+ accept-group="tablecolumns"
78
+ class="table-view-header-space right"
79
+ v-dropzone="{payload:{ last: true }}">
80
+ <div class="table-view-header-dropzone"></div>
41
81
  </div>
82
+ <div v-if="columnResizing" ref="resizeHandle" class="resize-handle"></div>
42
83
  </div>
43
- </div-->
84
+ </template>
85
+ <div v-if="showAddColumn" class="table-view-header-value">
86
+ <span class="table-header table-header-add-column" data-test="table-header-add-column" @click.prevent="$emit('add-column')">
87
+ <itf-icon name="plus" />
88
+ </span>
89
+ </div>
44
90
  </div>
45
91
  </div>
46
92
 
@@ -50,15 +96,22 @@
50
96
  position: sticky;
51
97
  top: 0;
52
98
  z-index: calc(var(--row-count) + 1);
99
+ border-top: 1px solid var(--bs-border-color);
53
100
 
101
+ .table-header.draggable-mirror{
102
+ z-index: 100000001;
103
+ background: rgba(235,237,239,0.75);
104
+ }
54
105
  .table-row-template {
55
106
  display: flex;
56
107
  align-items: stretch;
57
108
  height: var(--table-small-row-size);
109
+ user-select: none;
58
110
  }
59
111
  .table-view-header-value {
112
+ cursor: pointer;
60
113
  align-items: center;
61
- height: 36px;
114
+ height: var(--table-row-height);
62
115
  white-space: nowrap;
63
116
  border-top: 0;
64
117
  border-left: 0;
@@ -67,9 +120,12 @@
67
120
  border-style: solid;
68
121
  position: relative;
69
122
  display: flex;
70
- border-right-color: rgb(218 218 218 / 1);
71
- border-bottom-color: rgb(238 238 238 / 1);
72
- background-color: rgb(238 238 238 / 1);
123
+ min-width: var(--table-min-width);
124
+ border-right-color: var(--bs-border-color);
125
+ border-bottom-color: var(--bs-border-color);
126
+ background-color: var(--bs-body-bg);
127
+ //background-color: rgb(238 238 238 / 1);
128
+ font-weight: 500;
73
129
 
74
130
  &.reserved {
75
131
  left: var(--shadow-area-width);
@@ -91,11 +147,14 @@
91
147
  padding-right: 0.75rem;
92
148
  gap: 0.25rem;
93
149
  align-items: center;
94
- display: flex;
150
+
151
+ &.table-header-add-column {
152
+ text-overflow: clip;
153
+ }
95
154
  }
96
155
  .resize-handle {
97
156
  width: 4px;
98
- height: 36px;
157
+ height: var(--table-row-height);
99
158
  position: absolute;
100
159
  right: -2px;
101
160
  top: 0;
@@ -111,7 +170,6 @@
111
170
  }
112
171
  }
113
172
  .context-menu-toggle {
114
- display: flex;
115
173
  flex: 1 1 auto;
116
174
  text-overflow: ellipsis;
117
175
  white-space: nowrap;
@@ -134,6 +192,18 @@
134
192
  z-index: 100;
135
193
  width: 2px;
136
194
  margin-left: -1px;
195
+
196
+ &.right {
197
+ left: auto;
198
+ right: 0;
199
+ top: 0;
200
+ }
201
+ &.active {
202
+ display: block;
203
+ &.over {
204
+ background: #47BEFF;
205
+ }
206
+ }
137
207
  }
138
208
  .draggable-mirror {
139
209
  opacity: .5;
@@ -163,35 +233,80 @@
163
233
  import { Vue, Component, Prop, PropSync } from 'vue-property-decorator';
164
234
  import itfButton from '../button/Button.vue';
165
235
  import itfIcon from '../icon/Icon.vue';
166
- import { Draggable, Droppable, Sortable } from '@shopify/draggable';
236
+ import createDraggable from '../sortable/draggable';
237
+ import itfDropdown from '../dropdown/Dropdown.vue';
238
+
239
+ const { Node, ...draggableDirectives } = createDraggable();
167
240
 
168
241
  export default @Component({
169
242
  name: 'itfTableHeader',
170
243
  components: {
244
+ itfDropdown,
171
245
  itfButton,
172
246
  itfIcon
247
+ },
248
+ directives: {
249
+ ...draggableDirectives
173
250
  }
174
251
  })
175
252
  class itfTable extends Vue {
176
253
  @PropSync('columns', { type: Array, default: () => ([]) }) sortedColumns;
177
254
  @Prop(Boolean) columnSorting;
178
255
  @Prop(Boolean) columnResizing;
256
+ @Prop(Boolean) showAddColumn;
179
257
 
180
- initDraggable() {
181
- const draggable = new Sortable(this.$refs.container, {
182
- // draggable: '[group="tablecolumns"]',
183
- draggable: '[data-test="table-header-column"]',
184
- mirror: {
185
- yAxis: false,
186
- appendTo: this.$refs.container
187
- }
258
+ get visibleAttributes() {
259
+ return this.sortedColumns;
260
+ }
261
+
262
+ get lastPinnedIndex() {
263
+ return this.sortedColumns.findIndex((column) => column.lastPinned);
264
+ }
265
+
266
+ onSort(items) {
267
+ console.info(items);
268
+ }
269
+
270
+ reorderColumns({ detail }) {
271
+ const { index: fromIndex } = detail.draggablePayload;
272
+ const { index: toIndex, last } = detail.dropzonePayload;
273
+ const newValue = [...this.sortedColumns];
274
+ const [removed] = newValue.splice(fromIndex, 1);
275
+ let putIndex = (removed.pinned && toIndex > this.lastPinnedIndex + 1) ? this.lastPinnedIndex : toIndex;
276
+ if (!removed.pinned && toIndex <= this.lastPinnedIndex) {
277
+ putIndex = this.lastPinnedIndex + 1;
278
+ }
279
+
280
+ if (last) {
281
+ newValue.push(removed);
282
+ } else {
283
+ newValue.splice((fromIndex < putIndex) ? putIndex - 1 : putIndex, 0, removed);
284
+ }
285
+ this.$emit('sort:columns', newValue);
286
+ if (last) {
287
+ this.columnHighlightLast('leave');
288
+ } else {
289
+ this.columnHighlight(toIndex, 'leave');
290
+ }
291
+ for (const dropdown of this.$refs.dropdown) {
292
+ dropdown.hide();
293
+ }
294
+ }
295
+
296
+ columnHighlight(index, state) {
297
+ Array.from(document.querySelectorAll(`[data-column="${index}"]`)).forEach(t=>{
298
+ state === "enter" ? t.classList.add("highlight-drop-column") : t.classList.remove("highlight-drop-column")
188
299
  });
189
- // const droppable = new Droppable(this.$refs.container, {
190
- // draggable: '[group="tablecolumns"]',
191
- // dropzone: '[accept-group="tablecolumns"]'
192
- // });
193
- draggable.on('drag:stop', (event) => {
194
- console.info('dropped', event);
300
+ }
301
+ columnHighlightLast(state) {
302
+ Array.from(document.querySelectorAll(`[data-column="${this.sortedColumns.length - 1}"]`)).forEach(t=>{
303
+ if (state === "enter") {
304
+ t.classList.add("highlight-drop-column");
305
+ t.classList.add("right");
306
+ } else {
307
+ t.classList.remove("highlight-drop-column");
308
+ t.classList.remove("right");
309
+ }
195
310
  });
196
311
  }
197
312
 
@@ -205,16 +320,18 @@ class itfTable extends Vue {
205
320
  const startX = event.pageX;
206
321
  const index = column.getAttribute('data-column');
207
322
  const columns = body.querySelectorAll(`[data-column="${index}"]`);
323
+ let newWidth;
208
324
  const mouseMoveHandler = (event) => {
209
325
  const delta = event.pageX - startX;
326
+ newWidth = Math.max(columnWidth + delta, 100);
210
327
  columns.forEach((column) => {
211
- column.style.width = `${columnWidth + delta}px`;
328
+ column.style.width = `${newWidth}px`;
212
329
  });
213
- this.changeColumn(index, { width: columnWidth + delta });
214
330
  };
215
331
  const mouseUpHandler = () => {
216
332
  document.removeEventListener('mousemove', mouseMoveHandler);
217
333
  document.removeEventListener('mouseup', mouseUpHandler);
334
+ this.changeColumn(index, { width: newWidth });
218
335
  };
219
336
  document.addEventListener('mousemove', mouseMoveHandler);
220
337
  document.addEventListener('mouseup', mouseUpHandler);
@@ -222,9 +339,15 @@ class itfTable extends Vue {
222
339
  });
223
340
  }
224
341
 
342
+ beforeDestroy() {
343
+ if (this.columnSorting) {
344
+ Node.removeContainer(this.$refs.container);
345
+ }
346
+ }
347
+
225
348
  mounted() {
226
349
  if (this.columnSorting) {
227
- this.initDraggable();
350
+ Node.addContainer(this.$refs.container);
228
351
  }
229
352
  if (this.columnResizing) {
230
353
  this.initResizing();
@@ -232,7 +355,20 @@ class itfTable extends Vue {
232
355
  }
233
356
 
234
357
  changeColumn(index, params) {
235
- console.info(index, params);
358
+ this.$refs.dropdown[index].hide();
359
+ let newValue = [...this.sortedColumns];
360
+ const newItem = { ...newValue[index] };
361
+ Object.assign(newItem, params);
362
+ newValue[index] = newItem;
363
+ this.$emit('update:columns', newValue);
364
+ }
365
+
366
+ hideColumn(index) {
367
+ this.changeColumn(index, { visible: false });
368
+ }
369
+
370
+ togglePinned(index) {
371
+ this.changeColumn(index, { pinned: !this.sortedColumns[index].pinned });
236
372
  }
237
373
  }
238
374
  </script>
@@ -81,17 +81,24 @@ storiesOf('Common', module)
81
81
  },
82
82
  data() {
83
83
  return {
84
- list: Array.from({length: 10}).map((_, i) => ({
84
+ list: Array.from({length: 20}).map((_, i) => ({
85
85
  Id: i,
86
- text: `Рахунок`,
86
+ text: `Рахунок ✅`,
87
87
  Name: `Item #${i}`
88
- })),
88
+ })).concat(Array.from({length: 20}).map((_, i) => ({
89
+ Id: i,
90
+ text: `Рахунок ❌`,
91
+ Name: `Item #${i}`
92
+ }))),
89
93
  columns: [{
90
94
  text: 'Рахунок',
91
95
  name: 'Account',
92
96
  width: 200,
93
97
  min: 250,
94
- max: 250
98
+ max: 250,
99
+ sortable: true,
100
+ groupable: true,
101
+ pinned: true
95
102
  }, {
96
103
  text: 'Dr',
97
104
  name: 'Total',
@@ -101,6 +108,67 @@ storiesOf('Common', module)
101
108
  ],
102
109
  width: 200,
103
110
  min: 150,
111
+ max: 150,
112
+ pinned: true
113
+ }, {
114
+ text: 'Cr 1',
115
+ name: 'Total',
116
+ Type: 'select',
117
+ Options: [
118
+ { Id: 1, Name: 'test' }
119
+ ],
120
+ width: 200,
121
+ min: 150,
122
+ max: 150
123
+ }, {
124
+ text: 'Cr 2',
125
+ name: 'Total',
126
+ Type: 'select',
127
+ Options: [
128
+ { Id: 1, Name: 'test' }
129
+ ],
130
+ width: 200,
131
+ min: 150,
132
+ max: 150
133
+ }, {
134
+ text: 'Cr 3',
135
+ name: 'Total',
136
+ Type: 'select',
137
+ Options: [
138
+ { Id: 1, Name: 'test' }
139
+ ],
140
+ width: 200,
141
+ min: 150,
142
+ max: 150
143
+ }, {
144
+ text: 'Cr 4',
145
+ name: 'Total',
146
+ Type: 'select',
147
+ Options: [
148
+ { Id: 1, Name: 'test' }
149
+ ],
150
+ width: 200,
151
+ min: 150,
152
+ max: 150
153
+ }, {
154
+ text: 'Cr',
155
+ name: 'Total',
156
+ Type: 'select',
157
+ Options: [
158
+ { Id: 1, Name: 'test' }
159
+ ],
160
+ width: 200,
161
+ min: 150,
162
+ max: 150
163
+ }, {
164
+ text: 'Cr',
165
+ name: 'Total',
166
+ Type: 'select',
167
+ Options: [
168
+ { Id: 1, Name: 'test' }
169
+ ],
170
+ width: 200,
171
+ min: 150,
104
172
  max: 150
105
173
  }, {
106
174
  text: 'Cr',
@@ -115,6 +183,11 @@ storiesOf('Common', module)
115
183
  }]
116
184
  }
117
185
  },
186
+ methods: {
187
+ onAdd() {
188
+ console.info('add')
189
+ }
190
+ },
118
191
  template: `<div>
119
192
  <p>You need wrap whole application with this tag</p>
120
193
 
@@ -131,7 +204,9 @@ storiesOf('Common', module)
131
204
 
132
205
  <h3>Example</h3>
133
206
 
134
- <itf-table2 :columns="columns" :rows="list">
207
+ <itf-table2
208
+ group-by="text"
209
+ :columns.sync="columns" :rows="list" column-sorting column-resizing show-add-column show-grouping @add-column="onAdd">
135
210
  <template #column.Account="{ item }">
136
211
  {{item.text}}
137
212
  </template>
package/src/locales/uk.js CHANGED
@@ -56,4 +56,40 @@ module.exports = {
56
56
  addMore: 'Додати ще',
57
57
  close: 'Закрити',
58
58
  wholeYear: 'Весь рік',
59
+
60
+ select: {
61
+ loading: 'Завантаження...',
62
+ noOptions: 'Виберіть значення зі списку',
63
+ },
64
+ modal: {
65
+ delete: 'Видалити',
66
+ cancel: 'Відмінити',
67
+ save: 'Зберегти',
68
+ itemHasBeenSuccessfullySaved: 'Успішно збережено',
69
+ itemHasBeenSuccessfullyDeleted: 'Успішно видалено',
70
+ networkProblem: 'Проблеми з мережею. Перевірте підключення до Інтернету. Також проблема може виникнути через використання VPN.',
71
+ pleaseFixTheErrorsBelowToProceed: 'Щоб продовжити, виправте, будь ласка, помилки у формі.',
72
+ },
73
+ popover: {
74
+ noKeepIt: 'Ні,&nbsp;залишити',
75
+ yesDelete: 'Так,&nbsp;видалити',
76
+ areYouSureToDeleteThis: 'Ви впевнені, що хочете видалити це?',
77
+ confirmDelete: 'Підтвердження видалення',
78
+ },
79
+ customize: {
80
+ editProperty: 'Редагувати поле',
81
+ hideProperty: 'Видимість поля',
82
+ alwaysShow: 'Завжди показувати',
83
+ hideWhenEmpty: 'Приховувати, якщо порожнє',
84
+ alwaysHide: 'Завжди приховувати',
85
+ duplicateProperty: 'Дублювати поле',
86
+ deleteProperty: 'Видалити поле',
87
+ areYouSureYouWantToDeleteThisField: 'Ви впевнені, що хочете видалити це поле?',
88
+ customizePage: 'Налаштувати сторінку',
89
+ type: 'Тип',
90
+ options: 'Опції',
91
+ addOption: 'Додати опцію',
92
+ showMoreProperties: 'Ще {n} поле|Ще {n} полів',
93
+ hideMoreProperties: 'Приховати {n} поле|Приховати {n} полів',
94
+ }
59
95
  };