@itfin/components 1.2.84 → 1.2.86

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 (67) hide show
  1. package/package.json +7 -6
  2. package/src/components/customize/PropertiesEditMenu.vue +53 -0
  3. package/src/components/customize/PropertiesItemsMenu.vue +33 -0
  4. package/src/components/customize/PropertiesList.vue +179 -0
  5. package/src/components/customize/PropertiesPopupMenu.vue +46 -0
  6. package/src/components/customize/PropertyInlineEdit.vue +46 -0
  7. package/src/components/customize/index.stories.js +65 -0
  8. package/src/components/dropdown/Dropdown.vue +8 -19
  9. package/src/components/icon/components/type_checkbox.vue +2 -0
  10. package/src/components/icon/components/type_date.vue +2 -0
  11. package/src/components/icon/components/type_email.vue +2 -0
  12. package/src/components/icon/components/type_file.vue +2 -0
  13. package/src/components/icon/components/type_formula.vue +2 -0
  14. package/src/components/icon/components/type_id.vue +2 -0
  15. package/src/components/icon/components/type_multiselect.vue +2 -0
  16. package/src/components/icon/components/type_number.vue +2 -0
  17. package/src/components/icon/components/type_person.vue +2 -0
  18. package/src/components/icon/components/type_phone.vue +2 -0
  19. package/src/components/icon/components/type_relation.vue +2 -0
  20. package/src/components/icon/components/type_select.vue +2 -0
  21. package/src/components/icon/components/type_status.vue +2 -0
  22. package/src/components/icon/components/type_text.vue +2 -0
  23. package/src/components/icon/components/type_time.vue +2 -0
  24. package/src/components/icon/components/type_url.vue +2 -0
  25. package/src/components/icon/components/type_user.vue +2 -0
  26. package/src/components/icon/icons/type_checkbox.svg +1 -0
  27. package/src/components/icon/icons/type_date.svg +1 -0
  28. package/src/components/icon/icons/type_email.svg +1 -0
  29. package/src/components/icon/icons/type_file.svg +1 -0
  30. package/src/components/icon/icons/type_formula.svg +1 -0
  31. package/src/components/icon/icons/type_id.svg +1 -0
  32. package/src/components/icon/icons/type_multiselect.svg +1 -0
  33. package/src/components/icon/icons/type_number.svg +1 -0
  34. package/src/components/icon/icons/type_person.svg +1 -0
  35. package/src/components/icon/icons/type_phone.svg +1 -0
  36. package/src/components/icon/icons/type_relation.svg +1 -0
  37. package/src/components/icon/icons/type_select.svg +1 -0
  38. package/src/components/icon/icons/type_status.svg +1 -0
  39. package/src/components/icon/icons/type_text.svg +1 -0
  40. package/src/components/icon/icons/type_time.svg +1 -0
  41. package/src/components/icon/icons/type_url.svg +1 -0
  42. package/src/components/icon/icons/type_user.svg +1 -0
  43. package/src/components/icon/icons.js +295 -278
  44. package/src/components/modal/DeleteConfirmModal.vue +78 -0
  45. package/src/components/modal/ItemEditor.vue +219 -0
  46. package/src/components/modal/Modal.vue +15 -13
  47. package/src/components/modal/index.stories.js +15 -10
  48. package/src/components/popover/ConfirmPopover.vue +1 -1
  49. package/src/components/popover/DeleteConfirmPopover.vue +39 -0
  50. package/src/components/popover/IconPopover.vue +136 -0
  51. package/src/components/popover/SelectPopover.vue +127 -0
  52. package/src/components/popover/index.stories.js +26 -10
  53. package/src/components/sortable/AutoScroll.vue +142 -0
  54. package/src/components/sortable/Sortable.scss +93 -0
  55. package/src/components/sortable/Sortable.vue +399 -0
  56. package/src/components/sortable/sortable-item-list/axis.js +9 -0
  57. package/src/components/sortable/sortable-item-list/mocked-sortable-item-list.js +415 -0
  58. package/src/components/sortable/sortable-item-list/original-sortable-item-list.js +105 -0
  59. package/src/components/sortable/utils/event-outside.js +30 -0
  60. package/src/components/sortable/utils/get-relative-position.js +41 -0
  61. package/src/components/sortable/utils/sort-item-list.js +13 -0
  62. package/src/components/sortable/utils/stop-event.js +16 -0
  63. package/src/components/sortable/utils/vibrate.js +18 -0
  64. package/src/components/text-field/MoneyField.vue +103 -0
  65. package/src/components/text-field/index.stories.js +53 -0
  66. package/src/directives/tooltip.js +1 -1
  67. package/src/locales/en.js +28 -0
