@itfin/components 1.2.103 → 1.2.105

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.2.103",
3
+ "version": "1.2.105",
4
4
  "author": "Vitalii Savchuk <esvit666@gmail.com>",
5
5
  "scripts": {
6
6
  "serve": "vue-cli-service serve",
@@ -2,7 +2,7 @@
2
2
  <div class="itf-board">
3
3
 
4
4
  <div ref="container" class="itf-board-titles">
5
- <div v-for="(column, index) of columns"
5
+ <div v-for="(column, index) of orderColumnsInBoard"
6
6
  :data-column="index"
7
7
  @mouseover="columnHighlight(index, 'enter')"
8
8
  @mouseout="columnHighlight(index, 'leave')"
@@ -18,6 +18,7 @@
18
18
  accept-group="board-columns"
19
19
  @enter="columnHighlight(index, 'enter')"
20
20
  @leave="columnHighlight(index, 'leave')"
21
+ @click="$emit('update:columnSettings', column)"
21
22
  v-dropzone="{ payload: { index, column } }"
22
23
  class="d-flex align-items-center">
23
24
  <div
@@ -25,8 +26,8 @@
25
26
  @drop="reorderColumns"
26
27
  v-draggable="{ handle: true, payload: { index, column }, mirror: { yAxis:false } }"
27
28
  class="flex-grow-1 d-flex align-items-center itf-board-column__header justify-content-between">
28
- <div><slot name="header" :column="column">{{ column[columnNameKey] }}</slot></div>
29
- <div class="text-muted me-1"><slot name="header-addon" :column="column">{{ (groupedItems[column.Id] || []).length }}</slot></div>
29
+ <div><slot name="header" :column="column">{{ column[columnNameKey] }}</slot></div>
30
+ <div class="text-muted me-1"><slot name="header-addon" :column="column">{{ (groupedItems[column.Id] || []).length }}</slot></div>
30
31
  </div>
31
32
  </itf-edit-button>
32
33
  <div v-if="index === columns.length - 1"
@@ -39,7 +40,7 @@
39
40
  </div>
40
41
  </div>
41
42
  <div class="align-items-end d-flex pb-1">
42
- <slot name="add-column">
43
+ <slot name="add-column" @click="$emit('addColumn')">
43
44
  <itf-button icon small>
44
45
  <itf-icon name="plus" />
45
46
  </itf-button>
@@ -48,7 +49,7 @@
48
49
  </div>
49
50
 
50
51
  <div class="itf-board-columns flex-grow-1">
51
- <div v-for="(column, index) of columns"
52
+ <div v-for="(column, index) of orderColumnsInBoard"
52
53
  :key="`column-${index}`"
53
54
  :data-column="index"
54
55
  class="itf-board-column px-2 pb-2 pt-2" :class="{'empty': !groupedItems[column.Id]}">
@@ -66,6 +67,7 @@ import loading from '../../directives/loading';
66
67
  import itfForm from '../form/Form';
67
68
  import itfEditButton from '../editable/EditButton.vue';
68
69
  import createDraggable from '../sortable/draggable';
70
+ import { debounce } from '../../helpers/debounce';
69
71
 
70
72
  const { Node, ...draggableDirectives } = createDraggable();
71
73
 
@@ -87,6 +89,7 @@ export default @Component({
87
89
  class Board extends Vue {
88
90
  @Prop(Array) columns;
89
91
  @Prop(Array) items;
92
+ @Prop(Array) boardColumnsOrder
90
93
  @Prop(Array) columnOrders;
91
94
  @Prop({ type: Function, default: (item) => item.Status?.Id }) groupFunc;
92
95
  @Prop({ type: Function, default: (item, value) => { item.Status = value; } }) updateFunc;
@@ -100,6 +103,7 @@ class Board extends Vue {
100
103
  }
101
104
 
102
105
  mounted() {
106
+ this.itemStatusChanged = debounce(this.emitItemStatusChanged, 10);
103
107
  if (this.columnSorting) {
104
108
  Node.addContainer(this.$refs.container);
105
109
  }
@@ -113,12 +117,21 @@ class Board extends Vue {
113
117
  return grouped;
114
118
  }
115
119
 
120
+ get orderColumnsInBoard() {
121
+ return this.sortByOrdering(this.columns, this.boardColumnsOrder || []);
122
+ }
123
+
116
124
  orderItemsInColumn(column) {
117
- const columnOrdering = this.columnOrders.find((c) => c.Id === column.Id) || { ItemIds: [] };
125
+ const columnOrdering = (this.columnOrders.find((c) => c.Id === column.Id) || { ItemIds: [] }).ItemIds;
118
126
  let items = this.items.filter((item) => column.Id === this.groupFunc(item));
119
- items = items.sort((a, b) => {
120
- const aIndex = columnOrdering.ItemIds.findIndex((c) => c === a.Id);
121
- const bIndex = columnOrdering.ItemIds.findIndex((c) => c === b.Id);
127
+ return this.sortByOrdering(items, columnOrdering);
128
+ }
129
+
130
+ sortByOrdering (arr, ordering) {
131
+ const arrCopy = arr.slice();
132
+ return arrCopy.sort((a, b) => {
133
+ const aIndex = ordering.findIndex((id) => id === a.Id);
134
+ const bIndex = ordering.findIndex((id) => id === b.Id);
122
135
  if (aIndex === -1 && bIndex === -1) {
123
136
  return 0;
124
137
  }
@@ -130,7 +143,6 @@ class Board extends Vue {
130
143
  }
131
144
  return aIndex - bIndex;
132
145
  });
133
- return items;
134
146
  }
135
147
 
136
148
  columnHighlight(index, state, className = 'over') {
@@ -153,7 +165,7 @@ class Board extends Vue {
153
165
  reorderColumns({ detail }) {
154
166
  const { index: fromIndex } = detail.draggablePayload;
155
167
  const { index: toIndex, last } = detail.dropzonePayload;
156
- const newValue = [...this.columns];
168
+ const newValue = [...this.orderColumnsInBoard];
157
169
  const [removed] = newValue.splice(fromIndex, 1);
158
170
 
159
171
  if (last) {
@@ -186,36 +198,41 @@ class Board extends Vue {
186
198
 
187
199
  items[itemIndex] = newItem;
188
200
 
189
- const newOrders = [...this.columnOrders];
190
-
191
- let sorting = newOrders.find((c) => c.Id === column.Id);
192
- if (!sorting) {
193
- sorting = { Id: column.Id, ItemIds: [] };
194
- newOrders.push(sorting)
195
- }
196
- let fromSorting = newOrders.find((c) => c.Id === fromColumn.Id);
197
- if (!fromSorting) {
198
- fromSorting = { Id: fromColumn.Id, ItemIds: [] };
199
- newOrders.push(fromSorting)
200
- }
201
- // update from
202
- fromSorting.ItemIds = this.groupedItems[fromColumn.Id].map((i) => i.Id).filter((t) => t !== newItem.Id);
203
-
204
- // update to
205
- const columnItems = [...this.groupedItems[column.Id]];
206
- let placeIndex = last ? columnItems.length : toIndex;
207
- if (typeof placeIndex === 'undefined') { // ідекса може не бути, якщо на колонку переносять, тоді в кінець
208
- placeIndex = columnItems.length;
209
- }
210
- const itemsInColumn = columnItems.map((t) => t.Id).filter((t) => t !== newItem.Id);
211
- itemsInColumn.splice(placeIndex, 0, newItem.Id);
201
+ this.lastUpdatedIndex = typeof this.lastUpdatedIndex === 'undefined' ? toIndex : this.lastUpdatedIndex; // запамятовуємо індекс, бо виклики може бути два, коли колонка і карточка обробляє
202
+ this.itemStatusChanged(items[itemIndex], column, items, () => {
203
+ const toIndex = this.lastUpdatedIndex; // беремо індекс з пам'яті, бо викликів може бути два, але індекс тільки в картці, якщо нема, то це колонка
204
+ this.lastUpdatedIndex = undefined; // обнуляємо, щоб при наступному перетягувані вже не брало його
205
+ const newOrders = [...this.columnOrders];
206
+ let sorting = newOrders.find((c) => c.Id === column.Id);
207
+ if (!sorting) {
208
+ sorting = { Id: column.Id, ItemIds: [] };
209
+ newOrders.push(sorting)
210
+ }
211
+ let fromSorting = newOrders.find((c) => c.Id === fromColumn.Id);
212
+ if (!fromSorting) {
213
+ fromSorting = { Id: fromColumn.Id, ItemIds: [] };
214
+ newOrders.push(fromSorting)
215
+ }
216
+ // update from
217
+ fromSorting.ItemIds = this.groupedItems[fromColumn.Id].map((i) => i.Id).filter((t) => t !== newItem.Id);
218
+ // update to
219
+ const items = [...this.groupedItems[column.Id]];
220
+ let placeIndex = last ? items.length : toIndex;
221
+ if (typeof placeIndex === 'undefined') { // ідекса може не бути, якщо на колонку переносять, тоді в кінець
222
+ placeIndex = items.length;
223
+ }
224
+ const itemsInColumn = items.map((t) => t.Id).filter((t) => t !== newItem.Id);
225
+ itemsInColumn.splice(placeIndex, 0, newItem.Id);
226
+ sorting.ItemIds = itemsInColumn;
227
+ this.$emit('update:columnOrders', newOrders);
228
+ });
229
+ }
212
230
 
213
- sorting.ItemIds = itemsInColumn;
231
+ emitItemStatusChanged(item, column, items, updateOrder) {
232
+ updateOrder();
214
233
 
215
234
  this.$emit('update:item', [item, column]);
216
235
  this.$emit('update:items', items);
217
-
218
- this.$emit('update:columnOrders', newOrders);
219
236
  }
220
237
  }
221
238
  </script>
@@ -1,19 +1,21 @@
1
1
  <template>
2
- <div class="itf-board-card shadow-sm">
2
+ <div class="itf-board-card shadow-sm" @click="$emit('click')" tabindex="0">
3
3
  <slot name="header"></slot>
4
4
 
5
5
  <div class="itf-board-card-inner d-flex">
6
- <div class="flex-grow-1">
6
+ <div class="flex-grow-1 itf-board-card-inner-content">
7
7
  <slot>{{text}}</slot>
8
8
  </div>
9
- <div>
10
- <itf-button icon small>
9
+ <div v-if="dropdown">
10
+ <itf-button icon small @click.prevent.stop="">
11
11
  <itf-icon name="menu_horizontal" />
12
12
  </itf-button>
13
13
  </div>
14
14
  </div>
15
15
 
16
- <slot name="footer"></slot>
16
+ <div class="itf-board-card-footer pt-1 d-flex">
17
+ <slot name="footer"></slot>
18
+ </div>
17
19
  </div>
18
20
  </template>
19
21
  <script>
@@ -37,5 +39,6 @@ export default @Component({
37
39
  })
38
40
  class BoardColumn extends Vue {
39
41
  @Prop() text;
42
+ @Prop(Boolean) dropdown;
40
43
  }
41
44
  </script>
@@ -5,18 +5,17 @@
5
5
  --itf-board-placeholder-border-color: #0567eb;
6
6
  --itf-board-placeholder-bg-color: #ebeffe;
7
7
  --itf-board-card-bg-color: #fff;
8
+ --itf-board-card-hover-color: rgba(0, 0, 0, .05);
9
+ --itf-board-card-border-color: #ccc;
8
10
  }
9
11
 
10
12
  [data-theme="dark"] {
11
- --itf-board-column-hover-color: #494646;
13
+ --itf-board-column-hover-color: rgba(255, 255, 255, .05);
12
14
  --itf-board-placeholder-color: #FFCC00;
13
15
  --itf-board-placeholder-border-color: #FFCC00;
14
16
  --itf-board-placeholder-bg-color: #383b41;
15
17
  --itf-board-card-bg-color: #313337;
16
-
17
- .itf-board {
18
- --bs-border-color: #424448;
19
- }
18
+ --itf-board-card-border-color: #424448;
20
19
  }
21
20
 
22
21
  .itf-board {
@@ -108,7 +107,6 @@
108
107
  .itf-board-column {
109
108
  position: relative;
110
109
  width: var(--itf-board-column-width);
111
- min-width: var(--itf-board-column-width);
112
110
  border-radius: 0 0 var(--bs-border-radius) var(--bs-border-radius);
113
111
 
114
112
  &__title {
@@ -152,7 +150,7 @@
152
150
  }
153
151
 
154
152
  .itf-board-titles {
155
- border-bottom: 1px solid var(--bs-border-color);
153
+ border-bottom: 1px solid var(--itf-board-card-border-color);
156
154
  }
157
155
 
158
156
  .itf-board-columns {
@@ -212,18 +210,32 @@
212
210
  .itf-board-card {
213
211
  background-color: var(--itf-board-card-bg-color);
214
212
  border-radius: var(--bs-border-radius);
215
- border: 1px solid var(--bs-border-color);
213
+ border: 1px solid var(--itf-board-card-border-color);
216
214
  margin-bottom: .75rem;
217
215
  overflow: hidden;
218
216
  user-select: none;
217
+ padding: .5rem;
218
+ cursor: pointer;
219
+
220
+ &:hover, &:focus {
221
+ background-color: var(--itf-board-card-hover-bg-color);
222
+ }
219
223
 
220
224
  .itf-board-card-inner {
221
- padding: .5rem;
222
225
  font-size: .875rem;
223
226
  word-wrap: break-word;
224
227
  -webkit-line-clamp: unset;
225
- overflow-x: unset;
228
+ overflow: hidden;
226
229
  word-break: break-word;
230
+
231
+ .itf-board-card-inner-content {
232
+ padding-right: 0.2rem;
233
+ overflow-x: hidden;
234
+ }
235
+ }
236
+
237
+ .itf-board-card-footer {
238
+ overflow-x: hidden;
227
239
  }
228
240
  }
229
241
 
@@ -232,6 +244,7 @@
232
244
  flex-direction: column;
233
245
  max-height: 100%;
234
246
  flex-grow: 1;
247
+ max-width: 100%;
235
248
  }
236
249
 
237
250
  .itf-board-cards-wrapper {
@@ -243,7 +256,7 @@
243
256
  .draggable-source--is-dragging {
244
257
  position: relative !important;
245
258
  .itf-board-card {
246
- background-color: var(--bs-border-color);
259
+ background-color: var(--itf-board-card-border-color);
247
260
 
248
261
  & > div {
249
262
  opacity: 0;