@itfin/components 1.0.18 → 1.0.22

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.
Files changed (31) hide show
  1. package/package.json +1 -1
  2. package/src/assets/scss/_variables.scss +6 -5
  3. package/src/assets/scss/components/_dropdown-menu.scss +3 -5
  4. package/src/assets/scss/components/_dropdown-toggle.scss +8 -3
  5. package/src/assets/scss/components/_selected.scss +15 -0
  6. package/src/assets/scss/components/_spinner.scss +4 -3
  7. package/src/assets/scss/components/_states.scss +0 -1
  8. package/src/assets/scss/directives/loading.scss +1 -1
  9. package/src/components/button/Button.vue +7 -5
  10. package/src/components/checkbox/Checkbox.vue +114 -0
  11. package/src/components/checkbox/CheckboxGroup.vue +54 -0
  12. package/src/components/checkbox/index.stories.js +74 -0
  13. package/src/components/datepicker/DatePicker.vue +11 -9
  14. package/src/components/datepicker/DatePickerInline.vue +3 -1
  15. package/src/components/datepicker/DateRangePicker.vue +11 -9
  16. package/src/components/datepicker/MonthPicker.vue +163 -0
  17. package/src/components/datepicker/index.stories.js +5 -0
  18. package/src/components/icon/Icon.vue +1 -1
  19. package/src/components/modal/Modal.vue +6 -2
  20. package/src/components/popover/Popover.vue +1 -1
  21. package/src/components/select/Select.vue +20 -16
  22. package/src/components/select/index.stories.js +8 -1
  23. package/src/components/table/Table.vue +12 -9
  24. package/src/components/text-field/TextField.vue +10 -2
  25. package/src/components/tooltip/Tooltip.vue +39 -0
  26. package/src/components/tooltip/index.stories.js +52 -0
  27. package/src/components/tree/index.stories.js +10 -6
  28. package/src/directives/sticky.js +298 -0
  29. package/src/index.stories.js +0 -25
  30. package/src/components/select/Deselect.vue +0 -3
  31. package/src/components/select/OpenIndicator.vue +0 -3
@@ -1,5 +1,6 @@
1
1
  import { storiesOf } from '@storybook/vue';
2
2
  import itfDatePicker from './DatePicker.vue';
3
+ import itfMonthPicker from './MonthPicker.vue';
3
4
  import itfDatePickerInline from './DatePickerInline.vue';
4
5
  import itfDateRangePicker from './DateRangePicker.vue';
5
6
  import itfDateRangePickerInline from './DateRangePickerInline.vue';
