@itfin/components 1.2.102 → 1.2.104

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.102",
3
+ "version": "1.2.104",
4
4
  "author": "Vitalii Savchuk <esvit666@gmail.com>",
5
5
  "scripts": {
6
6
  "serve": "vue-cli-service serve",
@@ -29,7 +29,7 @@
29
29
  </li>
30
30
  </ul>
31
31
  </div>
32
- <div v-if="value.Type === 'multiselect'" sortable-skip>
32
+ <div v-if="value.Type === 'multiselect'">
33
33
  <div class="d-flex justify-content-between pe-2">
34
34
  <h6 class="dropdown-header">{{ $t('components.customize.options') }}</h6>
35
35
  <div v-if="value.Options && value.Options.length">
@@ -56,15 +56,16 @@
56
56
  </div>
57
57
 
58
58
  <sortable
59
+ require-sortable-attribute
59
60
  :value="value.Options"
60
61
  @input="setParam({ Options: $event })"
61
62
  axis="y"
62
- require-sortable-attribute
63
+ :read-only="false"
63
64
  auto-scroll="window"
64
65
  >
65
- <div v-for="option of value.Options" class="dropdown-item d-flex justify-content-between" sortable>
66
+ <div v-for="option of value.Options" class="dropdown-item d-flex justify-content-between">
66
67
  <div>
67
- <itf-icon class="dragHandle" name="drag_vertical" />
68
+ <itf-icon sortable class="dragHandle" name="drag_vertical" />
68
69
  <span>{{ option.Name }}</span>
69
70
  </div>
70
71
  <span class="text-muted">></span>
@@ -91,12 +92,14 @@ import itfIcon from '../icon/Icon';
91
92
  import itfButton from '../button/Button';
92
93
  import Sortable from '../sortable/Sortable';
93
94
  import itfIconPopover from '../popover/IconPopover.vue';
94
- import {INLINE_TYPES} from './constants';
95
- import itfDeleteConfirmModal from "../modal/DeleteConfirmModal.vue";
96
- import PropertyItem from "./PropertyItem.vue";
95
+ import { INLINE_TYPES } from './constants';
96
+ import itfDeleteConfirmModal from '../modal/DeleteConfirmModal.vue';
97
+ import PropertyItem from './PropertyItem.vue';
98
+ import PropertiesPopupMenu from "@/components/customize/PropertiesPopupMenu.vue";
97
99
 
98
100
  export default @Component({
99
101
  components: {
102
+ PropertiesPopupMenu,
100
103
  PropertyItem,
101
104
  itfDeleteConfirmModal,
102
105
  itfButton,
@@ -80,7 +80,7 @@ import itfButton from '../button/Button';
80
80
  import itfDropdown from '../dropdown/Dropdown.vue';
81
81
  import itfLabel from '../form/Label.vue';
82
82
  import itfTextField from '../text-field/TextField.vue';
83
- import Sortable from '../sortable/Sortable';
83
+ import Sortable from '../sortable/Sortable.vue';
84
84
  import PropertyItem from './PropertyItem';
85
85
  import { INLINE_TYPES } from './constants';
86
86
 
@@ -17,7 +17,6 @@
17
17
  </template>
18
18
  <properties-edit-menu
19
19
  v-if="isEditMode"
20
- sortable-skip
21
20
  :value="field"
22
21
  :loading="loading"
23
22
  @input="onChange($event)"
@@ -26,7 +25,6 @@
26
25
  />
27
26
  <properties-popup-menu
28
27
  v-else
29
- sortable-skip
30
28
  :field="field"
31
29
  :loading="loading"
32
30
  @edit="isEditMode = true"
@@ -119,7 +117,7 @@ import itfButton from '../button/Button';
119
117
  import itfDropdown from '../dropdown/Dropdown.vue';
120
118
  import itfLabel from '../form/Label.vue';
121
119
  import itfTextField from '../text-field/TextField.vue';
122
- import Sortable from '../sortable/Sortable';
120
+ import Sortable from '../sortable/sortable-shopify';
123
121
  import PropertiesPopupMenu from './PropertiesPopupMenu.vue';
124
122
  import PropertiesEditMenu from './PropertiesEditMenu.vue';
125
123
  import PropertyInlineEdit from './PropertyInlineEdit.vue';
@@ -1,5 +1,7 @@
1
1
  import { storiesOf } from '@storybook/vue';
2
+ import itfPropertyItem from './PropertyItem.vue';
2
3
  import itfPropertiesList from './PropertiesList.vue';
4
+ import itfPropertiesEditMenu from './PropertiesEditMenu.vue';
3
5
  import itfForm from '../form/Form.vue';
4
6
  import itfButton from '../button/Button.vue';
5
7
  import itfIcon from '../icon/Icon.vue';
@@ -14,7 +16,9 @@ storiesOf('Common', module)
14
16
  itfForm,
15
17
  itfButton,
16
18
  itfLabel,
17
- itfPropertiesList
19
+ itfPropertiesList,
20
+ itfPropertiesEditMenu,
21
+ itfPropertyItem
18
22
  },
19
23
  data() {
20
24
  return {
@@ -32,7 +36,12 @@ storiesOf('Common', module)
32
36
  ],
33
37
  value: {
34
38
  test1: 'test1'
35
- }
39
+ },
40
+ field: {
41
+ Type: 'text',
42
+ Name: 'Test'
43
+ },
44
+ fieldValue: 'text'
36
45
  }
37
46
  },
38
47
  methods: {
@@ -62,6 +71,17 @@ storiesOf('Common', module)
62
71
 
63
72
  <itf-properties-list lock-fields editable :fields.sync="list" v-model="value"></itf-properties-list>
64
73
 
74
+ {{field}}
75
+ <itf-property-item
76
+ editable
77
+ :field.sync="field"
78
+ :value="fieldValue"
79
+ />
80
+
81
+ <itf-properties-edit-menu
82
+ v-model="field"
83
+ />
84
+
65
85
  </itf-app>
66
86
  </div>`,
67
87
  }));
@@ -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>
@@ -2,8 +2,8 @@
2
2
  <div class="itf-board-card shadow-sm">
3
3
  <slot name="header"></slot>
4
4
 
5
- <div class="itf-board-card-inner d-flex">
6
- <div class="flex-grow-1">
5
+ <div class="itf-board-card-inner d-flex" @click="$emit('click')">
6
+ <div class="flex-grow-1 itf-board-card-inner-content">
7
7
  <slot>{{text}}</slot>
8
8
  </div>
9
9
  <div>
@@ -13,7 +13,9 @@
13
13
  </div>
14
14
  </div>
15
15
 
16
- <slot name="footer"></slot>
16
+ <div class="itf-board-card-footer d-flex">
17
+ <slot name="footer"></slot>
18
+ </div>
17
19
  </div>
18
20
  </template>
19
21
  <script>
@@ -1,10 +1,11 @@
1
1
  :root {
2
- --itf-board-column-hover-color: rgba(0, 0, 0, .05);
2
+ --itf-board-column-hover-color: #f5f9fe;
3
3
  --itf-board-column-width: 300px;
4
4
  --itf-board-placeholder-color: #47BEFF;
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-border-color: #ccc;
8
9
  }
9
10
 
10
11
  [data-theme="dark"] {
@@ -13,10 +14,7 @@
13
14
  --itf-board-placeholder-border-color: #FFCC00;
14
15
  --itf-board-placeholder-bg-color: #383b41;
15
16
  --itf-board-card-bg-color: #313337;
16
-
17
- .itf-board {
18
- --bs-border-color: #424448;
19
- }
17
+ --itf-board-card-border-color: #424448;
20
18
  }
21
19
 
22
20
  .itf-board {
@@ -108,7 +106,6 @@
108
106
  .itf-board-column {
109
107
  position: relative;
110
108
  width: var(--itf-board-column-width);
111
- min-width: var(--itf-board-column-width);
112
109
  border-radius: 0 0 var(--bs-border-radius) var(--bs-border-radius);
113
110
 
114
111
  &__title {
@@ -152,7 +149,7 @@
152
149
  }
153
150
 
154
151
  .itf-board-titles {
155
- border-bottom: 1px solid var(--bs-border-color);
152
+ border-bottom: 1px solid var(--itf-board-card-border-color);
156
153
  }
157
154
 
158
155
  .itf-board-columns {
@@ -212,18 +209,27 @@
212
209
  .itf-board-card {
213
210
  background-color: var(--itf-board-card-bg-color);
214
211
  border-radius: var(--bs-border-radius);
215
- border: 1px solid var(--bs-border-color);
212
+ border: 1px solid var(--itf-board-card-border-color);
216
213
  margin-bottom: .75rem;
217
214
  overflow: hidden;
218
215
  user-select: none;
216
+ padding: .5rem;
219
217
 
220
218
  .itf-board-card-inner {
221
- padding: .5rem;
222
219
  font-size: .875rem;
223
220
  word-wrap: break-word;
224
221
  -webkit-line-clamp: unset;
225
- overflow-x: unset;
222
+ overflow: hidden;
226
223
  word-break: break-word;
224
+
225
+ .itf-board-card-inner-content {
226
+ padding-right: 0.2rem;
227
+ overflow-x: hidden;
228
+ }
229
+ }
230
+
231
+ .itf-board-card-footer {
232
+ overflow-x: hidden;
227
233
  }
228
234
  }
229
235
 
@@ -232,6 +238,7 @@
232
238
  flex-direction: column;
233
239
  max-height: 100%;
234
240
  flex-grow: 1;
241
+ max-width: 100%;
235
242
  }
236
243
 
237
244
  .itf-board-cards-wrapper {
@@ -243,7 +250,7 @@
243
250
  .draggable-source--is-dragging {
244
251
  position: relative !important;
245
252
  .itf-board-card {
246
- background-color: var(--bs-border-color);
253
+ background-color: var(--itf-board-card-border-color);
247
254
 
248
255
  & > div {
249
256
  opacity: 0;
@@ -3,22 +3,6 @@ import { Draggable } from './draggable'
3
3
  import DraggableEvent from './event'
4
4
 
5
5
 
6
- Vue.directive("sortable-item", {
7
- inserted(el, { value }) {
8
- el.sortableItemPayload = value?.payload;
9
- el.classList.add(draggableNode.options.draggableClass);
10
- el.getAttribute("with-handle") && el.classList.add(draggableNode.options.dragHandleClass);
11
- value?.mirror && (el.dataset.draggableMirror = JSON.stringify(value.mirror));
12
- },
13
- update(el, {value}) {
14
- el.sortableItemPayload = value?.payload;
15
- el.classList.add(draggableNode.options.draggableClass);
16
- el.getAttribute("with-handle") && el.classList.add(draggableNode.options.dragHandleClass);
17
- value?.mirror && (el.dataset.draggableMirror = JSON.stringify(value.mirror))
18
- }
19
- });
20
-
21
-
22
6
  const SORT_TAG = "sort";
23
7
  function someFunc({ source, over, overContainer, children }) {
24
8
  const isDelete = !children.length
@@ -70,7 +54,7 @@ function c(A, H, tt) {
70
54
  }
71
55
 
72
56
  export
73
- const Sortable = {
57
+ const SortableShopify = {
74
58
  name: 'Sortable',
75
59
  render: function() {
76
60
  return this._self._c(this.tag, {
@@ -284,5 +268,20 @@ const Sortable = {
284
268
  }
285
269
  };
286
270
 
287
-
288
- Vue.component("Sortable", Sortable)
271
+ export default {
272
+ Sortable: SortableShopify,
273
+ SortableItem: {
274
+ inserted(el, { value }) {
275
+ el.sortableItemPayload = value?.payload;
276
+ el.classList.add(draggableNode.options.draggableClass);
277
+ el.getAttribute("with-handle") && el.classList.add(draggableNode.options.dragHandleClass);
278
+ value?.mirror && (el.dataset.draggableMirror = JSON.stringify(value.mirror));
279
+ },
280
+ update(el, {value}) {
281
+ el.sortableItemPayload = value?.payload;
282
+ el.classList.add(draggableNode.options.draggableClass);
283
+ el.getAttribute("with-handle") && el.classList.add(draggableNode.options.dragHandleClass);
284
+ value?.mirror && (el.dataset.draggableMirror = JSON.stringify(value.mirror))
285
+ }
286
+ }
287
+ };
@@ -42,11 +42,11 @@
42
42
  }
43
43
 
44
44
  -webkit-overflow-scrolling: touch;
45
- //overflow: hidden auto;
46
- //
47
- //&.scrollable-x {
48
- // overflow-x: auto;
49
- //}
45
+ overflow: hidden auto;
46
+
47
+ &.scrollable-x {
48
+ overflow-x: auto;
49
+ }
50
50
  }
51
51
  .last-sticky-column:after {
52
52
  content: '';
@@ -93,7 +93,7 @@ class itfTable2 extends Vue {
93
93
  get groups() {
94
94
  const { groupBy, rows } = this;
95
95
  if (!groupBy) {
96
- return [];
96
+ return this.rows ? [{ name: '', rows: this.rows }] : []
97
97
  }
98
98
  const groups = rows.reduce((acc, row) => {
99
99
  const group = row[groupBy];
@@ -2,9 +2,9 @@
2
2
 
3
3
  <div class="itf-table-group table-small-row">
4
4
  <!-- Тут показується лінія при драг н дропі -->
5
- <div accept-group="tablegroups" class="preline">
5
+ <!--div accept-group="tablegroups" class="preline">
6
6
  <div class="line"></div>
7
- </div>
7
+ </div-->
8
8
 
9
9
  <div data-test="table-group-wrapper" class="table-group-wrapper flex-grow-1 w-100 d-block"
10
10
  :style="`--row-count: ${isShowTable ? rows.length : 0}`">
@@ -22,7 +22,7 @@
22
22
  @add-column="$emit('add-column', $event)"
23
23
  />
24
24
 
25
- <div group="tablegroups" class="draggable-item"
25
+ <div v-if="title" group="tablegroups" class="draggable-item"
26
26
  data-draggable-mirror="{&quot;xAxis&quot;:false}">
27
27
  <div class="table-row-template d-flex align-items-stretch"
28
28
  style="height: var(--group-title-height)">
@@ -28,7 +28,7 @@
28
28
  @drop="reorderColumns"
29
29
  v-drag-handle
30
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">
31
+ <itf-dropdown text append-to-body shadow ref="dropdown" class="w-100" disabled>
32
32
  <template #button>
33
33
  <span :title="column.text">
34
34
  <!-- <itf-icon name="type_select" :size="16" />-->