@itfin/components 2.0.1 → 2.0.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.
@@ -0,0 +1,3 @@
1
+ <svg style="transform: rotate(-90deg);" xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" viewBox="-1 -1 19 19">
2
+ <path d="M3.5 3.5c-.614-.884-.074-1.962.858-2.5L8 7.226 11.642 1c.932.538 1.472 1.616.858 2.5L8.81 8.61l1.556 2.661a2.5 2.5 0 1 1-.794.637L8 9.73l-1.572 2.177a2.5 2.5 0 1 1-.794-.637L7.19 8.61zm2.5 10a1.5 1.5 0 1 0-3 0 1.5 1.5 0 0 0 3 0m7 0a1.5 1.5 0 1 0-3 0 1.5 1.5 0 0 0 3 0"/>
3
+ </svg>
@@ -27,7 +27,6 @@
27
27
  @click="$emit('cancel')"
28
28
  >
29
29
  <span v-html="$t('components.popover.noKeepIt')"></span>
30
- <kbd>Esc</kbd>
31
30
  </button>
32
31
  <button
33
32
  type="button"
@@ -36,7 +35,6 @@
36
35
  @click="onConfirm"
37
36
  >
38
37
  <span v-html="$t('components.popover.yesDelete')"></span>
39
- <kbd>↵</kbd>
40
38
  </button>
41
39
  </div>
42
40
  </div>
@@ -43,15 +43,13 @@
43
43
 
44
44
  <itf-button
45
45
  v-if="!readonly"
46
- squircle
47
46
  data-test="item-editor-cancel"
48
47
  :disabled="loading"
49
- secondary
48
+ default
50
49
  class="me-2"
51
50
  @click="$emit('input', false)"
52
51
  >
53
52
  <span class="me-1">{{ $t('components.modal.cancel') }}</span>
54
- <kbd>Esc</kbd>
55
53
  </itf-button>
56
54
 
57
55
  <slot
@@ -60,14 +58,12 @@
60
58
  >
61
59
  <itf-button
62
60
  primary
63
- squircle
64
61
  data-test="item-editor-save"
65
62
  :disabled="loading"
66
63
  :loading="loading"
67
64
  @click="submitSaveItem()"
68
65
  >
69
66
  <span class="me-1">{{ saveBtnCaption }}</span>
70
- <kbd>Shift + ↵</kbd>
71
67
  </itf-button>
72
68
  </slot>
73
69
  </slot>
@@ -14,7 +14,7 @@
14
14
  <slot name="header">
15
15
  <div>
16
16
  <slot name="title">
17
- <div class="b-panel__title ps-1 fw-bold h5" v-text="title"></div>
17
+ <div class="b-panel__title ps-1 fw-bold h2" v-text="title"></div>
18
18
  </slot>
19
19
  </div>
20
20
  <div class="d-flex gap-1">
@@ -5,7 +5,7 @@
5
5
  </template>
6
6
  <style scoped lang="scss">
7
7
  .notice {
8
- position: absolute;
8
+ position: fixed;
9
9
  bottom: 10px;
10
10
  left: 50%;
11
11
  max-width: 740px;
@@ -17,10 +17,10 @@
17
17
  <div class="shadow-area"></div>
18
18
  <div class="header-wrapper" :class="{'header-additional-column': showAddColumn}" @click.prevent="toggleGroup">
19
19
  <a class="header-content position-sticky d-flex align-items-center">
20
- <span class="collapse-arrow">
20
+ <itf-button squircle icon small secondary class="collapse-arrow">
21
21
  <itf-icon :name="isShowTable ? 'chevron_down' : 'chevron_right'"/>
22
- </span>
23
- <span class="d-flex align-items-center line-overflow group-header-value"
22
+ </itf-button>
23
+ <span class="d-flex align-items-center line-overflow group-header-value text-primary"
24
24
  data-test="group-value-group-label-value">
25
25
  <slot name="group-title" :rows="rows" :title="title">{{ title }}</slot>
26
26
  </span>
@@ -230,7 +230,7 @@
230
230
  border-radius: 0;
231
231
  }
