@rhavenside/baseline 2.0.0
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/README.md +472 -0
- package/dist/base-line.css +5 -0
- package/dist/base-line.css.map +1 -0
- package/dist/fonts/GoogleSansCode-Bold.ttf +0 -0
- package/dist/fonts/GoogleSansCode-BoldItalic.ttf +0 -0
- package/dist/fonts/GoogleSansCode-ExtraBold.ttf +0 -0
- package/dist/fonts/GoogleSansCode-ExtraBoldItalic.ttf +0 -0
- package/dist/fonts/GoogleSansCode-Italic-VariableFont_wght.ttf +0 -0
- package/dist/fonts/GoogleSansCode-Italic.ttf +0 -0
- package/dist/fonts/GoogleSansCode-Light.ttf +0 -0
- package/dist/fonts/GoogleSansCode-LightItalic.ttf +0 -0
- package/dist/fonts/GoogleSansCode-Medium.ttf +0 -0
- package/dist/fonts/GoogleSansCode-MediumItalic.ttf +0 -0
- package/dist/fonts/GoogleSansCode-Regular.ttf +0 -0
- package/dist/fonts/GoogleSansCode-SemiBold.ttf +0 -0
- package/dist/fonts/GoogleSansCode-SemiBoldItalic.ttf +0 -0
- package/dist/fonts/GoogleSansCode-VariableFont_wght.ttf +0 -0
- package/dist/fonts/RobotoCondensed-Black.ttf +0 -0
- package/dist/fonts/RobotoCondensed-BlackItalic.ttf +0 -0
- package/dist/fonts/RobotoCondensed-Bold.ttf +0 -0
- package/dist/fonts/RobotoCondensed-BoldItalic.ttf +0 -0
- package/dist/fonts/RobotoCondensed-ExtraBold.ttf +0 -0
- package/dist/fonts/RobotoCondensed-ExtraBoldItalic.ttf +0 -0
- package/dist/fonts/RobotoCondensed-ExtraLight.ttf +0 -0
- package/dist/fonts/RobotoCondensed-ExtraLightItalic.ttf +0 -0
- package/dist/fonts/RobotoCondensed-Italic-VariableFont_wght.ttf +0 -0
- package/dist/fonts/RobotoCondensed-Italic.ttf +0 -0
- package/dist/fonts/RobotoCondensed-Light.ttf +0 -0
- package/dist/fonts/RobotoCondensed-LightItalic.ttf +0 -0
- package/dist/fonts/RobotoCondensed-Medium.ttf +0 -0
- package/dist/fonts/RobotoCondensed-MediumItalic.ttf +0 -0
- package/dist/fonts/RobotoCondensed-Regular.ttf +0 -0
- package/dist/fonts/RobotoCondensed-SemiBold.ttf +0 -0
- package/dist/fonts/RobotoCondensed-SemiBoldItalic.ttf +0 -0
- package/dist/fonts/RobotoCondensed-Thin.ttf +0 -0
- package/dist/fonts/RobotoCondensed-ThinItalic.ttf +0 -0
- package/dist/fonts/RobotoCondensed-VariableFont_wght.ttf +0 -0
- package/dist/fonts/ZalandoSansExpanded-Black.ttf +0 -0
- package/dist/fonts/ZalandoSansExpanded-BlackItalic.ttf +0 -0
- package/dist/fonts/ZalandoSansExpanded-Bold.ttf +0 -0
- package/dist/fonts/ZalandoSansExpanded-BoldItalic.ttf +0 -0
- package/dist/fonts/ZalandoSansExpanded-ExtraBold.ttf +0 -0
- package/dist/fonts/ZalandoSansExpanded-ExtraBoldItalic.ttf +0 -0
- package/dist/fonts/ZalandoSansExpanded-ExtraLight.ttf +0 -0
- package/dist/fonts/ZalandoSansExpanded-ExtraLightItalic.ttf +0 -0
- package/dist/fonts/ZalandoSansExpanded-Italic-VariableFont_wght.ttf +0 -0
- package/dist/fonts/ZalandoSansExpanded-Italic.ttf +0 -0
- package/dist/fonts/ZalandoSansExpanded-Light.ttf +0 -0
- package/dist/fonts/ZalandoSansExpanded-LightItalic.ttf +0 -0
- package/dist/fonts/ZalandoSansExpanded-Medium.ttf +0 -0
- package/dist/fonts/ZalandoSansExpanded-MediumItalic.ttf +0 -0
- package/dist/fonts/ZalandoSansExpanded-Regular.ttf +0 -0
- package/dist/fonts/ZalandoSansExpanded-SemiBold.ttf +0 -0
- package/dist/fonts/ZalandoSansExpanded-SemiBoldItalic.ttf +0 -0
- package/dist/fonts/ZalandoSansExpanded-VariableFont_wght.ttf +0 -0
- package/dist/fonts/baseline-icons.woff +0 -0
- package/dist/fonts/baseline-icons.woff2 +0 -0
- package/dist/js/accordion.js +103 -0
- package/dist/js/alert.js +91 -0
- package/dist/js/base.js +146 -0
- package/dist/js/button.js +80 -0
- package/dist/js/carousel.js +427 -0
- package/dist/js/collapse.js +233 -0
- package/dist/js/color-modes.js +70 -0
- package/dist/js/component.js +114 -0
- package/dist/js/dropdown.js +348 -0
- package/dist/js/index.js +108 -0
- package/dist/js/modal.js +440 -0
- package/dist/js/offcanvas.js +356 -0
- package/dist/js/popover.js +241 -0
- package/dist/js/swipe.js +143 -0
- package/dist/js/tab.js +285 -0
- package/dist/js/toast.js +228 -0
- package/dist/js/tooltip.js +716 -0
- package/dist/js/util/backdrop.js +133 -0
- package/dist/js/util/component-functions.js +111 -0
- package/dist/js/util/focustrap.js +101 -0
- package/dist/js/util/scrollbar.js +111 -0
- package/dist/js/util.js +564 -0
- package/package.json +47 -0
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base-Line Backdrop Utility
|
|
3
|
+
* Baseline 2.0 compatible backdrop with Base-Line naming
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { on, off, executeAfterTransition, reflow, getElement } from '../util.js'
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Constants
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const CLASS_NAME_FADE = 'c-fade'
|
|
13
|
+
const CLASS_NAME_SHOW = 'is-show'
|
|
14
|
+
const EVENT_MOUSEDOWN = `mousedown.c.backdrop`
|
|
15
|
+
|
|
16
|
+
const Default = {
|
|
17
|
+
className: 'c-modal-backdrop',
|
|
18
|
+
clickCallback: null,
|
|
19
|
+
isAnimated: false,
|
|
20
|
+
isVisible: true,
|
|
21
|
+
rootElement: 'body'
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Class definition
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
class Backdrop {
|
|
29
|
+
constructor(config) {
|
|
30
|
+
this._config = { ...Default, ...config }
|
|
31
|
+
this._isAppended = false
|
|
32
|
+
this._element = null
|
|
33
|
+
|
|
34
|
+
// Convert rootElement string to element
|
|
35
|
+
if (typeof this._config.rootElement === 'string') {
|
|
36
|
+
this._config.rootElement = getElement(this._config.rootElement) || document.body
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
static get Default() {
|
|
41
|
+
return Default
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
static get NAME() {
|
|
45
|
+
return 'backdrop'
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Public
|
|
49
|
+
show(callback) {
|
|
50
|
+
if (!this._config.isVisible) {
|
|
51
|
+
if (callback) callback()
|
|
52
|
+
return
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
this._append()
|
|
56
|
+
|
|
57
|
+
const element = this._getElement()
|
|
58
|
+
if (this._config.isAnimated) {
|
|
59
|
+
reflow(element)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
element.classList.add(CLASS_NAME_SHOW)
|
|
63
|
+
|
|
64
|
+
this._emulateAnimation(() => {
|
|
65
|
+
if (callback) callback()
|
|
66
|
+
})
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
hide(callback) {
|
|
70
|
+
if (!this._config.isVisible) {
|
|
71
|
+
if (callback) callback()
|
|
72
|
+
return
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
this._getElement().classList.remove(CLASS_NAME_SHOW)
|
|
76
|
+
|
|
77
|
+
this._emulateAnimation(() => {
|
|
78
|
+
this.dispose()
|
|
79
|
+
if (callback) callback()
|
|
80
|
+
})
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
dispose() {
|
|
84
|
+
if (!this._isAppended) {
|
|
85
|
+
return
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
off(this._element, EVENT_MOUSEDOWN)
|
|
89
|
+
|
|
90
|
+
this._element.remove()
|
|
91
|
+
this._isAppended = false
|
|
92
|
+
this._element = null
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Private
|
|
96
|
+
_getElement() {
|
|
97
|
+
if (!this._element) {
|
|
98
|
+
const backdrop = document.createElement('div')
|
|
99
|
+
backdrop.className = this._config.className
|
|
100
|
+
if (this._config.isAnimated) {
|
|
101
|
+
backdrop.classList.add(CLASS_NAME_FADE)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
this._element = backdrop
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return this._element
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
_append() {
|
|
111
|
+
if (this._isAppended) {
|
|
112
|
+
return
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const element = this._getElement()
|
|
116
|
+
this._config.rootElement.append(element)
|
|
117
|
+
|
|
118
|
+
on(element, EVENT_MOUSEDOWN, () => {
|
|
119
|
+
if (this._config.clickCallback) {
|
|
120
|
+
this._config.clickCallback()
|
|
121
|
+
}
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
this._isAppended = true
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
_emulateAnimation(callback) {
|
|
128
|
+
executeAfterTransition(callback, this._getElement(), this._config.isAnimated)
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export default Backdrop
|
|
133
|
+
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base-Line Component Functions Utility
|
|
3
|
+
* Baseline 2.0 compatible component functions with Base-Line naming
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { SelectorEngine } from '../util.js'
|
|
7
|
+
import { isDisabled } from '../util.js'
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Enable dismiss trigger for components
|
|
11
|
+
* @param {Function} component - Component class
|
|
12
|
+
* @param {string} method - Method name to call (default: 'hide')
|
|
13
|
+
*/
|
|
14
|
+
export const enableDismissTrigger = (component, method = 'hide') => {
|
|
15
|
+
const clickEvent = `click.dismiss${component.EVENT_KEY}`
|
|
16
|
+
const name = component.NAME
|
|
17
|
+
const selector = `[data-c-dismiss="${name}"]`
|
|
18
|
+
|
|
19
|
+
// Use direct event listener with capture phase to catch events before React
|
|
20
|
+
// This matches Bootstrap's approach but uses capture phase for React compatibility
|
|
21
|
+
document.addEventListener('click', function (event) {
|
|
22
|
+
// Traverse up the DOM tree to find the dismiss button (similar to Bootstrap's approach)
|
|
23
|
+
let target = event.target
|
|
24
|
+
let dismissButton = null
|
|
25
|
+
|
|
26
|
+
while (target && target !== document) {
|
|
27
|
+
if (target.matches && target.matches(selector)) {
|
|
28
|
+
dismissButton = target
|
|
29
|
+
break
|
|
30
|
+
}
|
|
31
|
+
target = target.parentElement
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (!dismissButton) {
|
|
35
|
+
return
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (['A', 'AREA'].includes(dismissButton.tagName)) {
|
|
39
|
+
event.preventDefault()
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Stop propagation to prevent React from interfering
|
|
43
|
+
event.stopPropagation()
|
|
44
|
+
|
|
45
|
+
if (isDisabled(dismissButton)) {
|
|
46
|
+
return
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// First try to find the component element using closest (for dismiss buttons inside the component)
|
|
50
|
+
// This is the most reliable method
|
|
51
|
+
let componentElement = dismissButton.closest(`.c-${name}`)
|
|
52
|
+
|
|
53
|
+
// If closest didn't work, try getElementFromSelector (for buttons with data-c-target pointing to the component)
|
|
54
|
+
if (!componentElement) {
|
|
55
|
+
componentElement = SelectorEngine.getElementFromSelector(dismissButton)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// If still not found, search for all components of this type and check if they contain the dismiss button
|
|
59
|
+
// This handles cases where the dismiss button is not a direct child of the component
|
|
60
|
+
if (!componentElement) {
|
|
61
|
+
const allComponents = document.querySelectorAll(`.c-${name}`)
|
|
62
|
+
|
|
63
|
+
for (const comp of allComponents) {
|
|
64
|
+
// Check if component contains the dismiss button
|
|
65
|
+
if (comp.contains(dismissButton)) {
|
|
66
|
+
componentElement = comp
|
|
67
|
+
break
|
|
68
|
+
}
|
|
69
|
+
// Also check if component has a dismiss button that matches
|
|
70
|
+
const dismissBtnInComp = comp.querySelector(`[data-c-dismiss="${name}"]`)
|
|
71
|
+
if (dismissBtnInComp === dismissButton) {
|
|
72
|
+
componentElement = comp
|
|
73
|
+
break
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Last resort: find the first visible component of this type that has the 'show' class
|
|
79
|
+
// Only use this if we really can't find the component any other way
|
|
80
|
+
if (!componentElement) {
|
|
81
|
+
const visibleComponents = Array.from(document.querySelectorAll(`.c-${name}`)).filter(comp =>
|
|
82
|
+
comp.classList.contains('show')
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
if (visibleComponents.length === 1) {
|
|
86
|
+
// Only use this if there's exactly one visible component
|
|
87
|
+
componentElement = visibleComponents[0]
|
|
88
|
+
} else if (visibleComponents.length > 1) {
|
|
89
|
+
// If multiple visible, try to find the one that contains the dismiss button
|
|
90
|
+
for (const comp of visibleComponents) {
|
|
91
|
+
if (comp.contains(dismissButton)) {
|
|
92
|
+
componentElement = comp
|
|
93
|
+
break
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (!componentElement) {
|
|
100
|
+
return
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const instance = component.getOrCreateInstance(componentElement)
|
|
104
|
+
|
|
105
|
+
// Method argument is left, for Alert and only, as it doesn't implement the 'hide' method
|
|
106
|
+
if (instance && typeof instance[method] === 'function') {
|
|
107
|
+
instance[method]()
|
|
108
|
+
}
|
|
109
|
+
}, true) // Use capture phase to catch events before React
|
|
110
|
+
}
|
|
111
|
+
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base-Line FocusTrap Utility
|
|
3
|
+
* Baseline 2.0 compatible focus trap with Base-Line naming
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { on, off } from '../util.js'
|
|
7
|
+
import { SelectorEngine } from '../util.js'
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Constants
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
const DATA_KEY = 'c.focustrap'
|
|
14
|
+
const EVENT_KEY = `.${DATA_KEY}`
|
|
15
|
+
const EVENT_FOCUSIN = `focusin${EVENT_KEY}`
|
|
16
|
+
const EVENT_KEYDOWN_TAB = `keydown.tab${EVENT_KEY}`
|
|
17
|
+
|
|
18
|
+
const TAB_KEY = 'Tab'
|
|
19
|
+
const TAB_NAV_FORWARD = 'forward'
|
|
20
|
+
const TAB_NAV_BACKWARD = 'backward'
|
|
21
|
+
|
|
22
|
+
const Default = {
|
|
23
|
+
autofocus: true,
|
|
24
|
+
trapElement: null
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Class definition
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
class FocusTrap {
|
|
32
|
+
constructor(config) {
|
|
33
|
+
this._config = { ...Default, ...config }
|
|
34
|
+
this._isActive = false
|
|
35
|
+
this._lastTabNavDirection = null
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
static get Default() {
|
|
39
|
+
return Default
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
static get NAME() {
|
|
43
|
+
return 'focustrap'
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Public
|
|
47
|
+
activate() {
|
|
48
|
+
if (this._isActive) {
|
|
49
|
+
return
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (this._config.autofocus) {
|
|
53
|
+
this._config.trapElement.focus()
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
off(document, EVENT_KEY) // guard against infinite focus loop
|
|
57
|
+
on(document, EVENT_FOCUSIN, (event) => this._handleFocusin(event))
|
|
58
|
+
on(document, EVENT_KEYDOWN_TAB, (event) => this._handleKeydown(event))
|
|
59
|
+
|
|
60
|
+
this._isActive = true
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
deactivate() {
|
|
64
|
+
if (!this._isActive) {
|
|
65
|
+
return
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
this._isActive = false
|
|
69
|
+
off(document, EVENT_KEY)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Private
|
|
73
|
+
_handleFocusin(event) {
|
|
74
|
+
const { trapElement } = this._config
|
|
75
|
+
|
|
76
|
+
if (event.target === document || event.target === trapElement || trapElement.contains(event.target)) {
|
|
77
|
+
return
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const elements = SelectorEngine.focusableChildren(trapElement)
|
|
81
|
+
|
|
82
|
+
if (elements.length === 0) {
|
|
83
|
+
trapElement.focus()
|
|
84
|
+
} else if (this._lastTabNavDirection === TAB_NAV_BACKWARD) {
|
|
85
|
+
elements[elements.length - 1].focus()
|
|
86
|
+
} else {
|
|
87
|
+
elements[0].focus()
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
_handleKeydown(event) {
|
|
92
|
+
if (event.key !== TAB_KEY) {
|
|
93
|
+
return
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
this._lastTabNavDirection = event.shiftKey ? TAB_NAV_BACKWARD : TAB_NAV_FORWARD
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export default FocusTrap
|
|
101
|
+
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base-Line ScrollBarHelper Utility
|
|
3
|
+
* Baseline 2.0 compatible scrollbar helper with Base-Line naming
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { SelectorEngine, isElement } from '../util.js'
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Constants
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const SELECTOR_FIXED_CONTENT = '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top'
|
|
13
|
+
const SELECTOR_STICKY_CONTENT = '.sticky-top'
|
|
14
|
+
const PROPERTY_PADDING = 'padding-right'
|
|
15
|
+
const PROPERTY_MARGIN = 'margin-right'
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Class definition
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
class ScrollBarHelper {
|
|
22
|
+
constructor() {
|
|
23
|
+
this._element = document.body
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Public
|
|
27
|
+
getWidth() {
|
|
28
|
+
// https://developer.mozilla.org/en-US/docs/Web/API/Window/innerWidth#usage_notes
|
|
29
|
+
const documentWidth = document.documentElement.clientWidth
|
|
30
|
+
return Math.abs(window.innerWidth - documentWidth)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
hide() {
|
|
34
|
+
const width = this.getWidth()
|
|
35
|
+
this._disableOverFlow()
|
|
36
|
+
// give padding to element to balance the hidden scrollbar width
|
|
37
|
+
this._setElementAttributes(this._element, PROPERTY_PADDING, calculatedValue => calculatedValue + width)
|
|
38
|
+
// trick: We adjust positive paddingRight and negative marginRight to sticky-top elements to keep showing fullwidth
|
|
39
|
+
this._setElementAttributes(SELECTOR_FIXED_CONTENT, PROPERTY_PADDING, calculatedValue => calculatedValue + width)
|
|
40
|
+
this._setElementAttributes(SELECTOR_STICKY_CONTENT, PROPERTY_MARGIN, calculatedValue => calculatedValue - width)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
reset() {
|
|
44
|
+
this._resetElementAttributes(this._element, 'overflow')
|
|
45
|
+
this._resetElementAttributes(this._element, PROPERTY_PADDING)
|
|
46
|
+
this._resetElementAttributes(SELECTOR_FIXED_CONTENT, PROPERTY_PADDING)
|
|
47
|
+
this._resetElementAttributes(SELECTOR_STICKY_CONTENT, PROPERTY_MARGIN)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
isOverflowing() {
|
|
51
|
+
return this.getWidth() > 0
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Private
|
|
55
|
+
_disableOverFlow() {
|
|
56
|
+
this._saveInitialAttribute(this._element, 'overflow')
|
|
57
|
+
this._element.style.overflow = 'hidden'
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
_setElementAttributes(selector, styleProperty, callback) {
|
|
61
|
+
const scrollbarWidth = this.getWidth()
|
|
62
|
+
const manipulationCallBack = element => {
|
|
63
|
+
if (element !== this._element && window.innerWidth > element.clientWidth + scrollbarWidth) {
|
|
64
|
+
return
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
this._saveInitialAttribute(element, styleProperty)
|
|
68
|
+
const calculatedValue = window.getComputedStyle(element).getPropertyValue(styleProperty)
|
|
69
|
+
element.style.setProperty(styleProperty, `${callback(Number.parseFloat(calculatedValue) || 0)}px`)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
this._applyManipulationCallback(selector, manipulationCallBack)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
_saveInitialAttribute(element, styleProperty) {
|
|
76
|
+
const actualValue = element.style.getPropertyValue(styleProperty)
|
|
77
|
+
if (actualValue) {
|
|
78
|
+
element.setAttribute(`data-c-${styleProperty}`, actualValue)
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
_resetElementAttributes(selector, styleProperty) {
|
|
83
|
+
const manipulationCallBack = element => {
|
|
84
|
+
const value = element.getAttribute(`data-c-${styleProperty}`)
|
|
85
|
+
// We only want to remove the property if the value is `null`; the value can also be zero
|
|
86
|
+
if (value === null) {
|
|
87
|
+
element.style.removeProperty(styleProperty)
|
|
88
|
+
return
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
element.removeAttribute(`data-c-${styleProperty}`)
|
|
92
|
+
element.style.setProperty(styleProperty, value)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
this._applyManipulationCallback(selector, manipulationCallBack)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
_applyManipulationCallback(selector, callBack) {
|
|
99
|
+
if (isElement(selector)) {
|
|
100
|
+
callBack(selector)
|
|
101
|
+
return
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
for (const sel of SelectorEngine.find(selector, this._element)) {
|
|
105
|
+
callBack(sel)
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export default ScrollBarHelper
|
|
111
|
+
|