@@ -10,6 +11,7 @@ storiesOf('Common', module)
10
11
  components: {
11
12
  itfApp,
12
13
  itfDatePicker,
14
+ itfMonthPicker,
13
15
  itfDateRangePicker,
14
16
  itfDatePickerInline,
15
17
  itfDateRangePickerInline
@@ -67,6 +69,9 @@ storiesOf('Common', module)
67
69
 
68
70
  <itf-date-range-picker-inline v-model="dateRange"></itf-date-range-picker-inline>
69
71
 
72
+ <h2>Month</h2>
73
+
74
+ <itf-month-picker :value="date" v-model.lazy="date"></itf-month-picker>
70
75
  </itf-app>
71
76
  </div>`,
72
77
  }));
@@ -1,6 +1,6 @@
1
1
  <template>
2
2
 
3
- <component :style="style" class="itf-icon" :is="iconComponent"></component>
3
+ <component @click="$emit('click')" :style="style" class="itf-icon" :is="iconComponent"></component>
4
4
 
5
5
  </template>
6
6
  <style lang="scss" scoped>
@@ -36,7 +36,7 @@
36
36
  }
37
37
  </style>
38
38
  <script>
39
- import { Vue, Component, Prop, Watch, PropSync, Provide } from 'vue-property-decorator';
39
+ import { Vue, Component, Prop, Watch, PropSync, Inject } from 'vue-property-decorator';
40
40
  import itfButton from '../button/Button';
41
41
 
42
42
  let globalModalIndex = 0; // base modal z-index
@@ -52,6 +52,8 @@ export default @Component({
52
52
  }
53
53
  })
54
54
  class itfModal extends Vue {
55
+ @Inject({ default: null }) globalApp;
56
+
55
57
  @PropSync('visible') value;
56
58
  @Prop({ type: String }) title;
57
59
  @Prop({ type: String, default: '', validator: (value) => ['', 'sm', 'lg', 'xl'].includes(value) }) size;
@@ -105,7 +107,9 @@ class itfModal extends Vue {
105
107
  }
106
108
  if (this.appendToBody && this.$el instanceof Node && this.$el.parentNode) {
107
109
  this.$el.parentNode.removeChild(this.$el);
108
- document.body.appendChild(this.$el);
110
+ const elContext = (this.globalApp && this.globalApp.$el) || document.body;
111
+ console.info(elContext);
112
+ elContext.appendChild(this.$el);
109
113
  }
110
114
  const { default: Modal } = await import('bootstrap/js/src/modal.js');
111
115
  this.modalEl = new Modal(this.$el);
@@ -60,7 +60,7 @@ class itfPopover extends Vue {
60
60
  @PropSync('visible') value;
61
61
  @Prop({ type: String, default: 'bottom', validator: (value) => ['bottom', 'left', 'right', 'top'].includes(value) }) placement;
62
62
  @Prop({ type: String, default: 'click', validator: (value) => ['click', 'focus', 'hover', 'manual'].includes(value) }) trigger;
63
- @Prop({ type: String }) customClass;
63
+ @Prop({ type: String, default: '' }) customClass;
64
64
 
65
65
  modalId = '';
66
66
  modalEl = null;
@@ -40,7 +40,7 @@
40
40
  :aria-label="`Deselect ${getOptionLabel(option)}`"
41
41
  @click="deselect(option)"
42
42
  >
43
- <deselect />
43
+ <itf-icon name="close" />
44
44
  </itf-button>
45
45
  </span>
46
46
  </slot>
@@ -66,22 +66,23 @@
66
66
  aria-label="Clear Selected"
67
67
  @click="clearSelection"
68
68
  >
69
- <deselect />
69
+ <itf-icon name="close" />
70
70
  </itf-button>
71
71
 
72
72
  <slot name="open-indicator" v-bind="scope.openIndicator">
73
73
  <itf-button
74
+ tabindex="-1"
74
75
  small
75
76
  icon
76
77
  v-if="!noDrop && !mutableLoading && !disabled"
77
78
  v-bind="scope.openIndicator.attributes"
78
79
  >
79
- <open-indicator />
80
+ <itf-icon name="chevron_down" />
80
81
  </itf-button>
81
82
  </slot>
82
83
 
83
84
  <slot name="spinner" v-bind="scope.spinner">
84
- <div v-show="mutableLoading" class="itf-spinner">Loading...</div>
85
+ <div v-show="mutableLoading" class="itf-spinner itf-select__loader">Loading...</div>
85
86
  </slot>
86
87
  </div>
87
88
  </div>
@@ -178,7 +179,8 @@
178
179
  }
179
180
  }
180
181
  &.vs--multiple .form-control {
181
- padding-top: 1px;
182
+ padding-top: 0.125rem;
183
+ padding-bottom: 0.125rem;
182
184
  }
183
185
  &.vs--open .form-control {
184
186
  box-shadow: 0 0 0 0.125rem $input-focus-border;
@@ -193,9 +195,7 @@
193
195
  }
194
196
  .dropdown-menu {
195
197
  background-color: $body-bg;
196
- border-left: 2px solid $input-focus-border;
197
- border-right: 2px solid $input-focus-border;
198
- border-bottom: 2px solid $input-focus-border;
198
+ border: 2px solid $input-focus-border;
199
199
  padding-left: 0.125rem;
200
200
  padding-right: 0.125rem;
201
201
  left: -2px;
@@ -204,9 +204,7 @@
204
204
 
205
205
  @media (prefers-color-scheme: notdark) {
206
206
  background-color: $dark-body-bg;
207
- border-left-color: $dark-input-focus-border;
208
- border-right-color: $dark-input-focus-border;
209
- border-bottom-color: $dark-input-focus-border;
207
+ border-color: $dark-input-focus-border;
210
208
  }
211
209
 
212
210
  .dropdown-item {
@@ -226,8 +224,7 @@
226
224
  import pointerScroll from '../../mixins/pointerScroll';
227
225
  import typeAheadPointer from '../../mixins/typeAheadPointer';
228
226
  import ajax from '../../mixins/ajax';
229
- import Deselect from './Deselect';
230
- import OpenIndicator from './OpenIndicator';
227
+ import itfIcon from '../icon/Icon';
231
228
  import itfButton from '../button/Button';
232
229
  import appendToBody from '../../directives/appendToBody';
233
230
  import sortAndStringify from '../../helpers/sortAndStringify';
@@ -237,9 +234,8 @@ import uniqueId from '../../helpers/uniqueId';
237
234
  */
238
235
  export default {
239
236
  components: {
240
- Deselect,
241
- OpenIndicator,
242
237
  itfButton,
238
+ itfIcon
243
239
  },
244
240
  directives: { appendToBody },
245
241
  mixins: [pointerScroll, typeAheadPointer, ajax],
@@ -585,6 +581,14 @@ export default {
585
581
  return clearSearchOnSelect && !multiple
586
582
  },
587
583
  },
584
+ /**
585
+ * Disable the dropdown entirely.
586
+ * @type {Boolean}
587
+ */
588
+ opened: {
589
+ type: Boolean,
590
+ default: false,
591
+ },
588
592
  /**
589
593
  * Disable the dropdown entirely.
590
594
  * @type {Boolean}
@@ -866,7 +870,7 @@ export default {
866
870
  * @return {Boolean} True if open
867
871
  */
868
872
  dropdownOpen() {
869
- return this.dropdownShouldOpen(this)
873
+ return this.opened || this.dropdownShouldOpen(this);
870
874
  },
871
875
  /**
872
876
  * Return the placeholder string if it's set
@@ -32,7 +32,8 @@ storiesOf('Common', module)
32
32
  countries: [
33
33
  {code: 'CA', country: 'Canada'},
34
34
  {code: 'US', country: 'United states'},
35
- {code: 'UA', country: 'Ukraine'}
35
+ {code: 'UA', country: 'Ukraine'},
36
+ {code: 'TEST', country: 'ASdasd sdas dasd sad sadas da ad asdsad ad d ada dsadsadsadasd sadsa das dasd asdasd asdas da '}
36
37
  ]
37
38
  }
38
39
  },
@@ -75,6 +76,12 @@ storiesOf('Common', module)
75
76
  :reduce="country => country.code"
76
77
  v-model="selected" label="country" :options="countries"></itf-select>
77
78
 
79
+ <itf-select
80
+ loading
81
+ placeholder="Country"
82
+ :reduce="country => country.code"
83
+ v-model="selected" label="country" :options="countries"></itf-select>
84
+
78
85
  </itf-label>
79
86
  </div>
80
87
  <div class="col-6">
@@ -44,14 +44,13 @@
44
44
  </div>
45
45
  </div>
46
46
  </div>
47
- <!-- <v-progress-linear v-if="loading" :height="3" class="com-table-loading" indeterminate />-->
48
47
  </div>
49
48
  <div v-show="rows && rows.length" class="itf-table__rows" ref="scrollContainer2">
50
49
  <div class="itf-table__row"
51
50
  :class="{'itf-table__summary-row': row.summary}"
52
51
  v-for="(row, r) in rows"
53
52
  :key="r"
54
- @click="$emit('row-click', { row, index: r })">
53
+ @click="!row.summary && $emit('row-click', { row, index: r })">
55
54
  <div
56
55
  class="itf-table__cell"
57
56
  :class="{'itf-table__cell--sorted': sortedColumns[k]}"
@@ -137,7 +136,10 @@ html {
137
136
 
138
137
  & > .itf-table__row {
139
138
  display: contents;
140
- cursor: var(--itf-table-row-cursor);
139
+
140
+ &:not(.itf-table__summary-row) {
141
+ cursor: var(--itf-table-row-cursor);
142
+ }
141
143
  }
142
144
  }
143
145
 
@@ -145,9 +147,13 @@ html {
145
147
  background-color: var(--itf-table-strip-color);
146
148
  }
147
149
 
150
+ &__cell.itf-table__cell--sorted {
151
+ background-color: var(--itf-table-sorted-color);
152
+ }
148
153
  &--hoverable &__rows{
149
- & > .itf-table__row {
150
- &:hover > div{
154
+ & > .itf-table__row:not(.itf-table__summary-row) {
155
+ &:hover > .itf-table__cell,
156
+ &:hover > .itf-table__cell--sorted {
151
157
  background-color: var(--itf-table-hover-color);
152
158
  }
153
159
  }
@@ -171,9 +177,6 @@ html {
171
177
  }
172
178
  }
173
179
 
174
- &__cell.itf-table__cell--sorted {
175
- background-color: var(--itf-table-sorted-color) !important;
176
- }
177
180
  &__header {
178
181
  background-color: var(--itf-table-background-color);
179
182
  grid-row: header;
@@ -422,7 +425,7 @@ class itfTable extends Vue {
422
425
  function initSyncScroll(el1, el2, stuck, unstuck) {
423
426
  function isScrolledEnd(el) {
424
427
  return el.scrollWidth === el.getBoundingClientRect().width // якщо контейнер менший ширини екрану
425
- || el.scrollLeft === el.scrollWidth - el.getBoundingClientRect().width; // якщо контейнер більший ширини екрану
428
+ || el.scrollLeft === el.scrollWidth - el.getBoundingClientRect().width; // якщо контейнер більший ширини екрану
426
429
  }
427
430
 
428
431
  function func1() {
@@ -3,7 +3,7 @@
3
3
  <div class="itf-text-field input-group with-addon addon-start">
4
4
  <div class="addon" v-if="prependIcon">
5
5
  <slot name="addon">
6
- <itf-icon :name="prependIcon" />
6
+ <itf-icon :name="prependIcon"/>
7
7
  </slot>
8
8
  </div>
9
9
 
@@ -13,7 +13,7 @@
13
13
  class="itf-text-field__input form-control"
14
14
  type="text"
15
15
  :value="value"
16
- @input="$emit('input', $event.target.value)"
16
+ @input="onInput($event.target.value)"
17
17
  />
18
18
 
19
19
  </div>
@@ -33,6 +33,7 @@
33
33
  <script>
34
34
  import { Vue, Component, Model, Inject, Prop } from 'vue-property-decorator';
35
35
  import itfIcon from '../icon/Icon';
36
+ import { debounce } from '../../helpers/debounce';
36
37
 
37
38
  export default @Component({
38
39
  name: 'itfTextField',
@@ -45,6 +46,13 @@ class itfTextField extends Vue {
45
46
  @Model('input') value;
46
47
  @Prop(String) prependIcon;
47
48
  @Prop(String) placeholder;
49
+ @Prop({ type: [Number, String], default: 0 }) delayInput;
50
+
51
+ onInput = null;
52
+
53
+ created() {
54
+ this.onInput = debounce((val) => this.$emit('input', val), Number(this.delayInput));
55
+ }
48
56
 
49
57
  isInvalid() {
50
58
  return this.itemLabel && this.itemLabel.isHasError();
@@ -0,0 +1,39 @@
1
+ <template>
2
+ <span>
3
+ <slot name="activator"></slot>
4
+ <div style="display: none"><div ref="tooltip"><slot></slot></div></div>
5
+ </span>
6
+ </template>
7
+ <script>
8
+ import { Vue, Component, Model, Inject, Prop } from 'vue-property-decorator';
9
+ import tippy from 'tippy.js';
10
+ import '../../assets/scss/directives/tooltip.scss';
11
+
12
+ export default @Component({
13
+ name: 'itfTooltip',
14
+ components: {
15
+ }
16
+ })
17
+ class itfTooltip extends Vue {
18
+ @Prop({ type: String, default: 'bottom', validator: (value) => [
19
+ 'bottom-start', 'bottom-end', 'bottom',
20
+ 'left', 'right',
21
+ 'top-start', 'top-end', 'top'
22
+ ].includes(value) }) placement;
23
+
24
+ mounted() {
25
+ if (typeof document === 'undefined') {
26
+ return;
27
+ }
28
+ this.tooltip = tippy(this.$el, {
29
+ content: this.$refs.tooltip,
30
+ allowHTML: true,
31
+ theme: 'itfin',
32
+ interactive: true,
33
+ delay: 500,
34
+ placement: this.placement,
35
+ appendTo: document.body,
36
+ });
37
+ }
38
+ }
39
+ </script>
@@ -0,0 +1,52 @@
1
+ import { storiesOf } from '@storybook/vue';
2
+ import itfApp from '../app/App.vue';
3
+ import itfButton from '../button/Button.vue';
4
+ import itfIcon from '../icon/Icon.vue';
5
+ import itfTooltip from './Tooltip.vue';
6
+ import tooltip from '../../directives/tooltip';
7
+
8
+ storiesOf('Common', module)
9
+ .add('Tooltip', () => ({
10
+ components: {
11
+ itfApp,
12
+ itfIcon,
13
+ itfTooltip,
14
+ itfButton
15
+ },
16
+ directives: {
17
+ tooltip
18
+ },
19
+ data() {
20
+ return {
21
+ tooltip: 'Test tooltip'
22
+ }
23
+ },
24
+ template: `<div>
25
+ <p>You need wrap whole application with this tag</p>
26
+
27
+ <h2>Usage</h2>
28
+
29
+ <pre>
30
+ &lt;button v-tooltip="'Test tooltip'">Test&lt;/button>
31
+ &lt;button v-tooltip.delay="'Test tooltip with delay'">Test&lt;/button>
32
+ </pre>
33
+
34
+ <h3>Example</h3>
35
+
36
+ <itf-app>
37
+
38
+ <button v-tooltip="tooltip">Tooltip test</button>
39
+
40
+ <button v-tooltip.delay="tooltip">Tooltip test with delay</button>
41
+
42
+ <itf-tooltip>
43
+ <template #activator="{ on }">
44
+ <a href="" v-on="on">Test</a>
45
+ </template>
46
+
47
+ <span>Test</span>
48
+ </itf-tooltip>
49
+
50
+ </itf-app>
51
+ </div>`,
52
+ }));
@@ -16,10 +16,10 @@ storiesOf('Tree', module)
16
16
  return {
17
17
  selected: null,
18
18
  items: [
19
- { Name: 'The Company', Id: null, Count: 69, Responsible: { FirstName: 'Anatolii', LastName: 'Maslov' } },
20
- { Name: 'Delivery', Id: 1, ParentId: null, Count: 50, Type: 'Dep' },
21
- { Name: 'Marketing', Id: 2, ParentId: null, Count: 1, Type: 'Dep' },
22
- { Name: 'Sales', Id: 3, ParentId: null, Count: 4, Type: 'Dep' },
19
+ { Name: 'CEO', Id: null, Count: 69, Responsible: { FirstName: 'Anatolii', LastName: 'Maslov' } },
20
+ { Name: 'Delivery', Id: 1, ParentId: null, Count: 50, Type: 'Dep', Responsible: { FirstName: 'Andrii', LastName: 'Olek' } },
21
+ { Name: 'Marketing', Id: 2, ParentId: null, Count: 1, Type: 'Dep', Responsible: { FirstName: 'Emil', LastName: 'Tro' } },
22
+ { Name: 'Sales', Id: 3, ParentId: null, Count: 4, Type: 'Dep', Responsible: { FirstName: 'Yurii', LastName: 'Ko' } },
23
23
  { Name: 'Salesman', Id: 4, ParentId: 3, Count: 2, Type: 'Team' },
24
24
  { Name: 'Searchers', Id: 5, ParentId: 3, Count: 2, Type: 'Team' },
25
25
  { Name: 'PMO', Id: 6, ParentId: 1, Count: 69, Type: 'Dep' },
@@ -47,8 +47,12 @@ storiesOf('Tree', module)
47
47
  <div class="col-3">
48
48
  <itf-tree-view :items="items" v-model="selected">
49
49
  <template #item="{ item }">
50
- <h6 class="mb-0">{{item.Name}}</h6>
51
- <p class="mb-0 opacity-75" v-if="item.Responsible">
50
+ <h6 class="mb-0">
51
+ <span>
52
+ {{item.Name}}
53
+ </span>
54
+ </h6>
55
+ <p v-if="item.Responsible" class="mb-0 opacity-75">
52
56
  <small>
53
57
  {{item.Responsible.FirstName}}
54
58
  {{item.Responsible.LastName}}