232
232
  &:hover {
233
- background: var(--itf-table-hover-bg);
233
+ //background: var(--itf-table-hover-bg); // видно, що група не на всю ширину коли є нижній скролінг
234
234
  }
235
235
  }
236
236
 
@@ -239,7 +239,7 @@
239
239
  }
240
240
  .header-content:not(.draggable-mirror *) {
241
241
  left: var(--shadow-area-width);
242
- padding-left: 0.75rem;
242
+ //padding-left: 0.75rem;
243
243
  padding-right: 0.75rem;
244
244
  gap: 1rem;
245
245
  align-items: center;
@@ -284,9 +284,20 @@
284
284
  }
285
285
 
286
286
  .sticky-group {
287
+ top: -10px;
287
288
  position: sticky;
288
- top: 0;
289
289
  z-index: 10;
290
+
291
+ & > .draggable-item {
292
+ margin-bottom: 8px;
293
+ }
294
+ .collapse-arrow {
295
+ padding: 0;
296
+
297
+ &:after {
298
+ display: none;
299
+ }
300
+ }
290
301
  }
291
302
  .table-summary {
292
303
  .shadow-area {
@@ -143,43 +143,6 @@
143
143
  </div>
144
144
  </template>
145
145
  <div class="table-view-item-value extra flex-grow-1"></div>
146
- <itf-dropdown v-if="showAddColumn && visibleHeader" ref="newDd" text append-to-context shadow autoclose="outside" class="table-header-add-column table-view-item-actions" data-test="table-header-add-column">
147
- <template #button>
148
- <itf-button icon small><span class="nom-gear"></span></itf-button>
149
- </template>
150
-
151
- <itf-sortable :value="sortedColumns" @input="onSortColumns">
152
- <template v-for="(column, k) in sortedColumns">
153
- <div :key="`column${k}`" class="d-flex align-items-center justify-content-between" :class="{'px-2 py-1': column.visible !== false}">
154
- <template v-if="column.visible !== false">
155
- <div class="d-flex justify-content-between flex-grow-1">
156
- <div>
157
- <span class="nom-grip-vertical"></span>
158
- <span v-if="column.icon" :class="column.icon"></span>
159
- {{getTitle(column.title)}}
160
- </div>
161
- <span v-if="column.pinned" class="nom-pin-fill"></span>
162
- </div>
163
- <a sortable-skip href="" class="text-decoration-none" @click.prevent="hideColumn(k)">
164
- <span class="nom-trash"></span>
165
- </a>
166
- </template>
167
- </div>
168
- </template>
169
- </itf-sortable>
170
-
171
- <div v-if="invisibleColumns.length">
172
- <div class="dropdown-header">{{$t('components.table.addColumn')}}</div>
173
- <template v-for="(column, k) in invisibleColumns">
174
- <a href="" @click.prevent="addColumn(column)" :key="`inv-column${k}`" class="dropdown-item d-flex align-items-center justify-content-between px-2 py-1">
175
- <div>
176
- <span class="nom-plus"></span>
177
- {{getTitle(column.title)}}
178
- </div>
179
- </a>
180
- </template>
181
- </div>
182
- </itf-dropdown>
183
146
 
184
147
  <div class="boundary top"></div>
185
148
  <div class="boundary right"></div>
@@ -57,18 +57,18 @@
57
57
  <slot :name="`column.${column.property}`" :toggle="() => $emit('toggle', item)" :level="level" :editable="column.editable && editable" :item="item" :column="column" :update="(val) => updateValue(item, val, n, column)" :value="getValue(item, column)">
58
58
  <template v-if="column.editable && editable && (!editableProperty || item[editableProperty])">
59
59
  <slot :name="`edit.${column.type}`" :level="level" :toggle="() => $emit('toggle', item)" :update="(val) => updateValue(item, val, n, column)" :value="getValue(item, column)" :item="item" :column="column">
60
- <itf-text-field class="w-100" v-if="column.type === 'text'" :value="getValue(item, column)" @input="updateValue(item, $event, n, column)" />
61
- <itf-text-field class="w-100" v-if="column.type === 'number'" type="number" :value="getValue(item, column)" @input="updateValue(item, $event, n, column)" />
60
+ <itf-text-field class="w-100 h-100" v-if="column.type === 'text'" :value="getValue(item, column)" @input="updateValue(item, $event, n, column)" />
61
+ <itf-text-field class="w-100 h-100" v-if="column.type === 'number'" type="number" :value="getValue(item, column)" @input="updateValue(item, $event, n, column)" />
62
62
  <itf-hours-field
63
- class="w-100"
63
+ class="w-100 h-100"
64
64
  placeholder="00h 00m"
65
65
  v-else-if="column.type === 'time'"
66
66
  :hours="getValue(item, column)"
67
67
  @update:hours="updateValue(item, $event, n, column)"
68
68
  />
69
- <itf-textarea class="w-100" :rows="1" autogrow v-else-if="column.type === 'textarea'" :value="getValue(item, column)" @input="updateValue(item, $event, n, column)" />
70
- <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)" />
71
- <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
+ <itf-textarea class="w-100 h-100" :rows="1" autogrow v-else-if="column.type === 'textarea'" :value="getValue(item, column)" @input="updateValue(item, $event, n, column)" />
70
+ <itf-money-field class="w-100 h-100" currency-disabled :currency="currency" :currencies="currencies" v-else-if="column.type === 'money'" :value="getValue(item, column)" @input="updateValue(item, $event, n, column)" />
71
+ <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>
72
72
  </slot>
73
73
  </template>
74
74
  <div v-else class="h-100 align-items-center d-flex w-100">
@@ -1,7 +1,7 @@
1
1
  :root {
2
2
  --itf-primary: #1A4A97;
3
3
  --itf-table-header-font-size: 12px;
4
- --itf-table-content-font-size: 14px;
4
+ --itf-table-content-font-size: 16px;
5
5
  --itf-table-selected-bg: #f9fafc;
6
6
  --itf-table-active-bg: #1A4A971A;
7
7
  --itf-table-alt-bg: #F9FAFB;
@@ -48,11 +48,20 @@ body[data-theme="dark"] {
48
48
  font-size: var(--itf-table-content-font-size, var(--itf-table-font-size));
49
49
  position: relative;
50
50
 
51
+ .itf-cell-center {
52
+ width: 100%;
53
+ height: 100%;
54
+ display: flex;
55
+ align-items: center;
56
+ }
51
57
  .scrollable {
52
58
  -webkit-overflow-scrolling: touch;
53
59
  overflow: hidden scroll;
54
60
  height: 100%;
55
61
  }
62
+ .scroller {
63
+ margin-bottom: .5rem;
64
+ }
56
65
  .scrollable-x {
57
66
  overflow-x: scroll;
58
67
  padding-right: 4px;
@@ -194,10 +203,10 @@ body[data-theme="dark"] {
194
203
  content: "";
195
204
  position: absolute;
196
205
  display: block;
197
- height: 20px;
206
+ height: 12px;
198
207
  left: 0;
199
208
  right: 0;
200
- top: -20px;
209
+ top: -12px;
201
210
  z-index: 4;
202
211
  background: var(--itf-table-bg);
203
212
  }
@@ -398,13 +407,13 @@ body[data-theme="dark"] {
398
407
  }
399
408
  }
400
409
 
401
- &:hover, &.permanent-editable-border {
402
- .table-view-item-value.editable {
403
- .form-control {
404
- border: 1px solid var(--itf-table-input-border-color);
405
- }
406
- }
407
- }
410
+ //&:hover, &.permanent-editable-border {
411
+ // .table-view-item-value.editable {
412
+ // .form-control {
413
+ // border: 1px solid var(--itf-table-input-border-color);
414
+ // }
415
+ // }
416
+ //}
408
417
  .table-view-item-value-content {
409
418
  position: relative;
410
419
  z-index: 2;
@@ -427,16 +436,16 @@ body[data-theme="dark"] {
427
436
  &.editable {
428
437
  padding: 2px;
429
438
 
430
- .form-control {
431
- border-radius: 0;
432
- border: 1px solid transparent;
433
- background-color: transparent;
434
- box-shadow: none;
435
-
436
- &:focus {
437
- border-color: var(--itf-table-input-focus-border-color);
438
- }
439
- }
439
+ //.form-control {
440
+ // border-radius: 0;
441
+ // border: 1px solid transparent;
442
+ // background-color: transparent;
443
+ // box-shadow: none;
444
+ //
445
+ // &:focus {
446
+ // border-color: var(--itf-table-input-focus-border-color);
447
+ // }
448
+ //}
440
449
  }
441
450
 
442
451
  &.highlight-drop-column {
@@ -1,26 +1,24 @@
1
1
  <template>
2
2
  <div class="itf-money-field ph-no-capture" :class="{'currency-arrow': !currencyDisabled, 'currency-select': currencySelect}">
3
- <div class="h-100" :class="{'input-group h-100': noCurrencySign}" :style="`--itf-money-field-padding-left: ${noCurrencySign ? 1 : selectedCurrencySymbol.length * 0.6 + 1}rem`">
4
- <span class="itf-money-field__prepend" v-if="!noCurrencySign">{{ selectedCurrencySymbol }}</span>
3
+ <div class="input-group h-100" :style="`--itf-money-field-padding-left: ${noCurrencySign ? 1 : selectedCurrencySymbol.length * 0.6 + 1}rem`">
4
+ <span class="input-group-text pe-1" v-if="!noCurrencySign">{{ selectedCurrencySymbol }}</span>
5
5
  <i-mask-component
6
6
  ref="input"
7
7
  v-bind="mask"
8
- class="form-control h-100"
8
+ class="form-control"
9
9
  :class="{ 'is-invalid': isInvalid(), 'is-valid': isSuccess() }"
10
10
  @input="setValue"
11
11
  :value="maskedValue"
12
12
  :unmask="false"
13
13
  :disabled="disabled"
14
14
  />
15
- </div>
16
-
17
- <div v-if="currencySelect" class="itf-money-field__currency">
18
- <span>{{ selectedCurrencyCode }}<itf-icon v-if="!currencyDisabled && currenciesList.length > 1" name="chevron_down" /></span>
19
- <select v-if="!disabled && !currencyDisabled" :value="currencyId" @input="onCurrencyChanged">
15
+ <span v-if="currencySelect" class="input-group-text ps-1">{{ selectedCurrencyCode }}<itf-icon v-if="!currencyDisabled && currenciesList.length > 1" name="chevron_down" /></span>
16
+ <select v-if="currencySelect && !disabled && !currencyDisabled" :value="currencyId" @input="onCurrencyChanged">
20
17
  <option v-for="currency in currenciesList" :key="currency.Id" :value="currency.Id" :selected="currencyId === currency.Id">
21
18
  {{ currency.Symbol }}, {{ currency.Code }} - {{ currency.Title }}
22
19
  </option>
23
20
  </select>
21
+ <slot name="postfix"></slot>
24
22
  </div>
25
23
  </div>
26
24
  </template>
@@ -28,50 +26,9 @@
28
26
  .itf-money-field {
29
27
  position: relative;
30
28
 
31
- input {
32
- padding-left: var(--itf-money-field-padding-left, 1.5rem);
33
-
34
- &.is-invalid, &.is-valid {
35
- padding-right: 4rem;
36
- }
37
- }
38
- &.currency-select {
39
- input {
40
- padding-right: 3rem;
41
- }
42
- &.currency-arrow {
43
- input {
44
- padding-right: 4.5rem;
45
- }
46
- }
47
- }
48
-
49
- &__prepend {
50
- position: absolute;
51
- left: .75rem;
52
- top: .5rem;
53
- bottom: .5rem;
54
- display: flex;
55
- align-items: center;
56
- }
57
- &__currency {
58
- position: absolute;
59
- right: .75rem;
60
- top: 0;
61
- bottom: 0;
62
- display: flex;
63
- align-items: center;
64
- .is-invalid &, .is-valid & {
65
- right: 1.75rem;
66
- }
67
-
68
- select {
69
- position: absolute;
70
- height: 100%;
71
- right: 0;
72
- opacity: 0;
73
- left: 0;
74
- }
29
+ .form-control {
30
+ padding-left: 0;
31
+ padding-right: 0;
75
32
  }
76
33
  }
77
34
  </style>
@@ -1,17 +1,16 @@
1
1
  <template>
2
2
 
3
- <div v-loading="loading" class="flex-grow-1 w-100 d-flex flex-column">
4
- {{filter}}
3
+ <div v-loading="loading || loadingData" class="flex-grow-1 w-100 d-flex flex-column">
5
4
  <itf-filter-panel
6
5
  search-placeholder="Search by text"
7
6
  search
8
7
  class="py-2 px-3"
9
- :static-filters="filters"
8
+ :endpoint="filtersEndpoint"
10
9
  v-model="filter"
11
- @input="$emit('load')"
10
+ @input="loadData"
12
11
  >
13
12
  <template #after-filter-btn>
14
- <itf-dropdown v-if="$refs.table" shadow :button-options="{ default: true, icon: true }" autoclose="outside">
13
+ <itf-dropdown v-if="$refs.table && schema" shadow :button-options="{ default: true, icon: true }" autoclose="outside">
15
14
  <template #button>
16
15
  <itf-icon new name="table-view" />
17
16
  </template>
@@ -21,7 +20,7 @@
21
20
  <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
21
  <div class="d-flex align-items-center gap-1">
23
22
  <itf-icon v-if="property.icon" :size="24" new :name="property.icon" />
24
- {{property.title.en_US}}
23
+ {{getTitle(property.title)}}
25
24
  </div>
26
25
 
27
26
  <itf-icon v-if="$refs.table.getColumnVisibility(property.property)" new :size="24" name="eye-open" />
@@ -84,9 +83,9 @@ import loading from '../../directives/loading';
84
83
  import itfTable from '../table/Table2.vue';
85
84
  import itfFilterPanel from '../filter/FilterPanel.vue';
86
85
  import itfPagination from '../pagination/Pagination2.vue';
87
- import itfTableBody from "@/components/table/TableBody.vue";
88
- import itfIcon from "@/components/icon/Icon.vue";
89
- import itfDropdown from "@/components/dropdown/Dropdown.vue";
86
+ import itfTableBody from "../table/TableBody.vue";
87
+ import itfIcon from "../icon/Icon.vue";
88
+ import itfDropdown from "../dropdown/Dropdown.vue";
90
89
 
91
90
  export default @Component({
92
91
  name: 'itfView',
@@ -103,14 +102,50 @@ export default @Component({
103
102
  })
104
103
  class itfView extends Vue {
105
104
  @Prop({ type: Boolean }) loading;
106
- @Prop({ type: Array, required: true }) items;
107
105
  @Prop({ type: Array }) filters;
108
106
  @Prop({ type: Object, required: true }) schema;
109
107
  @Prop({ default: 20 }) size;
110
108
  @Prop({ default: 100 }) total;
111
109
  @Prop({ default: 1 }) page;
110
+ @Prop(String) sorting;
111
+ @Prop(String) endpoint;
112
+ @Prop(String) filtersEndpoint;
113
+ @Prop(String) itemsKey;
112
114
 
115
+ items = [];
113
116
  filter = {};
117
+ loadingData = false;
118
+
119
+ mounted() {
120
+ }
121
+
122
+ async loadData() {
123
+ if (!this.endpoint) {
124
+ return;
125
+ }
126
+ this.$emit('load', this.filter);
127
+ this.loadingData = true;
128
+ await this.$try(async () => {
129
+ const res = await this.$axios.$get(this.endpoint, {
130
+ params: {
131
+ ...this.filter,
132
+ page: this.page,
133
+ size: this.size,
134
+ sorting: this.sorting
135
+ }
136
+ });
137
+ this.items = res[this.itemsKey];
138
+ });
139
+ this.loadingData = false;
140
+ this.$emit('loaded', this.filter);
141
+ }
142
+
143
+ getTitle(title) {
144
+ if (typeof title === 'string') {
145
+ return title;
146
+ }
147
+ return title[this.locale] || title['en_US'];
148
+ }
114
149
 
115
150
  get countPages() {
116
151
  return Math.ceil(this.total / this.size);