@itfin/components 1.3.68 → 1.3.69

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.68",
3
+ "version": "1.3.69",
4
4
  "author": "Vitalii Savchuk <esvit666@gmail.com>",
5
5
  "scripts": {
6
6
  "serve": "vue-cli-service serve",
@@ -0,0 +1,292 @@
1
+ <template>
2
+ <div class="itf-daterange-picker" :class="{ 'with-addon addon-start': prependIcon, 'with-addon addon-end': clearable }">
3
+ <div class="addon" v-if="prependIcon">
4
+ <slot name="addon">
5
+ <itf-icon :name="prependIcon" />
6
+ </slot>
7
+ </div>
8
+ <div class="input-group form-control py-0"
9
+ :class="{ 'focused': focused, 'is-invalid': isInvalid(), 'is-valid': isSuccess() }"
10
+ ref="group">
11
+ <i-mask-component
12
+ ref="input"
13
+ class="form-control"
14
+ :class="{ 'placeholder-visible': !displayValue || !displayValue[0] }"
15
+ @input="updateValue($event, 0)"
16
+ @focus="onFocus"
17
+ @blur="onBlur($event, 0)"
18
+ :value="displayValue[0]"
19
+ :mask="Date"
20
+ :pattern="dateFormat"
21
+ :blocks="blocks"
22
+ :disabled="disabled"
23
+ :format="format"
24
+ :parse="parse"
25
+ :unmask="false"
26
+ :lazy="!focused"
27
+ :placeholder="placeholder"
28
+ />
29
+ <span v-if="displayValue && displayValue[0]" class="input-group-text" :class="{'hidden': !focused && (value && !value[0])}">-</span>
30
+
31
+ <i-mask-component
32
+ v-if="displayValue && displayValue[0]"
33
+ ref="input2"
34
+ class="form-control"
35
+ @input="updateValue($event, 1)"
36
+ @focus="onFocus"
37
+ @blur="onBlur($event, 1)"
38
+ :value="displayValue[1]"
39
+ :mask="Date"
40
+ :pattern="dateFormat"
41
+ :blocks="blocks"
42
+ :format="format"
43
+ :parse="parse"
44
+ :unmask="false"
45
+ :lazy="!focused"
46
+ />
47
+ </div>
48
+ <div style="display: none">
49
+ <div ref="dropdown" class="itf-daterange-picker__dropdown d-flex gap-2">
50
+ <div class="p-3">
51
+ <itf-radio-group v-model="granularity">
52
+ <itf-radio v-for="(gr, n) in granularities" :key="n" :label="gr.title" :value="gr.value" />
53
+ </itf-radio-group>
54
+ </div>
55
+ <div>
56
+ <itf-date-range-picker-inline
57
+ :value="value"
58
+ only-calendar
59
+ :display-format="displayFormat"
60
+ :value-format="valueFormat"
61
+ :min-date="minDate"
62
+ :max-date="maxDate"
63
+ :min-view="minView"
64
+ @input="selectInlineDate"
65
+ ></itf-date-range-picker-inline>
66
+ </div>
67
+ <!--itf-date-range-picker-inline
68
+ :value="value"
69
+ :start-view="startView"
70
+ :only-calendar="onlyCalendar"
71
+ :display-format="displayFormat"
72
+ :value-format="valueFormat"
73
+ :min-date="minDate"
74
+ :max-date="maxDate"
75
+ @input="selectInlineDate"
76
+ ></itf-date-range-picker-inline-->
77
+ </div>
78
+ </div>
79
+
80
+ <div class="addon-end" v-if="clearable && value && value[0]">
81
+ <slot name="clear">
82
+ <itf-button
83
+ icon
84
+ small
85
+ @click="$emit('input', '')"
86
+ >
87
+ <itf-icon name="close" />
88
+ </itf-button>
89
+ </slot>
90
+ </div>
91
+ </div>
92
+ </template>
93
+ <script>
94
+ import { Vue, Component, Prop, PropSync, Inject } from 'vue-property-decorator';
95
+ import { IMask, IMaskComponent } from 'vue-imask';
96
+ import { DateTime } from 'luxon';
97
+ import tippy from 'tippy.js';
98
+ import itfIcon from '../icon/Icon';
99
+ import itfButton from '../button/Button';
100
+ import itfRadio from '../checkbox/Radio.vue';
101
+ import itfRadioGroup from '../checkbox/RadioGroup.vue';
102
+ import itfDateRangePickerInline from './DateRangePickerInline.vue';
103
+ import ITFSettings from '../../ITFSettings';
104
+
105
+ export default @Component({
106
+ name: 'itfDateRangePicker',
107
+ components: {
108
+ itfIcon,
109
+ itfButton,
110
+ itfRadio,
111
+ itfRadioGroup,
112
+ itfDateRangePickerInline,
113
+ IMaskComponent,
114
+ },
115
+ })
116
+ class itfDateGranularityPicker extends Vue {
117
+ @Inject({ default: null }) itemLabel;
118
+
119
+ @Prop({ default: () => ([]) }) value;
120
+ @Prop({ type: String, default: 'ISO' }) valueFormat;
121
+ @Prop({ type: String }) displayFormat;
122
+ // @Prop({ type: String, default: 'days', validator: (value) => ['days', 'months', 'years'].includes(value) }) startView;
123
+ @Prop({ type: Boolean, default: false }) onlyCalendar;
124
+ @Prop({ type: Boolean, default: false }) clearable;
125
+ @Prop({ type: String, default: '' }) placeholder;
126
+ @Prop({ type: String, default: '' }) prependIcon;
127
+ @Prop({ type: String, default: 'bottom-start' }) placement;
128
+ @Prop({ type: [String, Date], default: '' }) minDate;
129
+ @Prop({ type: [String, Date], default: ''}) maxDate;
130
+ @Prop(Boolean) disabled;
131
+
132
+ granularity = 'yearly';
133
+
134
+ get granularities() {
135
+ return [
136
+ { title: 'Yearly', value: 'yearly' },
137
+ { title: 'Quarterly', value: 'quarterly' },
138
+ { title: 'Monthly', value: 'monthly' },
139
+ { title: 'Weekly', value: 'weekly' },
140
+ { title: 'Custom', value: 'manual' },
141
+ ];
142
+ }
143
+
144
+ get minView() {
145
+ switch (this.granularity) {
146
+ case 'yearly': return 'years';
147
+ case 'quarterly': return 'years';
148
+ case 'monthly': return 'months';
149
+ case 'manual':
150
+ case 'weekly': return 'days';
151
+ }
152
+ }
153
+
154
+ focused = false;
155
+
156
+ tooltip = null;
157
+
158
+ blocks = {
159
+ yyyy: {
160
+ mask: IMask.MaskedRange,
161
+ from: 1970,
162
+ to: 2100,
163
+ },
164
+ MM: {
165
+ mask: IMask.MaskedRange,
166
+ from: 1,
167
+ to: 12,
168
+ },
169
+ dd: {
170
+ mask: IMask.MaskedRange,
171
+ from: 1,
172
+ to: 31,
173
+ },
174
+ };
175
+
176
+ get dateFormat() {
177
+ return this.displayFormat || ITFSettings.defaultDisplayDateFormat;
178
+ }
179
+
180
+ isInvalid() {
181
+ return this.itemLabel && this.itemLabel.isHasError();
182
+ }
183
+
184
+ isSuccess() {
185
+ return this.itemLabel && this.itemLabel.isHasSuccess();
186
+ }
187
+
188
+ mounted() {
189
+ // якщо в модалці, то контекст модалки, якщо ні, то аплікейшена
190
+ const context = this.$el.closest('.itf-append-context') || document.body;
191
+ this.tooltip = tippy(this.$refs.group, {
192
+ interactiveBorder: 30,
193
+ interactiveDebounce: 75,
194
+ animation: 'scale',
195
+ arrow: true,
196
+ content: this.$refs.dropdown,
197
+ allowHTML: true,
198
+ trigger: 'click',
199
+ interactive: true,
200
+ placement: this.placement,
201
+ appendTo: context
202
+ });
203
+ }
204
+
205
+ get valueAsLuxon() {
206
+ if (!this.value || this.value.length < 2 || !this.value[0] || !this.value[1]) {
207
+ return null;
208
+ }
209
+ if (this.valueFormat === 'ISO') {
210
+ return [
211
+ DateTime.fromISO(this.value[0]),
212
+ DateTime.fromISO(this.value[1]),
213
+ ];
214
+ }
215
+ return [
216
+ DateTime.fromFormat(this.value[0], this.valueFormat),
217
+ DateTime.fromFormat(this.value[1], this.valueFormat),
218
+ ];
219
+ }
220
+
221
+ get displayValue() {
222
+ if (!this.valueAsLuxon || this.valueAsLuxon.length < 2) {
223
+ return ['', ''];
224
+ }
225
+ return [
226
+ this.valueAsLuxon[0].toFormat(this.dateFormat),
227
+ this.valueAsLuxon[1].toFormat(this.dateFormat)
228
+ ];
229
+ }
230
+
231
+ get minDateLuxon() {
232
+ return this.minDate && this.dateLuxon(this.minDate);
233
+ }
234
+
235
+ get maxDateLuxon() {
236
+ return this.maxDate && this.dateLuxon(this.maxDate);
237
+ }
238
+
239
+ dateLuxon(date) {
240
+ return (typeof date === 'string' ? DateTime.fromISO(date) : DateTime.fromJSDate(date));
241
+ }
242
+
243
+ updateValue(value, index, emitEmpty = false) {
244
+ const val = value && DateTime.fromFormat(value, this.dateFormat);
245
+ if (!val || !val.isValid) {
246
+ if (emitEmpty) {
247
+ this.$emit('input', []);
248
+ }
249
+ return;
250
+ }
251
+ const current = [...(this.value || [])];
252
+ current[0] = current[0] || null;
253
+ current[1] = current[1] || null;
254
+ current[index] = (this.valueFormat === 'ISO') ? val.toISO() : val.toFormat(this.valueFormat);
255
+ if ((this.minDateLuxon && val < this.minDateLuxon) ||
256
+ (this.maxDateLuxon && val > this.maxDateLuxon)
257
+ ) {
258
+ return;
259
+ }
260
+ this.$emit('input', [...current, this.granularity]);
261
+ }
262
+
263
+ format(date) {
264
+ return DateTime.fromJSDate(date).toFormat(this.dateFormat);
265
+ }
266
+
267
+ parse(str) {
268
+ return DateTime.fromFormat(str, this.dateFormat).toJSDate();
269
+ }
270
+
271
+ onFocus() {
272
+ this.focused = true;
273
+ }
274
+
275
+ onBlur(e, index) {
276
+ this.focused = false;
277
+ if (this.valueAsLuxon && this.valueAsLuxon[0] && this.valueAsLuxon[1] && this.valueAsLuxon[0] > this.valueAsLuxon[1]) {
278
+ if ((this.minDateLuxon && (this.valueAsLuxon[0] < this.minDateLuxon || this.valueAsLuxon[1] < this.minDateLuxon)) ||
279
+ (this.maxDateLuxon && (this.valueAsLuxon[0] > this.maxDateLuxon || this.valueAsLuxon[1] > this.maxDateLuxon))
280
+ ) {
281
+ return;
282
+ }
283
+ this.$emit('input', [this.value[0], this.value[1], this.granularity]);
284
+ }
285
+ }
286
+
287
+ selectInlineDate(date) {
288
+ this.$emit('input', [...date, this.granularity]);
289
+ this.tooltip.hide();
290
+ }
291
+ }
292
+ </script>
@@ -44,6 +44,7 @@
44
44
  :display-format="dateFormat"
45
45
  :value-format="valueFormat"
46
46
  :min-date="minDate"
47
+ :days-list="daysList"
47
48
  @input="selectInlineDate"
48
49
  ></itf-date-picker-inline>
49
50
  </div>
@@ -79,6 +80,7 @@ class itfDatePicker extends Vue {
79
80
  @Prop({ type: [Number, String], default: 300 }) delayInput;
80
81
  @Prop({ type: String, default: 'ISO' }) valueFormat;
81
82
  @Prop({ type: String }) displayFormat;
83
+ @Prop({ type: Array }) daysList;
82
84
  @Prop({ type: String, default: 'days', validator: (value) => ['days', 'months', 'years'].includes(value) }) startView;
83
85
  @Prop({ type: Boolean, default: false }) onlyCalendar;
84
86
  @Prop({ type: String, default: '' }) placeholder;
@@ -55,6 +55,7 @@
55
55
  :value-format="valueFormat"
56
56
  :min-date="minDate"
57
57
  :max-date="maxDate"
58
+ :days-list="daysList"
58
59
  @input="selectInlineDate"
59
60
  ></itf-date-range-picker-inline>
60
61
  </div>
@@ -82,10 +83,12 @@ import itfIcon from '../icon/Icon';
82
83
  import itfButton from '../button/Button';
83
84
  import itfDateRangePickerInline from './DateRangePickerInline.vue';
84
85
  import ITFSettings from '../../ITFSettings';
86
+ import itfDatePickerInline from "@/components/datepicker/DatePickerInline.vue";
85
87
 
86
88
  export default @Component({
87
89
  name: 'itfDateRangePicker',
88
90
  components: {
91
+ itfDatePickerInline,
89
92
  itfIcon,
90
93
  itfButton,
91
94
  itfDateRangePickerInline,
@@ -98,6 +101,7 @@ class itfDateRangePicker extends Vue {
98
101
  @Prop({ default: () => ([]) }) value;
99
102
  @Prop({ type: String, default: 'ISO' }) valueFormat;
100
103
  @Prop({ type: String }) displayFormat;
104
+ @Prop({ type: Array }) daysList;
101
105
  @Prop({ type: String, default: 'days', validator: (value) => ['days', 'months', 'years'].includes(value) }) startView;
102
106
  @Prop({ type: Boolean, default: false }) onlyCalendar;
103
107
  @Prop({ type: Boolean, default: false }) clearable;
@@ -37,6 +37,7 @@ class itfDatePickerInline extends Vue {
37
37
  @Prop({ type: Object, default: () => ({}) }) customDays;
38
38
  @Prop({ type: [String, Date], default: '' }) minDate;
39
39
  @Prop({ type: [String, Date], default: '' }) maxDate;
40
+ @Prop({ type: String, default: 'days' }) minView;
40
41
  @Prop({
41
42
  type: Array,
42
43
  default: function () {
@@ -61,6 +62,7 @@ class itfDatePickerInline extends Vue {
61
62
 
62
63
  @Watch('minDate')
63
64
  @Watch('maxDate')
65
+ @Watch('minView')
64
66
  async createCalendar() {
65
67
  if (this.calendar) {
66
68
  this.destroyCalendar();
@@ -88,6 +90,8 @@ class itfDatePickerInline extends Vue {
88
90
  altFieldDateFormat: this.valueFormat,
89
91
  minDate: this.minDate,
90
92
  maxDate: this.maxDate,
93
+ view: this.minView,
94
+ minView: this.minView,
91
95
  range: true,
92
96
  dynamicRange: true,
93
97
  toggleSelected: false,
@@ -5,7 +5,7 @@
5
5
  * --------------------------------------------------------------------------
6
6
  */
7
7
 
8
- import { defineJQueryPlugin, getElementFromSelector, isRTL, isVisible, reflow } from 'bootstrap/js/src/util/index'
8
+ import { defineJQueryPlugin, getElement, isRTL, isVisible, reflow } from 'bootstrap/js/src/util/index'
9
9
  import EventHandler from 'bootstrap/js/src/dom/event-handler'
10
10
  import SelectorEngine from 'bootstrap/js/src/dom/selector-engine'
11
11
  import ScrollBarHelper from 'bootstrap/js/src/util/scrollbar'
@@ -337,7 +337,7 @@ class Modal extends BaseComponent {
337
337
  */
338
338
 
339
339
  EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {
340
- const target = getElementFromSelector(this)
340
+ const target = getElement(this)
341
341
 
342
342
  if (['A', 'AREA'].includes(this.tagName)) {
343
343
  event.preventDefault()
@@ -258,8 +258,13 @@ export default class PanelList extends Vue {
258
258
  newPanel.isCloseable = false;
259
259
  }
260
260
  let newStack = [...this.panelsStack];
261
+ if (this.panels[type].permanentExpanded && newStack.length) {
262
+ for (const panel of newStack) {
263
+ panel.isCollapsed = true;
264
+ }
265
+ }
261
266
  let isAnimation = true;
262
- if (openIndex) {
267
+ if (typeof openIndex !== 'undefined') {
263
268
  isAnimation = newStack.length === openIndex;
264
269
  newStack = newStack.slice(0, openIndex);
265
270
  }
@@ -39,6 +39,7 @@
39
39
  :striped="striped"
40
40
  :expanded-ids="expandedIds"
41
41
  :css-property="cssProperty"
42
+ :sticky-header="stickyHeader"
42
43
  :editable-property="editableProperty"
43
44
  :sorting.sync="_sorting"
44
45
  @update:expanded-ids="$emit('update:expanded-ids', $event)"
@@ -97,6 +98,7 @@ class itfTable2 extends Vue {
97
98
  @Prop({ type: Array, default: () => [] }) expandedIds;
98
99
  @Prop() currency;
99
100
  @Prop() currencies;
101
+ @Prop(Boolean) stickyHeader;
100
102
  @Prop(Boolean) addNewRows;
101
103
  @Prop(Boolean) columnSorting;
102
104
  @Prop(Boolean) columnResizing;
@@ -1,6 +1,6 @@
1
1
  <template>
2
2
 
3
- <div class="itf-table-group table-small-row">
3
+ <div class="itf-table-group table-small-row" :class="{'no-indicator': indicatorType === 'none'}">
4
4
  <!-- Тут показується лінія при драг н дропі -->
5
5
  <!--div accept-group="tablegroups" class="preline">
6
6
  <div class="line"></div>
@@ -147,6 +147,12 @@
147
147
  //margin-top: 20px;
148
148
  //margin-bottom: 20px ;
149
149
 
150
+ &.no-indicator {
151
+ .shadow-area + .table-view-header-value, .table-item-inner {
152
+ border-left: 1px solid var(--itf-table-border-color);
153
+ }
154
+ }
155
+
150
156
  .preline {
151
157
  display: flex;
152
158
  align-items: center;
@@ -348,6 +354,7 @@ class itfTableGroup extends Vue {
348
354
  @Prop() editableProperty;
349
355
  @Prop(Boolean) expandedAll;
350
356
  @Prop(Boolean) striped;
357
+ @Prop(Boolean) stickyHeader;
351
358
  @Prop() indicatorWidth;
352
359
  @Prop() cssProperty;
353
360
  @PropSync('sorting', { type: Object, default: () => ({}) }) _sorting;
@@ -388,10 +395,12 @@ class itfTableGroup extends Vue {
388
395
  }
389
396
 
390
397
  mounted() {
391
- this.sticky = new Sticky(`.${this.stickyId}`, {
392
- wrap: true,
393
- stickyClass: 'sticky',
394
- });
398
+ if (this.stickyHeader) {
399
+ this.sticky = new Sticky(`.${this.stickyId}`, {
400
+ wrap: true,
401
+ stickyClass: 'sticky',
402
+ });
403
+ }
395
404
  }
396
405
 
397
406
  selectSummary(method, index) {
@@ -4,7 +4,7 @@
4
4
  <div ref="container" class="table-row-template">
5
5
  <div accept-group="items" class="table-view-body-space" v-dropzone="{ payload: 0 }"></div>
6
6
  <div class="shadow-area"></div>
7
- <div class="table-view-header-value reserved sticky">
7
+ <div v-if="indicatorType !== 'none'" class="table-view-header-value reserved sticky">
8
8
  <itf-checkbox v-if="indicatorType !== 'none' && visibleHeader && !noSelectAll" ungrouped value="all" v-model="selectAll" ref="selectAll" />
9
9
  </div>
10
10
 
@@ -20,7 +20,7 @@
20
20
  </a>
21
21
  </div>
22
22
  </div>
23
- <div class="indicator sticky">
23
+ <div v-if="indicatorType !== 'none'" class="indicator sticky">
24
24
  <div class="fill table-view-row-count" :class="{'on-rest': !noSelectAll}">
25
25
  <span v-if="indicatorType === 'order'">{{ (n + 1) }}</span>
26
26
  <span v-else-if="indicatorType === 'property'">{{ item[idProperty] }}</span>
@@ -1,6 +1,7 @@
1
1
  :root {
2
2
  --itf-table-border-color: #e1e1e1;
3
3
  --itf-table-header-bg: #f8f8f8;
4
+ --itf-table-font-size: 1rem;
4
5
  --itf-table-selected-bg: #f0f0f0;
5
6
  --itf-table-alt-bg: #f9f9f9;
6
7
  //--itf-table-border-color: #e1e1e1;
@@ -37,6 +38,8 @@ body[data-theme="dark"] {
37
38
  --itf-table-summary-text: #82909d80;
38
39
  }
39
40
  .itf-table2 {
41
+ font-size: var(--itf-table-font-size);
42
+
40
43
  &.scrollable {
41
44
  -webkit-overflow-scrolling: touch;
42
45
  overflow: hidden scroll;
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div class="itf-money-field" :class="{'currency-arrow': !currencyDisabled, 'currency-select': currencySelect}">
2
+ <div class="itf-money-field ph-no-capture" :class="{'currency-arrow': !currencyDisabled, 'currency-select': currencySelect}">
3
3
  <div :class="{'input-group h-100': noCurrencySign}" :style="`--itf-money-field-padding-left: ${noCurrencySign ? 1 : selectedCurrencySymbol.length * 0.6 + 1}rem`">
4
4
  <span class="itf-money-field__prepend" v-if="!noCurrencySign">{{ selectedCurrencySymbol }}</span>
5
5
  <i-mask-component