@itfin/components 1.3.34 → 1.3.35
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 +2 -1
- package/src/ITFSettings.js +8 -0
- package/src/assets/fonts/bootstrap-icons.woff +0 -0
- package/src/assets/fonts/bootstrap-icons.woff2 +0 -0
- package/src/assets/scss/icons.scss +2085 -0
- package/src/assets/scss/main.scss +1 -0
- package/src/components/avatar/index.stories.js +0 -1
- package/src/components/button/1.html +30 -0
- package/src/components/button/NativeButton.js +116 -0
- package/src/components/button/index.stories.js +10 -6
- package/src/components/checkbox/Checkbox.vue +5 -1
- package/src/components/dropdown/Dropdown.vue +5 -4
- package/src/components/dropdown/DropdownMenu.vue +7 -0
- package/src/components/sortable/sortable-shopify.js +1 -1
- package/src/components/table/Table2.vue +108 -33
- package/src/components/table/TableBody.vue +58 -36
- package/src/components/table/TableGroup.vue +166 -114
- package/src/components/table/TableHeader.vue +153 -36
- package/src/components/table/index.stories.js +152 -4
- package/src/components/table/sticky.js +439 -0
|
@@ -0,0 +1,439 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sticky.js
|
|
3
|
+
* Library for sticky elements written in vanilla javascript. With this library you can easily set sticky elements on your website. It's also responsive.
|
|
4
|
+
*
|
|
5
|
+
* @version 1.3.0
|
|
6
|
+
* @author Rafal Galus <biuro@rafalgalus.pl>
|
|
7
|
+
* @website https://rgalus.github.io/sticky-js/
|
|
8
|
+
* @repo https://github.com/rgalus/sticky-js
|
|
9
|
+
* @license https://github.com/rgalus/sticky-js/blob/master/LICENSE
|
|
10
|
+
*/
|
|
11
|
+
export default
|
|
12
|
+
class Sticky {
|
|
13
|
+
/**
|
|
14
|
+
* Sticky instance constructor
|
|
15
|
+
* @constructor
|
|
16
|
+
* @param {string} selector - Selector which we can find elements
|
|
17
|
+
* @param {string} options - Global options for sticky elements (could be overwritten by data-{option}="" attributes)
|
|
18
|
+
*/
|
|
19
|
+
constructor(selector = '', options = {}) {
|
|
20
|
+
this.selector = selector;
|
|
21
|
+
this.elements = [];
|
|
22
|
+
|
|
23
|
+
this.version = '1.3.0';
|
|
24
|
+
|
|
25
|
+
this.vp = this.getViewportSize();
|
|
26
|
+
this.body = document.querySelector('body');
|
|
27
|
+
|
|
28
|
+
this.options = {
|
|
29
|
+
wrap: options.wrap || false,
|
|
30
|
+
wrapWith: options.wrapWith || '<span></span>',
|
|
31
|
+
marginTop: options.marginTop || 0,
|
|
32
|
+
marginBottom: options.marginBottom || 0,
|
|
33
|
+
stickyFor: options.stickyFor || 0,
|
|
34
|
+
stickyClass: options.stickyClass || null,
|
|
35
|
+
stickyContainer: options.stickyContainer || 'body',
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
this.updateScrollTopPosition = this.updateScrollTopPosition.bind(this);
|
|
39
|
+
|
|
40
|
+
this.updateScrollTopPosition();
|
|
41
|
+
window.addEventListener('load', this.updateScrollTopPosition);
|
|
42
|
+
window.addEventListener('scroll', this.updateScrollTopPosition);
|
|
43
|
+
|
|
44
|
+
this.run();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Function that waits for page to be fully loaded and then renders & activates every sticky element found with specified selector
|
|
50
|
+
* @function
|
|
51
|
+
*/
|
|
52
|
+
run() {
|
|
53
|
+
// wait for page to be fully loaded
|
|
54
|
+
const pageLoaded = setInterval(() => {
|
|
55
|
+
if (document.readyState === 'complete') {
|
|
56
|
+
clearInterval(pageLoaded);
|
|
57
|
+
|
|
58
|
+
const elements = document.querySelectorAll(this.selector);
|
|
59
|
+
this.forEach(elements, (element) => this.renderElement(element));
|
|
60
|
+
}
|
|
61
|
+
}, 10);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Function that assign needed variables for sticky element, that are used in future for calculations and other
|
|
67
|
+
* @function
|
|
68
|
+
* @param {node} element - Element to be rendered
|
|
69
|
+
*/
|
|
70
|
+
renderElement(element) {
|
|
71
|
+
// create container for variables needed in future
|
|
72
|
+
element.sticky = {};
|
|
73
|
+
|
|
74
|
+
// set default variables
|
|
75
|
+
element.sticky.active = false;
|
|
76
|
+
|
|
77
|
+
element.sticky.marginTop = parseInt(element.getAttribute('data-margin-top')) || this.options.marginTop;
|
|
78
|
+
element.sticky.marginBottom = parseInt(element.getAttribute('data-margin-bottom')) || this.options.marginBottom;
|
|
79
|
+
element.sticky.stickyFor = parseInt(element.getAttribute('data-sticky-for')) || this.options.stickyFor;
|
|
80
|
+
element.sticky.stickyClass = element.getAttribute('data-sticky-class') || this.options.stickyClass;
|
|
81
|
+
element.sticky.wrap = element.hasAttribute('data-sticky-wrap') ? true : this.options.wrap;
|
|
82
|
+
// @todo attribute for stickyContainer
|
|
83
|
+
// element.sticky.stickyContainer = element.getAttribute('data-sticky-container') || this.options.stickyContainer;
|
|
84
|
+
element.sticky.stickyContainer = this.options.stickyContainer;
|
|
85
|
+
|
|
86
|
+
element.sticky.container = this.getStickyContainer(element);
|
|
87
|
+
element.sticky.container.rect = this.getRectangle(element.sticky.container);
|
|
88
|
+
|
|
89
|
+
element.sticky.rect = this.getRectangle(element);
|
|
90
|
+
|
|
91
|
+
// fix when element is image that has not yet loaded and width, height = 0
|
|
92
|
+
if (element.tagName.toLowerCase() === 'img') {
|
|
93
|
+
element.onload = () => element.sticky.rect = this.getRectangle(element);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (element.sticky.wrap) {
|
|
97
|
+
this.wrapElement(element);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// activate rendered element
|
|
101
|
+
this.activate(element);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Wraps element into placeholder element
|
|
107
|
+
* @function
|
|
108
|
+
* @param {node} element - Element to be wrapped
|
|
109
|
+
*/
|
|
110
|
+
wrapElement(element) {
|
|
111
|
+
element.insertAdjacentHTML('beforebegin', element.getAttribute('data-sticky-wrapWith') || this.options.wrapWith);
|
|
112
|
+
element.previousSibling.appendChild(element);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Function that activates element when specified conditions are met and then initalise events
|
|
118
|
+
* @function
|
|
119
|
+
* @param {node} element - Element to be activated
|
|
120
|
+
*/
|
|
121
|
+
activate(element) {
|
|
122
|
+
if (
|
|
123
|
+
((element.sticky.rect.top + element.sticky.rect.height) < (element.sticky.container.rect.top + element.sticky.container.rect.height))
|
|
124
|
+
&& (element.sticky.stickyFor < this.vp.width)
|
|
125
|
+
&& !element.sticky.active
|
|
126
|
+
) {
|
|
127
|
+
element.sticky.active = true;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (this.elements.indexOf(element) < 0) {
|
|
131
|
+
this.elements.push(element);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (!element.sticky.resizeEvent) {
|
|
135
|
+
this.initResizeEvents(element);
|
|
136
|
+
element.sticky.resizeEvent = true;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (!element.sticky.scrollEvent) {
|
|
140
|
+
this.initScrollEvents(element);
|
|
141
|
+
element.sticky.scrollEvent = true;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
this.setPosition(element);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Function which is adding onResizeEvents to window listener and assigns function to element as resizeListener
|
|
150
|
+
* @function
|
|
151
|
+
* @param {node} element - Element for which resize events are initialised
|
|
152
|
+
*/
|
|
153
|
+
initResizeEvents(element) {
|
|
154
|
+
element.sticky.resizeListener = () => this.onResizeEvents(element);
|
|
155
|
+
window.addEventListener('resize', element.sticky.resizeListener);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Removes element listener from resize event
|
|
161
|
+
* @function
|
|
162
|
+
* @param {node} element - Element from which listener is deleted
|
|
163
|
+
*/
|
|
164
|
+
destroyResizeEvents(element) {
|
|
165
|
+
window.removeEventListener('resize', element.sticky.resizeListener);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Function which is fired when user resize window. It checks if element should be activated or deactivated and then run setPosition function
|
|
171
|
+
* @function
|
|
172
|
+
* @param {node} element - Element for which event function is fired
|
|
173
|
+
*/
|
|
174
|
+
onResizeEvents(element) {
|
|
175
|
+
this.vp = this.getViewportSize();
|
|
176
|
+
|
|
177
|
+
element.sticky.rect = this.getRectangle(element);
|
|
178
|
+
element.sticky.container.rect = this.getRectangle(element.sticky.container);
|
|
179
|
+
|
|
180
|
+
if (
|
|
181
|
+
((element.sticky.rect.top + element.sticky.rect.height) < (element.sticky.container.rect.top + element.sticky.container.rect.height))
|
|
182
|
+
&& (element.sticky.stickyFor < this.vp.width)
|
|
183
|
+
&& !element.sticky.active
|
|
184
|
+
) {
|
|
185
|
+
element.sticky.active = true;
|
|
186
|
+
} else if (
|
|
187
|
+
((element.sticky.rect.top + element.sticky.rect.height) >= (element.sticky.container.rect.top + element.sticky.container.rect.height))
|
|
188
|
+
|| element.sticky.stickyFor >= this.vp.width
|
|
189
|
+
&& element.sticky.active
|
|
190
|
+
) {
|
|
191
|
+
element.sticky.active = false;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
this.setPosition(element);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Function which is adding onScrollEvents to window listener and assigns function to element as scrollListener
|
|
200
|
+
* @function
|
|
201
|
+
* @param {node} element - Element for which scroll events are initialised
|
|
202
|
+
*/
|
|
203
|
+
initScrollEvents(element) {
|
|
204
|
+
element.sticky.scrollListener = () => this.onScrollEvents(element);
|
|
205
|
+
window.addEventListener('scroll', element.sticky.scrollListener);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Removes element listener from scroll event
|
|
211
|
+
* @function
|
|
212
|
+
* @param {node} element - Element from which listener is deleted
|
|
213
|
+
*/
|
|
214
|
+
destroyScrollEvents(element) {
|
|
215
|
+
window.removeEventListener('scroll', element.sticky.scrollListener);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Function which is fired when user scroll window. If element is active, function is invoking setPosition function
|
|
221
|
+
* @function
|
|
222
|
+
* @param {node} element - Element for which event function is fired
|
|
223
|
+
*/
|
|
224
|
+
onScrollEvents(element) {
|
|
225
|
+
if (element.sticky && element.sticky.active) {
|
|
226
|
+
this.setPosition(element);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Main function for the library. Here are some condition calculations and css appending for sticky element when user scroll window
|
|
233
|
+
* @function
|
|
234
|
+
* @param {node} element - Element that will be positioned if it's active
|
|
235
|
+
*/
|
|
236
|
+
setPosition(element) {
|
|
237
|
+
this.css(element, { position: '', width: '', top: '', left: '' });
|
|
238
|
+
|
|
239
|
+
if ((this.vp.height < element.sticky.rect.height) || !element.sticky.active) {
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if (!element.sticky.rect.width) {
|
|
244
|
+
element.sticky.rect = this.getRectangle(element);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
if (element.sticky.wrap) {
|
|
248
|
+
this.css(element.parentNode, {
|
|
249
|
+
display: 'block',
|
|
250
|
+
width: element.sticky.rect.width + 'px',
|
|
251
|
+
height: element.sticky.rect.height + 'px',
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
const translateY = Math.floor(this.scrollTop - element.sticky.rect.top - element.sticky.marginTop);
|
|
256
|
+
if (
|
|
257
|
+
element.sticky.rect.top === 0
|
|
258
|
+
&& element.sticky.container === this.body
|
|
259
|
+
) {
|
|
260
|
+
this.css(element, {
|
|
261
|
+
position: 'relative',
|
|
262
|
+
transform: `translate3d(0px, ${translateY}px, 0px)`,
|
|
263
|
+
// top: element.sticky.rect.top + 'px',
|
|
264
|
+
// left: element.sticky.rect.left + 'px',
|
|
265
|
+
width: element.sticky.rect.width + 'px',
|
|
266
|
+
top: 0
|
|
267
|
+
});
|
|
268
|
+
if (element.sticky.stickyClass) {
|
|
269
|
+
element.classList.add(element.sticky.stickyClass);
|
|
270
|
+
}
|
|
271
|
+
} else if (this.scrollTop > (element.sticky.rect.top - element.sticky.marginTop)) {
|
|
272
|
+
this.css(element, {
|
|
273
|
+
position: 'relative',
|
|
274
|
+
transform: `translate3d(0px, ${translateY}px, 0px)`,
|
|
275
|
+
width: element.sticky.rect.width + 'px',
|
|
276
|
+
top: 0
|
|
277
|
+
// left: element.sticky.rect.left + 'px',
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
if (
|
|
281
|
+
(this.scrollTop + element.sticky.rect.height + element.sticky.marginTop)
|
|
282
|
+
> (element.sticky.container.rect.top + element.sticky.container.offsetHeight - element.sticky.marginBottom)
|
|
283
|
+
) {
|
|
284
|
+
|
|
285
|
+
if (element.sticky.stickyClass) {
|
|
286
|
+
// element.classList.remove(element.sticky.stickyClass);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
this.css(element, {
|
|
290
|
+
top: (element.sticky.container.rect.top + element.sticky.container.offsetHeight) - (this.scrollTop + element.sticky.rect.height + element.sticky.marginBottom) + 'px' }
|
|
291
|
+
);
|
|
292
|
+
} else {
|
|
293
|
+
if (element.sticky.stickyClass) {
|
|
294
|
+
element.classList.add(element.sticky.stickyClass);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
this.css(element, { top: element.sticky.marginTop + 'px' });
|
|
298
|
+
}
|
|
299
|
+
} else {
|
|
300
|
+
if (element.sticky.stickyClass) {
|
|
301
|
+
element.classList.remove(element.sticky.stickyClass);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
this.css(element, { transform: '', position: '', width: '', top: '', left: '' });
|
|
305
|
+
|
|
306
|
+
if (element.sticky.wrap) {
|
|
307
|
+
this.css(element.parentNode, { display: '', width: '', height: '' });
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* Function that updates element sticky rectangle (with sticky container), then activate or deactivate element, then update position if it's active
|
|
315
|
+
* @function
|
|
316
|
+
*/
|
|
317
|
+
update() {
|
|
318
|
+
this.forEach(this.elements, (element) => {
|
|
319
|
+
element.sticky.rect = this.getRectangle(element);
|
|
320
|
+
element.sticky.container.rect = this.getRectangle(element.sticky.container);
|
|
321
|
+
|
|
322
|
+
this.activate(element);
|
|
323
|
+
this.setPosition(element);
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* Destroys sticky element, remove listeners
|
|
330
|
+
* @function
|
|
331
|
+
*/
|
|
332
|
+
destroy() {
|
|
333
|
+
window.removeEventListener('load', this.updateScrollTopPosition);
|
|
334
|
+
window.removeEventListener('scroll', this.updateScrollTopPosition);
|
|
335
|
+
|
|
336
|
+
this.forEach(this.elements, (element) => {
|
|
337
|
+
this.destroyResizeEvents(element);
|
|
338
|
+
this.destroyScrollEvents(element);
|
|
339
|
+
delete element.sticky;
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* Function that returns container element in which sticky element is stuck (if is not specified, then it's stuck to body)
|
|
346
|
+
* @function
|
|
347
|
+
* @param {node} element - Element which sticky container are looked for
|
|
348
|
+
* @return {node} element - Sticky container
|
|
349
|
+
*/
|
|
350
|
+
getStickyContainer(element) {
|
|
351
|
+
let container = element.parentNode;
|
|
352
|
+
|
|
353
|
+
while (
|
|
354
|
+
!container.hasAttribute('data-sticky-container')
|
|
355
|
+
&& !container.parentNode.querySelector(element.sticky.stickyContainer)
|
|
356
|
+
&& container !== this.body
|
|
357
|
+
) {
|
|
358
|
+
container = container.parentNode;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
return container;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
/**
|
|
366
|
+
* Function that returns element rectangle & position (width, height, top, left)
|
|
367
|
+
* @function
|
|
368
|
+
* @param {node} element - Element which position & rectangle are returned
|
|
369
|
+
* @return {object}
|
|
370
|
+
*/
|
|
371
|
+
getRectangle(element) {
|
|
372
|
+
this.css(element, { position: '', width: '', top: '', left: '' });
|
|
373
|
+
|
|
374
|
+
const width = Math.max(element.offsetWidth, element.clientWidth, element.scrollWidth);
|
|
375
|
+
const height = Math.max(element.offsetHeight, element.clientHeight, element.scrollHeight);
|
|
376
|
+
|
|
377
|
+
let top = 0;
|
|
378
|
+
let left = 0;
|
|
379
|
+
|
|
380
|
+
do {
|
|
381
|
+
top += element.offsetTop || 0;
|
|
382
|
+
left += element.offsetLeft || 0;
|
|
383
|
+
element = element.offsetParent;
|
|
384
|
+
} while(element);
|
|
385
|
+
|
|
386
|
+
return { top, left, width, height };
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* Function that returns viewport dimensions
|
|
392
|
+
* @function
|
|
393
|
+
* @return {object}
|
|
394
|
+
*/
|
|
395
|
+
getViewportSize() {
|
|
396
|
+
return {
|
|
397
|
+
width: Math.max(document.documentElement.clientWidth, window.innerWidth || 0),
|
|
398
|
+
height: Math.max(document.documentElement.clientHeight, window.innerHeight || 0),
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
|
|
403
|
+
/**
|
|
404
|
+
* Function that updates window scroll position
|
|
405
|
+
* @function
|
|
406
|
+
* @return {number}
|
|
407
|
+
*/
|
|
408
|
+
updateScrollTopPosition() {
|
|
409
|
+
this.scrollTop = (window.pageYOffset || document.scrollTop) - (document.clientTop || 0) || 0;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
|
|
413
|
+
/**
|
|
414
|
+
* Helper function for loops
|
|
415
|
+
* @helper
|
|
416
|
+
* @param {array}
|
|
417
|
+
* @param {function} callback - Callback function (no need for explanation)
|
|
418
|
+
*/
|
|
419
|
+
forEach(array, callback) {
|
|
420
|
+
for (let i = 0, len = array.length; i < len; i++) {
|
|
421
|
+
callback(array[i]);
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
|
|
426
|
+
/**
|
|
427
|
+
* Helper function to add/remove css properties for specified element.
|
|
428
|
+
* @helper
|
|
429
|
+
* @param {node} element - DOM element
|
|
430
|
+
* @param {object} properties - CSS properties that will be added/removed from specified element
|
|
431
|
+
*/
|
|
432
|
+
css(element, properties) {
|
|
433
|
+
for (let property in properties) {
|
|
434
|
+
if (properties.hasOwnProperty(property)) {
|
|
435
|
+
element.style[property] = properties[property];
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
}
|