@@ -0,0 +1,127 @@
1
+ <template>
2
+ <itf-popover :visible.sync="value" ref="popover" :trigger="trigger" custom-class="nopadding" :placement="placement">
3
+ <template #activator="{ on }">
4
+ <slot name="activator" :on="on"></slot>
5
+ </template>
6
+
7
+ <div class="modal-body py-2 px-3 text-center itf-select-popover">
8
+ <div class="d-flex align-items-center justify-content-between">
9
+ <div class="mb-0" v-if="title" v-html="title"></div>
10
+
11
+ <itf-button v-if="removable" small secondary>
12
+ Remove
13
+ </itf-button>
14
+ </div>
15
+
16
+ <div class="d-flex py-2">
17
+ <itf-text-field
18
+ class="flex-grow-1 me-2"
19
+ v-model="search"
20
+ placeholder="Filter"
21
+ prepend-icon="search"
22
+ clearable
23
+ />
24
+
25
+ <itf-button v-tooltip="$t('random')">
26
+ <itf-icon name="shuffle" />
27
+ </itf-button>
28
+ </div>
29
+
30
+ <div class="itf-select-popover__scroll text-start">
31
+ <swatches
32
+ background-color="transparent"
33
+ :value="value"
34
+ :swatches="colors"
35
+ shapes="circles"
36
+ inline
37
+ swatch-size="24"
38
+ show-border
39
+ @input="$emit('input', $event)"
40
+ />
41
+ </div>
42
+ <slot>
43
+ </slot>
44
+ </div>
45
+ </itf-popover>
46
+ </template>
47
+ <style lang="scss">
48
+ .itf-select-popover {
49
+ width: 280px;
50
+ min-width: 180px;
51
+ max-width: calc(100vw - 24px);
52
+ height: 356px;
53
+ max-height: 70vh;
54
+ overflow: hidden;
55
+ display: flex;
56
+ flex-direction: column;
57
+
58
+ &__scroll {
59
+ overflow: hidden auto;
60
+ flex-grow: 1;
61
+ }
62
+ }
63
+ </style>
64
+ <script>
65
+ import { Vue, Component, Prop, PropSync } from 'vue-property-decorator';
66
+ import itfPopover from './Popover';
67
+ import itfIcon from '../icon/Icon';
68
+ import iconsList from '../icon/icons';
69
+ import itfButton from '../button/Button';
70
+ import itfTextField from '../text-field/TextField.vue';
71
+ import tooltip from '../../directives/tooltip';
72
+ import Swatches from 'vue-swatches';
73
+ import 'vue-swatches/dist/vue-swatches.css';
74
+
75
+ const RECENT_ITEMS_KEY = 'itfSelectPopoverRecent';
76
+
77
+ export default @Component({
78
+ name: 'itfSelectPopover',
79
+ directives: {
80
+ tooltip
81
+ },
82
+ components: {
83
+ itfIcon,
84
+ itfPopover,
85
+ itfButton,
86
+ itfTextField,
87
+ Swatches
88
+ },
89
+ })
90
+ class itfSelectPopover extends Vue {
91
+ @PropSync('visible') value;
92
+ @Prop({ type: String, default: '' }) title;
93
+ @Prop({ type: Boolean, default: '' }) removable;
94
+ @Prop({ type: String, default: 'bottom', validator: (value) => ['bottom', 'left', 'right', 'top'].includes(value) }) placement;
95
+ @Prop({ type: String, default: 'click', validator: (value) => ['click', 'focus', 'hover', 'manual'].includes(value) }) trigger;
96
+
97
+ search = '';
98
+ recentIcons = [];
99
+
100
+ colors = [
101
+ ['#FFFFFF', '#DDE6E8', '#BDC3C8', '#E84B3C', '#F39C19', '#F2C511', '#27AF60', '#3398DB', '#8E43AD']
102
+ ];
103
+
104
+ created() {
105
+ this.recentIcons = this.getRecentIcons();
106
+ }
107
+
108
+ get iconsList() {
109
+ return Object.keys(iconsList).filter((icon) => icon.includes(this.search.toLowerCase()));
110
+ }
111
+
112
+ onSelectIcon(icon) {
113
+ this.search = '';
114
+ this.$emit('input', icon);
115
+ this.$refs.popover.hide();
116
+
117
+ const icons = this.getRecentIcons();
118
+ icons.unshift(icon);
119
+ this.recentIcons = [...new Set(icons.slice(0, 14))];
120
+ localStorage.setItem(RECENT_ITEMS_KEY, JSON.stringify(this.recentIcons));
121
+ }
122
+
123
+ getRecentIcons() {
124
+ return localStorage.getItem(RECENT_ITEMS_KEY) ? JSON.parse(localStorage.getItem(RECENT_ITEMS_KEY)) : [];
125
+ }
126
+ }
127
+ </script>
@@ -1,25 +1,32 @@
1
1
  import { storiesOf } from '@storybook/vue';
