@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
@@ -0,0 +1,298 @@
1
+ const namespace = 'itf-sticky';
2
+ const events = [
3
+ 'resize',
4
+ 'scroll',
5
+ 'touchstart',
6
+ 'touchmove',
7
+ 'touchend',
8
+ 'pageshow',
9
+ 'load',
10
+ ];
11
+
12
+ const batchStyle = (el, style = {}, className = {}) => {
13
+ for (let k in style) {
14
+ el.style[k] = style[k];
15
+ }
16
+ for (let k in className) {
17
+ if (className[k] && !el.classList.contains(k)) {
18
+ el.classList.add(k);
19
+ } else if (!className[k] && el.classList.contains(k)) {
20
+ el.classList.remove(k);
21
+ }
22
+ }
23
+ };
24
+
25
+ class Sticky {
26
+ constructor(el, vm) {
27
+ this.el = el;
28
+ this.vm = vm;
29
+ this.unsubscribers = [];
30
+ this.isPending = false;
31
+ this.state = {
32
+ isTopSticky: null,
33
+ isBottomSticky: null,
34
+ height: null,
35
+ width: null,
36
+ xOffset: null,
37
+ };
38
+
39
+ this.lastState = {
40
+ top: null,
41
+ bottom: null,
42
+ sticked: false,
43
+ };
44
+
45
+ const offset = this.getAttribute('sticky-offset') || {};
46
+ const side = this.getAttribute('sticky-side') || 'top';
47
+ const zIndex = this.getAttribute('sticky-z-index') || '10';
48
+ const onStick = this.getAttribute('on-stick') || null;
49
+
50
+ this.options = {
51
+ topOffset: Number(offset.top) || 0,
52
+ bottomOffset: Number(offset.bottom) || 0,
53
+ shouldTopSticky: side === 'top' || side === 'both',
54
+ shouldBottomSticky: side === 'bottom' || side === 'both',
55
+ zIndex: zIndex,
56
+ onStick: onStick,
57
+ };
58
+ }
59
+
60
+ doBind() {
61
+ if (this.unsubscribers.length > 0) {
62
+ return;
63
+ }
64
+ const { el, vm } = this;
65
+ vm.$nextTick(() => {
66
+ this.placeholderEl = document.createElement('div');
67
+ this.containerEl = this.getContainerEl();
68
+ el.parentNode.insertBefore(this.placeholderEl, el);
69
+ events.forEach(event => {
70
+ const fn = this.update.bind(this);
71
+ this.unsubscribers.push(() => window.removeEventListener(event, fn));
72
+ this.unsubscribers.push(() =>
73
+ this.containerEl.removeEventListener(event, fn),
74
+ );
75
+ window.addEventListener(event, fn, { passive: true });
76
+ this.containerEl.addEventListener(event, fn, { passive: true });
77
+ });
78
+ });
79
+ }
80
+
81
+ doUnbind() {
82
+ this.unsubscribers.forEach(fn => fn());
83
+ this.unsubscribers = [];
84
+ this.resetElement();
85
+ }
86
+
87
+ update() {
88
+ if (!this.isPending) {
89
+ requestAnimationFrame(() => {
90
+ this.isPending = false;
91
+ this.recomputeState();
92
+ this.updateElements();
93
+ });
94
+ this.isPending = true;
95
+ }
96
+ }
97
+
98
+ isTopSticky() {
99
+ if (!this.options.shouldTopSticky) return false;
100
+ const fromTop = this.state.placeholderElRect.top;
101
+ const fromBottom = this.state.containerElRect.bottom;
102
+
103
+ const topBreakpoint = this.options.topOffset;
104
+ const bottomBreakpoint = this.options.bottomOffset;
105
+
106
+ return fromTop <= topBreakpoint && fromBottom >= bottomBreakpoint;
107
+ }
108
+
109
+ isBottomSticky() {
110
+ if (!this.options.shouldBottomSticky) return false;
111
+ const fromBottom =
112
+ window.innerHeight - this.state.placeholderElRect.top - this.state.height;
113
+ const fromTop = window.innerHeight - this.state.containerElRect.top;
114
+
115
+ const topBreakpoint = this.options.topOffset;
116
+ const bottomBreakpoint = this.options.bottomOffset;
117
+
118
+ return fromBottom <= bottomBreakpoint && fromTop >= topBreakpoint;
119
+ }
120
+
121
+ recomputeState() {
122
+ this.state = Object.assign({}, this.state, {
123
+ height: this.getHeight(),
124
+ width: this.getWidth(),
125
+ xOffset: this.getXOffset(),
126
+ placeholderElRect: this.getPlaceholderElRect(),
127
+ containerElRect: this.getContainerElRect(),
128
+ });
129
+ this.state.isTopSticky = this.isTopSticky();
130
+ this.state.isBottomSticky = this.isBottomSticky();
131
+ }
132
+
133
+ fireEvents() {
134
+ if (
135
+ typeof this.options.onStick === 'function' &&
136
+ (this.lastState.top !== this.state.isTopSticky ||
137
+ this.lastState.bottom !== this.state.isBottomSticky ||
138
+ this.lastState.sticked !==
139
+ (this.state.isTopSticky || this.state.isBottomSticky))
140
+ ) {
141
+ this.lastState = {
142
+ top: this.state.isTopSticky,
143
+ bottom: this.state.isBottomSticky,
144
+ sticked: this.state.isBottomSticky || this.state.isTopSticky,
145
+ };
146
+ this.options.onStick(this.lastState);
147
+ }
148
+ }
149
+
150
+ updateElements() {
151
+ const placeholderStyle = { paddingTop: 0 };
152
+ const elStyle = {
153
+ position: 'static',
154
+ top: 'auto',
155
+ bottom: 'auto',
156
+ left: 'auto',
157
+ width: 'auto',
158
+ zIndex: this.options.zIndex,
159
+ };
160
+ const placeholderClassName = { 'vue-sticky-placeholder': true };
161
+ const elClassName = {
162
+ 'vue-sticky-el': true,
163
+ 'top-sticky': false,
164
+ 'bottom-sticky': false,
165
+ };
166
+
167
+ if (this.state.isTopSticky) {
168
+ elStyle.position = 'fixed';
169
+ elStyle.top = this.options.topOffset + 'px';
170
+ elStyle.left = this.state.xOffset + 'px';
171
+ elStyle.width = this.state.width + 'px';
172
+ const bottomLimit =
173
+ this.state.containerElRect.bottom -
174
+ this.state.height -
175
+ this.options.bottomOffset -
176
+ this.options.topOffset;
177
+ if (bottomLimit < 0) {
178
+ elStyle.top = bottomLimit + this.options.topOffset + 'px';
179
+ }
180
+ placeholderStyle.paddingTop = this.state.height + 'px';
181
+ elClassName['top-sticky'] = true;
182
+ } else if (this.state.isBottomSticky) {
183
+ elStyle.position = 'fixed';
184
+ elStyle.bottom = this.options.bottomOffset + 'px';
185
+ elStyle.left = this.state.xOffset + 'px';
186
+ elStyle.width = this.state.width + 'px';
187
+ const topLimit =
188
+ window.innerHeight -
189
+ this.state.containerElRect.top -
190
+ this.state.height -
191
+ this.options.bottomOffset -
192
+ this.options.topOffset;
193
+ if (topLimit < 0) {
194
+ elStyle.bottom = topLimit + this.options.bottomOffset + 'px';
195
+ }
196
+ placeholderStyle.paddingTop = this.state.height + 'px';
197
+ elClassName['bottom-sticky'] = true;
198
+ } else {
199
+ placeholderStyle.paddingTop = 0;
200
+ }
201
+
202
+ batchStyle(this.el, elStyle, elClassName);
203
+ batchStyle(this.placeholderEl, placeholderStyle, placeholderClassName);
204
+
205
+ this.fireEvents();
206
+ }
207
+
208
+ resetElement() {
209
+ ['position', 'top', 'bottom', 'left', 'width', 'zIndex'].forEach(attr => {
210
+ this.el.style.removeProperty(attr);
211
+ });
212
+ this.el.classList.remove('bottom-sticky', 'top-sticky');
213
+ const { parentNode } = this.placeholderEl;
214
+ if (parentNode) {
215
+ parentNode.removeChild(this.placeholderEl);
216
+ }
217
+ }
218
+
219
+ getContainerEl() {
220
+ let node = this.el.parentNode;
221
+ while (
222
+ node &&
223
+ node.tagName !== 'HTML' &&
224
+ node.tagName !== 'BODY' &&
225
+ node.nodeType === 1
226
+ ) {
227
+ if (node.hasAttribute('sticky-container')) {
228
+ return node;
229
+ }
230
+ node = node.parentNode;
231
+ }
232
+ return this.el.parentNode;
233
+ }
234
+
235
+ getXOffset() {
236
+ return this.placeholderEl.getBoundingClientRect().left;
237
+ }
238
+
239
+ getWidth() {
240
+ return this.placeholderEl.getBoundingClientRect().width;
241
+ }
242
+
243
+ getHeight() {
244
+ return this.el.getBoundingClientRect().height;
245
+ }
246
+
247
+ getPlaceholderElRect() {
248
+ return this.placeholderEl.getBoundingClientRect();
249
+ }
250
+
251
+ getContainerElRect() {
252
+ return this.containerEl.getBoundingClientRect();
253
+ }
254
+
255
+ getAttribute(name) {
256
+ const expr = this.el.getAttribute(name);
257
+ let result = undefined;
258
+ if (expr) {
259
+ if (this.vm[expr]) {
260
+ result = this.vm[expr];
261
+ } else {
262
+ try {
263
+ result = eval(`(${expr})`);
264
+ } catch (error) {
265
+ result = expr;
266
+ }
267
+ }
268
+ }
269
+ return result;
270
+ }
271
+ }
272
+
273
+ export default {
274
+ inserted(el, bind, vnode) {
275
+ if (typeof bind.value === 'undefined' || bind.value) {
276
+ el[namespace] = new Sticky(el, vnode.context);
277
+ el[namespace].doBind();
278
+ }
279
+ },
280
+ unbind(el, bind, vnode) {
281
+ if (el[namespace]) {
282
+ el[namespace].doUnbind();
283
+ el[namespace] = undefined;
284
+ }
285
+ },
286
+ componentUpdated(el, bind, vnode) {
287
+ if (typeof bind.value === 'undefined' || bind.value) {
288
+ if (!el[namespace]) {
289
+ el[namespace] = new Sticky(el, vnode.context);
290
+ }
291
+ el[namespace].doBind();
292
+ } else {
293
+ if (el[namespace]) {
294
+ el[namespace].doUnbind();
295
+ }
296
+ }
297
+ },
298
+ };
@@ -63,31 +63,6 @@ storiesOf('Common', module)
63
63
  </itf-app>