2
2
  import itfPopover from './Popover.vue';
3
3
  import itfConfirmPopover from './ConfirmPopover.vue';
4
+ import itfIconPopover from './IconPopover.vue';
5
+ import itfSelectPopover from './SelectPopover.vue';
6
+ import itfDeleteConfirmPopover from './DeleteConfirmPopover.vue';
4
7
  import itfForm from '../form/Form.vue';
8
+ import itfButton from '../button/Button.vue';
9
+ import itfIcon from '../icon/Icon.vue';
5
10
  import itfLabel from '../form/Label.vue';
6
- import itfDatePicker from '../datepicker/DatePicker.vue';
7
- import itfDateRangePicker from '../datepicker/DateRangePicker.vue';
8
11
  import itfApp from '../app/App.vue';
9
12
 
10
13
  storiesOf('Common', module)
11
14
  .add('Popover', () => ({
12
15
  components: {
13
16
  itfApp,
17
+ itfIcon,
14
18
  itfForm,
19
+ itfButton,
15
20
  itfLabel,
16
21
  itfPopover,
17
- itfDatePicker,
18
- itfDateRangePicker,
19
- itfConfirmPopover
22
+ itfIconPopover,
23
+ itfSelectPopover,
24
+ itfConfirmPopover,
25
+ itfDeleteConfirmPopover
20
26
  },
21
27
  data() {
22
28
  return {
29
+ icon: 'shuffle',
23
30
  isVisible: false,
24
31
  from: '2021-01-16',
25
32
  to: null,
@@ -44,11 +51,6 @@ storiesOf('Common', module)
44
51
 
45
52
  <pre>
46
53
 
47
- &lt;itf-datepicker>&lt;/itf-datepicker>
48
-
49
- &lt;button @click="$showSuccess('Success')">Show success&lt;/button>
50
- &lt;button @click="$showError('Error')">Show error&lt;/button>
51
- &lt;button @click="$try(() => { throw new Error('Invalid function'); })">Try function with error&lt;/button>
52
54
  </pre>
53
55
 
54
56
  <h2>Example</h2>
@@ -59,6 +61,20 @@ storiesOf('Common', module)
59
61
  <itf-confirm-popover>
60
62
  <button slot="activator" class="btn btn-primary" type="button">Show modal</button>
61
63
  </itf-confirm-popover>
64
+
65
+ <itf-icon-popover title="Icon" removable v-model="icon">
66
+ <itf-button slot="activator" icon>
67
+ <itf-icon :name="icon" />
68
+ </itf-button>
69
+ </itf-icon-popover>
70
+
71
+ <itf-select-popover title="Icon" removable v-model="icon">
72
+ <itf-button slot="activator" icon>
73
+ <itf-icon :name="icon" />
74
+ </itf-button>
75
+ </itf-select-popover>
76
+
77
+ <itf-delete-confirm-popover />
62
78
  </div>
63
79
  </itf-app>
64
80
  </div>`,
@@ -0,0 +1,142 @@
1
+ <template>
2
+ <div @mousemove="onMouseMove" @touchmove="onTouchMove">
3
+ <!-- @slot Content to scroll -->
4
+ <slot />
5
+ </div>
6
+ </template>
7
+ <script>
8
+ const THRESHOLD_MIN = 40;
9
+ const THRESHOLD_MAX = 100;
10
+ const THROTTLE_INDEX = 5;
11
+
12
+ /**
13
+ * @description
14
+ * Automatically scroll window or closest parent element
15
+ * taken by selector from `parent-selector` prop
16
+ * when mouse cursor/touch is close to its borders.
17
+ */
18
+ export default {
19
+ name: 'itfAutoScroll',
20
+ props: {
21
+ /**
22
+ * Auto scroll disabled if set to true
23
+ */
24
+ disabled: {
25
+ type: Boolean,
26
+ default: false
27
+ },
28
+ /**
29
+ * Selector for parent which is scrolled. By default it is window.
30
+ * Can be selected by tag name, class name, element id.
31
+ */
32
+ parentSelector: {
33
+ type: String,
34
+ default: null
35
+ }
36
+ },
37
+ data () {
38
+ return {
39
+ parent: null
40
+ };
41
+ },
42
+ watch: {
43
+ parentSelector () {
44
+ this.resolveParentSelector();
45
+ }
46
+ },
47
+ mounted () {
48
+ this.resolveParentSelector();
49
+ },
50
+ methods: {
51
+ /**
52
+ * Scroll parent element/window accordingly to received pageX, pageY coordinates
53
+ *
54
+ * @param {number} pageX PageX coordinate
55
+ * @param {number} pageY PageY coordinate
56
+ * @param {boolean} gradually Scroll gradually. True by default
57
+ * @public
58
+ */
59
+ autoScroll (pageX, pageY, gradually = true) {
60
+ this.performAutoScroll(pageX, pageY, gradually);
61
+ },
62
+ /**
63
+ * Find parent by selector. Empty parent means `window` by default.
64
+ */
65
+ resolveParentSelector () {
66
+ this.parent = null;
67
+ if (this.parentSelector && this.parentSelector !== 'window') {
68
+ this.parent = this.$el.closest(this.parentSelector);
69
+ }
70
+ },
71
+ onMouseMove (event) {
72
+ const { pageX, pageY } = event;
73
+ this.performAutoScroll(pageX, pageY, false);
74
+ },
75
+ onTouchMove (event) {
76
+ const { pageX, pageY } = event.targetTouches[0];
77
+ this.performAutoScroll(pageX, pageY, false);
78
+ },
79
+ performAutoScroll (pageX, pageY, gradually = true) {
80
+ if (this.disabled) {
81
+ return;
82
+ }
83
+ let x;
84
+ let y;
85
+ if (this.parent) {
86
+ const rect = this.parent.getBoundingClientRect();
87
+ const scrollLeft = document.documentElement
88
+ ? document.documentElement.scrollLeft
89
+ : document.body.scrollLeft;
90
+ const scrollTop = document.documentElement
91
+ ? document.documentElement.scrollTop
92
+ : document.body.scrollTop;
93
+ x = pageX - (rect.left + scrollLeft);
94
+ y = pageY - (rect.top + scrollTop);
95
+ } else {
96
+ x = pageX - window.pageXOffset;
97
+ y = pageY - window.pageYOffset;
98
+ }
99
+ const width = this.parent ? this.parent.clientWidth : window.innerWidth;
100
+ const height = this.parent
101
+ ? this.parent.clientHeight
102
+ : window.innerHeight;
103
+ const shiftX = this.getShift(width, x, gradually);
104
+ const shiftY = this.getShift(height, y, gradually);
105
+ if (shiftX !== 0 || shiftY !== 0) {
106
+ (this.parent || window).scrollBy(shiftX, shiftY);
107
+ /**
108
+ * Autoscroll event
109
+ * @param {number} shiftX Shift by axis X
110
+ * @param {number} shiftY Shift by axis Y
111
+ */
112
+ this.$emit('autoscroll', shiftX, shiftY);
113
+ }
114
+ },
115
+ /**
116
+ * Calculate shift x/y for scrolling
117
+ * @param {number} size
118
+ * @param {number} position
119
+ * @param {boolean} gradually
120
+ * @returns {number}
121
+ */
122
+ getShift (size, position, gradually) {
123
+ if (THRESHOLD_MAX <= size) {
124
+ let threshold = size / 10;
125
+ threshold = threshold > THRESHOLD_MAX ? THRESHOLD_MAX : threshold;
126
+ threshold = threshold < THRESHOLD_MIN ? THRESHOLD_MIN : threshold;
127
+ const boundTop = threshold;
128
+ const boundBottom = size - threshold;
129
+ if (position < boundTop) {
130
+ return gradually ? -threshold / THROTTLE_INDEX : position - boundTop;
131
+ }
132
+ if (position > boundBottom) {
133
+ return gradually
134
+ ? threshold / THROTTLE_INDEX
135
+ : position - boundBottom;
136
+ }
137
+ }
138
+ return 0;
139
+ }
140
+ }
141
+ };
142
+ </script>
@@ -0,0 +1,93 @@
1
+ .itf-sortable {
2
+ .hidden {
3
+ display: none!important;
4
+ visibility: hidden!important;
5
+ }
6
+
7
+ .itf-sortable-list {
8
+ padding: 0;
9
+ margin: 0;
10
+ list-style: none;
11
+ }
12
+
13
+ .up-source-item {
14
+ opacity: 0.2;
15
+ }
16
+
17
+ .itf-sortable-list-mocked {
18
+ position: relative;
19
+ }
20
+
21
+ .itf-sortable-list-mocked,
22
+ .itf-sortable-list-mocked * {
23
+ user-select: none;
24
+ }
25
+
26
+ .up-cursor-item {
27
+ position: absolute;
28
+ z-index: var(--zindex-dropdown);
29
+ cursor: move;
30
+ user-select: none;
31
+ }
32
+
33
+ .up-cursor-item-presentation {
34
+ box-shadow: var(--pop-shadow);
35
+ }
36
+
37
+ &.up-cursor-item-white {
38
+ .up-cursor-item-presentation {
39
+ background-color: var(--bg-inverse);
40
+ }
41
+ }
42
+ }
43
+
44
+ .itf-sortable-y {
45
+ --sortable-ws: 2rem;
46
+
47
+ margin: 0 calc(var(--sortable-ws) / 2 * -1);
48
+
49
+ //@include media-breakpoint-up(md) {
50
+ // margin: 0 calc(var(--sortable-ws) * -1);
51
+ //}
52
+
53
+ .itf-sortable-drag-icon {
54
+ padding: calc(var(--sortable-ws) / 2);
55
+ color: var(--text-2);
56
+ pointer-events: all;
57
+ line-height: 0;
58
+
59
+ //@include media-breakpoint-up(md) {
60
+ // margin-right: var(--sortable-ws);
61
+ // padding: 0;
62
+ //}
63
+ }
64
+
65
+ li {
66
+ display: flex;
67
+ align-items: center;
68
+ width: 100%;
69
+ margin-bottom: 0;
70
+ padding-right: calc(var(--sortable-ws) / 2);
71
+ background: var(--bg-inverse);
72
+ border-bottom: var(--border-base);
73
+ pointer-events: none;
74
+
75
+ //@include media-breakpoint-up(md) {
76
+ // padding: 1rem var(--sortable-ws);
77
+ // pointer-events: all;
78
+ //}
79
+
80
+ &:hover {
81
+ cursor: grab;
82
+
83
+ .itf-sortable-drag-icon {
84
+ color: var(--brand-primary);
85
+ }
86
+ }
87
+ }
88
+
89
+ [sortable-skip='true'] {
90
+ cursor: default;
91
+ pointer-events: all;
92
+ }
93
+ }