64
64
  </div>`,
65
65
  }))
66
- .add('Tooltip', () => ({
67
- directives: {
68
- tooltip,
69
- },
70
- components: { itfApp },
71
- data() {
72
- return { date: '2021-01-16', tooltip: 'This button run payroll calculation <br/><a href="/" target="_blank">Read more</a>' }
73
- },
74
- template: `<div>
75
- <h2>Usage</h2>
76
-
77
- <pre>
78
-
79
- &lt;button v-tooltip="'Test tooltip'">Test&lt;/button>
80
- &lt;button v-tooltip.delay="'Test tooltip with delay'">Test&lt;/button>
81
- </pre>
82
-
83
- <h2>Example</h2>
84
-
85
- <button v-tooltip="tooltip">Tooltip test</button>
86
-
87
- <button v-tooltip.delay="tooltip">Tooltip test with delay</button>
88
-
89
- </div>`,
90
- }))
91
66
  .add('Inline loader', () => ({
92
67
  directives: {
93
68
  loading,
@@ -1,3 +0,0 @@
1
- <template>
2
- <svg height="21" viewBox="0 0 21 21" width="21" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"><path d="m7.5 7.5 6 6"/><path d="m13.5 7.5-6 6"/></g></svg>
3
- </template>
@@ -1,3 +0,0 @@
1
- <template>
2
- <svg height="21" viewBox="0 0 21 21" width="21" xmlns="http://www.w3.org/2000/svg"><path d="m8.5.5-4 4-4-4" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" transform="translate(6 8)"/></svg>
3
- </template>