@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
package/dist/js/swipe.js
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base-Line Swipe Utility
|
|
3
|
+
* Baseline 2.0 compatible swipe with Base-Line naming
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { on, off } from './util.js'
|
|
7
|
+
|
|
8
|
+
const NAME = 'swipe'
|
|
9
|
+
const EVENT_KEY = `.c.${NAME}`
|
|
10
|
+
const EVENT_TOUCHSTART = `touchstart${EVENT_KEY}`
|
|
11
|
+
const EVENT_TOUCHMOVE = `touchmove${EVENT_KEY}`
|
|
12
|
+
const EVENT_TOUCHEND = `touchend${EVENT_KEY}`
|
|
13
|
+
const EVENT_POINTERDOWN = `pointerdown${EVENT_KEY}`
|
|
14
|
+
const EVENT_POINTERUP = `pointerup${EVENT_KEY}`
|
|
15
|
+
const POINTER_TYPE_TOUCH = 'touch'
|
|
16
|
+
const POINTER_TYPE_PEN = 'pen'
|
|
17
|
+
const CLASS_NAME_POINTER_EVENT = 'pointer-event'
|
|
18
|
+
const SWIPE_THRESHOLD = 40
|
|
19
|
+
|
|
20
|
+
const Default = {
|
|
21
|
+
endCallback: null,
|
|
22
|
+
leftCallback: null,
|
|
23
|
+
rightCallback: null
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
class Swipe {
|
|
27
|
+
constructor(element, config = {}) {
|
|
28
|
+
this._element = element
|
|
29
|
+
this._config = { ...Default, ...config }
|
|
30
|
+
|
|
31
|
+
if (!element || !Swipe.isSupported()) {
|
|
32
|
+
return
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
this._deltaX = 0
|
|
36
|
+
this._supportPointerEvents = Boolean(window.PointerEvent)
|
|
37
|
+
this._initEvents()
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
static get Default() {
|
|
41
|
+
return Default
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
static get NAME() {
|
|
45
|
+
return NAME
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
static isSupported() {
|
|
49
|
+
return 'ontouchstart' in document.documentElement || navigator.maxTouchPoints > 0
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
dispose() {
|
|
53
|
+
if (this._boundStart) {
|
|
54
|
+
if (this._supportPointerEvents) {
|
|
55
|
+
off(this._element, EVENT_POINTERDOWN, this._boundStart)
|
|
56
|
+
off(this._element, EVENT_POINTERUP, this._boundEnd)
|
|
57
|
+
} else {
|
|
58
|
+
off(this._element, EVENT_TOUCHSTART, this._boundStart)
|
|
59
|
+
off(this._element, EVENT_TOUCHMOVE, this._boundMove)
|
|
60
|
+
off(this._element, EVENT_TOUCHEND, this._boundEnd)
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
if (this._element && this._element.classList) {
|
|
64
|
+
this._element.classList.remove(CLASS_NAME_POINTER_EVENT)
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
_start(event) {
|
|
69
|
+
if (!this._supportPointerEvents) {
|
|
70
|
+
this._deltaX = event.touches[0].clientX
|
|
71
|
+
return
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (this._eventIsPointerPenTouch(event)) {
|
|
75
|
+
this._deltaX = event.clientX
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
_end(event) {
|
|
80
|
+
if (this._eventIsPointerPenTouch(event)) {
|
|
81
|
+
this._deltaX = event.clientX - this._deltaX
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
this._handleSwipe()
|
|
85
|
+
if (this._config.endCallback) {
|
|
86
|
+
this._config.endCallback()
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
_move(event) {
|
|
91
|
+
this._deltaX = event.touches && event.touches.length > 1 ?
|
|
92
|
+
0 :
|
|
93
|
+
event.touches[0].clientX - this._deltaX
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
_handleSwipe() {
|
|
97
|
+
const absDeltaX = Math.abs(this._deltaX)
|
|
98
|
+
|
|
99
|
+
if (absDeltaX <= SWIPE_THRESHOLD) {
|
|
100
|
+
return
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const direction = absDeltaX / this._deltaX
|
|
104
|
+
|
|
105
|
+
this._deltaX = 0
|
|
106
|
+
|
|
107
|
+
if (!direction) {
|
|
108
|
+
return
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (direction > 0 && this._config.rightCallback) {
|
|
112
|
+
this._config.rightCallback()
|
|
113
|
+
} else if (direction < 0 && this._config.leftCallback) {
|
|
114
|
+
this._config.leftCallback()
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
_initEvents() {
|
|
119
|
+
this._boundStart = (event) => this._start(event)
|
|
120
|
+
this._boundMove = (event) => this._move(event)
|
|
121
|
+
this._boundEnd = (event) => this._end(event)
|
|
122
|
+
|
|
123
|
+
if (this._supportPointerEvents) {
|
|
124
|
+
on(this._element, EVENT_POINTERDOWN, this._boundStart)
|
|
125
|
+
on(this._element, EVENT_POINTERUP, this._boundEnd)
|
|
126
|
+
|
|
127
|
+
if (this._element.classList) {
|
|
128
|
+
this._element.classList.add(CLASS_NAME_POINTER_EVENT)
|
|
129
|
+
}
|
|
130
|
+
} else {
|
|
131
|
+
on(this._element, EVENT_TOUCHSTART, this._boundStart)
|
|
132
|
+
on(this._element, EVENT_TOUCHMOVE, this._boundMove)
|
|
133
|
+
on(this._element, EVENT_TOUCHEND, this._boundEnd)
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
_eventIsPointerPenTouch(event) {
|
|
138
|
+
return this._supportPointerEvents && (event.pointerType === POINTER_TYPE_PEN || event.pointerType === POINTER_TYPE_TOUCH)
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export default Swipe
|
|
143
|
+
|
package/dist/js/tab.js
ADDED
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base-Line Tab Component
|
|
3
|
+
* Baseline 2.0 compatible tabs with Base-Line naming
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { BaseComponent } from './base.js'
|
|
7
|
+
import { on, getElementFromSelector, getNextActiveElement, isDisabled, SelectorEngine } from './util.js'
|
|
8
|
+
|
|
9
|
+
const NAME = 'tab'
|
|
10
|
+
const DATA_KEY = `c.${NAME}`
|
|
11
|
+
const EVENT_KEY = `.${DATA_KEY}`
|
|
12
|
+
|
|
13
|
+
const EVENT_HIDE = `hide${EVENT_KEY}`
|
|
14
|
+
const EVENT_HIDDEN = `hidden${EVENT_KEY}`
|
|
15
|
+
const EVENT_SHOW = `show${EVENT_KEY}`
|
|
16
|
+
const EVENT_SHOWN = `shown${EVENT_KEY}`
|
|
17
|
+
const EVENT_CLICK_DATA_API = `click${EVENT_KEY}`
|
|
18
|
+
const EVENT_KEYDOWN = `keydown${EVENT_KEY}`
|
|
19
|
+
const EVENT_LOAD_DATA_API = `load${EVENT_KEY}`
|
|
20
|
+
|
|
21
|
+
const ARROW_LEFT_KEY = 'ArrowLeft'
|
|
22
|
+
const ARROW_RIGHT_KEY = 'ArrowRight'
|
|
23
|
+
const ARROW_UP_KEY = 'ArrowUp'
|
|
24
|
+
const ARROW_DOWN_KEY = 'ArrowDown'
|
|
25
|
+
const HOME_KEY = 'Home'
|
|
26
|
+
const END_KEY = 'End'
|
|
27
|
+
|
|
28
|
+
const CLASS_NAME_ACTIVE = 'is-active'
|
|
29
|
+
const CLASS_NAME_FADE = 'c-fade'
|
|
30
|
+
const CLASS_NAME_SHOW = 'is-show'
|
|
31
|
+
const CLASS_DROPDOWN = 'c-dropdown'
|
|
32
|
+
|
|
33
|
+
const SELECTOR_DROPDOWN_TOGGLE = '.c-dropdown-toggle'
|
|
34
|
+
const SELECTOR_DROPDOWN_MENU = '.c-dropdown-menu'
|
|
35
|
+
const NOT_SELECTOR_DROPDOWN_TOGGLE = `:not(${SELECTOR_DROPDOWN_TOGGLE})`
|
|
36
|
+
|
|
37
|
+
const SELECTOR_TAB_PANEL = '.c-list-group, .c-nav, [role="tablist"]'
|
|
38
|
+
const SELECTOR_OUTER = '.c-nav-item, .c-list-group-item'
|
|
39
|
+
const SELECTOR_INNER = `.c-nav-link${NOT_SELECTOR_DROPDOWN_TOGGLE}, .c-list-group-item${NOT_SELECTOR_DROPDOWN_TOGGLE}, [role="tab"]${NOT_SELECTOR_DROPDOWN_TOGGLE}`
|
|
40
|
+
const SELECTOR_DATA_TOGGLE = '[data-c-toggle="tab"], [data-c-toggle="pill"], [data-bl-toggle="tab"], [data-bl-toggle="pill"], [data-bl-toggle="list"]'
|
|
41
|
+
const SELECTOR_INNER_ELEM = `${SELECTOR_INNER}, ${SELECTOR_DATA_TOGGLE}`
|
|
42
|
+
|
|
43
|
+
const SELECTOR_DATA_TOGGLE_ACTIVE = `.${CLASS_NAME_ACTIVE}[data-c-toggle="tab"], .${CLASS_NAME_ACTIVE}[data-c-toggle="pill"], .${CLASS_NAME_ACTIVE}[data-bl-toggle="tab"], .${CLASS_NAME_ACTIVE}[data-bl-toggle="pill"], .${CLASS_NAME_ACTIVE}[data-bl-toggle="list"]`
|
|
44
|
+
|
|
45
|
+
class Tab extends BaseComponent {
|
|
46
|
+
constructor(element) {
|
|
47
|
+
super(element)
|
|
48
|
+
this._parent = this._element.closest(SELECTOR_TAB_PANEL)
|
|
49
|
+
|
|
50
|
+
if (!this._parent) {
|
|
51
|
+
return
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Set up initial aria attributes
|
|
55
|
+
this._setInitialAttributes(this._parent, this._getChildren())
|
|
56
|
+
|
|
57
|
+
on(this._element, EVENT_KEYDOWN, (event) => this._keydown(event))
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
static get NAME() {
|
|
61
|
+
return NAME
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Public
|
|
65
|
+
show() {
|
|
66
|
+
const innerElem = this._element
|
|
67
|
+
if (this._elemIsActive(innerElem)) {
|
|
68
|
+
return
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Search for active tab on same parent to deactivate it
|
|
72
|
+
const active = this._getActiveElem()
|
|
73
|
+
|
|
74
|
+
const hideEvent = active ?
|
|
75
|
+
this._triggerEvent(active, EVENT_HIDE, { relatedTarget: innerElem }) :
|
|
76
|
+
null
|
|
77
|
+
|
|
78
|
+
const showEvent = this._triggerEvent(innerElem, EVENT_SHOW, { relatedTarget: active })
|
|
79
|
+
|
|
80
|
+
if (showEvent.defaultPrevented || (hideEvent && hideEvent.defaultPrevented)) {
|
|
81
|
+
return
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
this._deactivate(active, innerElem)
|
|
85
|
+
this._activate(innerElem, active)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Private
|
|
89
|
+
_activate(element, relatedElem) {
|
|
90
|
+
if (!element) {
|
|
91
|
+
return
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
element.classList.add(CLASS_NAME_ACTIVE)
|
|
95
|
+
|
|
96
|
+
this._activate(SelectorEngine.getElementFromSelector(element)) // Search and activate/show the proper section
|
|
97
|
+
|
|
98
|
+
const complete = () => {
|
|
99
|
+
if (element.getAttribute('role') !== 'tab') {
|
|
100
|
+
element.classList.add(CLASS_NAME_SHOW)
|
|
101
|
+
return
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
element.removeAttribute('tabindex')
|
|
105
|
+
element.setAttribute('aria-selected', true)
|
|
106
|
+
this._toggleDropDown(element, true)
|
|
107
|
+
this._triggerEvent(element, EVENT_SHOWN, {
|
|
108
|
+
relatedTarget: relatedElem
|
|
109
|
+
})
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
this._queueCallback(complete, element, element.classList.contains(CLASS_NAME_FADE))
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
_deactivate(element, relatedElem) {
|
|
116
|
+
if (!element) {
|
|
117
|
+
return
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
element.classList.remove(CLASS_NAME_ACTIVE)
|
|
121
|
+
element.blur()
|
|
122
|
+
|
|
123
|
+
this._deactivate(SelectorEngine.getElementFromSelector(element)) // Search and deactivate the shown section too
|
|
124
|
+
|
|
125
|
+
const complete = () => {
|
|
126
|
+
if (element.getAttribute('role') !== 'tab') {
|
|
127
|
+
element.classList.remove(CLASS_NAME_SHOW)
|
|
128
|
+
return
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
element.setAttribute('aria-selected', false)
|
|
132
|
+
element.setAttribute('tabindex', '-1')
|
|
133
|
+
this._toggleDropDown(element, false)
|
|
134
|
+
this._triggerEvent(element, EVENT_HIDDEN, { relatedTarget: relatedElem })
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
this._queueCallback(complete, element, element.classList.contains(CLASS_NAME_FADE))
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
_keydown(event) {
|
|
141
|
+
if (!([ARROW_LEFT_KEY, ARROW_RIGHT_KEY, ARROW_UP_KEY, ARROW_DOWN_KEY, HOME_KEY, END_KEY].includes(event.key))) {
|
|
142
|
+
return
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
event.stopPropagation()
|
|
146
|
+
event.preventDefault()
|
|
147
|
+
|
|
148
|
+
const children = this._getChildren().filter(element => !isDisabled(element))
|
|
149
|
+
let nextActiveElement
|
|
150
|
+
|
|
151
|
+
if ([HOME_KEY, END_KEY].includes(event.key)) {
|
|
152
|
+
nextActiveElement = children[event.key === HOME_KEY ? 0 : children.length - 1]
|
|
153
|
+
} else {
|
|
154
|
+
const isNext = [ARROW_RIGHT_KEY, ARROW_DOWN_KEY].includes(event.key)
|
|
155
|
+
nextActiveElement = getNextActiveElement(children, event.target, isNext, true)
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (nextActiveElement) {
|
|
159
|
+
nextActiveElement.focus({ preventScroll: true })
|
|
160
|
+
Tab.getOrCreateInstance(nextActiveElement).show()
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
_getChildren() {
|
|
165
|
+
return SelectorEngine.find(SELECTOR_INNER_ELEM, this._parent)
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
_getActiveElem() {
|
|
169
|
+
return this._getChildren().find(child => this._elemIsActive(child)) || null
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
_setInitialAttributes(parent, children) {
|
|
173
|
+
this._setAttributeIfNotExists(parent, 'role', 'tablist')
|
|
174
|
+
|
|
175
|
+
for (const child of children) {
|
|
176
|
+
this._setInitialAttributesOnChild(child)
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
_setInitialAttributesOnChild(child) {
|
|
181
|
+
child = this._getInnerElement(child)
|
|
182
|
+
const isActive = this._elemIsActive(child)
|
|
183
|
+
const outerElem = this._getOuterElement(child)
|
|
184
|
+
child.setAttribute('aria-selected', isActive)
|
|
185
|
+
|
|
186
|
+
if (outerElem !== child) {
|
|
187
|
+
this._setAttributeIfNotExists(outerElem, 'role', 'presentation')
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (!isActive) {
|
|
191
|
+
child.setAttribute('tabindex', '-1')
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
this._setAttributeIfNotExists(child, 'role', 'tab')
|
|
195
|
+
|
|
196
|
+
// set attributes to the related panel too
|
|
197
|
+
this._setInitialAttributesOnTargetPanel(child)
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
_setInitialAttributesOnTargetPanel(child) {
|
|
201
|
+
const target = SelectorEngine.getElementFromSelector(child)
|
|
202
|
+
|
|
203
|
+
if (!target) {
|
|
204
|
+
return
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
this._setAttributeIfNotExists(target, 'role', 'tabpanel')
|
|
208
|
+
|
|
209
|
+
if (child.id) {
|
|
210
|
+
this._setAttributeIfNotExists(target, 'aria-labelledby', `${child.id}`)
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
_toggleDropDown(element, open) {
|
|
215
|
+
const outerElem = this._getOuterElement(element)
|
|
216
|
+
if (!outerElem.classList.contains(CLASS_DROPDOWN)) {
|
|
217
|
+
return
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const toggle = (selector, className) => {
|
|
221
|
+
const elem = SelectorEngine.findOne(selector, outerElem)
|
|
222
|
+
if (elem) {
|
|
223
|
+
elem.classList.toggle(className, open)
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
toggle(SELECTOR_DROPDOWN_TOGGLE, CLASS_NAME_ACTIVE)
|
|
228
|
+
toggle(SELECTOR_DROPDOWN_MENU, CLASS_NAME_SHOW)
|
|
229
|
+
outerElem.setAttribute('aria-expanded', open)
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
_setAttributeIfNotExists(element, attribute, value) {
|
|
233
|
+
if (!element.hasAttribute(attribute)) {
|
|
234
|
+
element.setAttribute(attribute, value)
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
_elemIsActive(elem) {
|
|
239
|
+
return elem.classList.contains(CLASS_NAME_ACTIVE)
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
_getInnerElement(elem) {
|
|
243
|
+
return elem.matches(SELECTOR_INNER_ELEM) ? elem : SelectorEngine.findOne(SELECTOR_INNER_ELEM, elem)
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
_getOuterElement(elem) {
|
|
247
|
+
return elem.closest(SELECTOR_OUTER) || elem
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
_triggerEvent(element, eventName, detail = {}) {
|
|
251
|
+
const event = new CustomEvent(eventName, {
|
|
252
|
+
bubbles: true,
|
|
253
|
+
cancelable: true,
|
|
254
|
+
detail
|
|
255
|
+
})
|
|
256
|
+
element.dispatchEvent(event)
|
|
257
|
+
return event
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
static getOrCreateInstance(element) {
|
|
261
|
+
return element._baseLineComponent || new Tab(element)
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// Data API implementation
|
|
266
|
+
on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {
|
|
267
|
+
if (['A', 'AREA'].includes(this.tagName)) {
|
|
268
|
+
event.preventDefault()
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
if (isDisabled(this)) {
|
|
272
|
+
return
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
Tab.getOrCreateInstance(this).show()
|
|
276
|
+
})
|
|
277
|
+
|
|
278
|
+
// Initialize on focus
|
|
279
|
+
on(window, EVENT_LOAD_DATA_API, () => {
|
|
280
|
+
for (const element of SelectorEngine.find(SELECTOR_DATA_TOGGLE_ACTIVE)) {
|
|
281
|
+
Tab.getOrCreateInstance(element)
|
|
282
|
+
}
|
|
283
|
+
})
|
|
284
|
+
|
|
285
|
+
export default Tab
|
package/dist/js/toast.js
ADDED
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base-Line Toast Component
|
|
3
|
+
* Baseline 2.0 compatible toast with Base-Line naming
|
|
4
|
+
* Based on Baseline-main architecture
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { BaseComponent } from './base.js'
|
|
8
|
+
import { EventHandler } from './util.js'
|
|
9
|
+
import { enableDismissTrigger } from './util/component-functions.js'
|
|
10
|
+
import { defineJQueryPlugin, reflow } from './util.js'
|
|
11
|
+
|
|
12
|
+
const NAME = 'toast'
|
|
13
|
+
const DATA_KEY = `c.${NAME}`
|
|
14
|
+
const EVENT_KEY = `.${DATA_KEY}`
|
|
15
|
+
|
|
16
|
+
const EVENT_MOUSEOVER = `mouseover${EVENT_KEY}`
|
|
17
|
+
const EVENT_MOUSEOUT = `mouseout${EVENT_KEY}`
|
|
18
|
+
const EVENT_FOCUSIN = `focusin${EVENT_KEY}`
|
|
19
|
+
const EVENT_FOCUSOUT = `focusout${EVENT_KEY}`
|
|
20
|
+
const EVENT_HIDE = `hide${EVENT_KEY}`
|
|
21
|
+
const EVENT_HIDDEN = `hidden${EVENT_KEY}`
|
|
22
|
+
const EVENT_SHOW = `show${EVENT_KEY}`
|
|
23
|
+
const EVENT_SHOWN = `shown${EVENT_KEY}`
|
|
24
|
+
|
|
25
|
+
const CLASS_NAME_FADE = 'c-fade'
|
|
26
|
+
const CLASS_NAME_HIDE = 'c-hide' // @deprecated - kept here only for backwards compatibility
|
|
27
|
+
const CLASS_NAME_SHOW = 'is-show'
|
|
28
|
+
const CLASS_NAME_SHOWING = 'is-showing'
|
|
29
|
+
|
|
30
|
+
const DefaultType = {
|
|
31
|
+
animation: 'boolean',
|
|
32
|
+
autohide: 'boolean',
|
|
33
|
+
delay: 'number'
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const Default = {
|
|
37
|
+
animation: true,
|
|
38
|
+
autohide: true,
|
|
39
|
+
delay: 5000
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Class definition
|
|
44
|
+
*/
|
|
45
|
+
|
|
46
|
+
class Toast extends BaseComponent {
|
|
47
|
+
constructor(element, config) {
|
|
48
|
+
super(element, config)
|
|
49
|
+
|
|
50
|
+
this._timeout = null
|
|
51
|
+
this._hasMouseInteraction = false
|
|
52
|
+
this._hasKeyboardInteraction = false
|
|
53
|
+
this._setListeners()
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Getters
|
|
57
|
+
static get Default() {
|
|
58
|
+
return Default
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
static get DefaultType() {
|
|
62
|
+
return DefaultType
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
static get NAME() {
|
|
66
|
+
return NAME
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Public
|
|
70
|
+
show() {
|
|
71
|
+
const showEvent = EventHandler.trigger(this._element, EVENT_SHOW)
|
|
72
|
+
|
|
73
|
+
if (showEvent.defaultPrevented) {
|
|
74
|
+
return
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
this._clearTimeout()
|
|
78
|
+
|
|
79
|
+
if (this._config.animation) {
|
|
80
|
+
this._element.classList.add(CLASS_NAME_FADE)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const complete = () => {
|
|
84
|
+
this._element.classList.remove(CLASS_NAME_SHOWING)
|
|
85
|
+
EventHandler.trigger(this._element, EVENT_SHOWN)
|
|
86
|
+
|
|
87
|
+
this._maybeScheduleHide()
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
this._element.classList.remove(CLASS_NAME_HIDE) // @deprecated
|
|
91
|
+
reflow(this._element)
|
|
92
|
+
this._element.classList.add(CLASS_NAME_SHOW, CLASS_NAME_SHOWING)
|
|
93
|
+
|
|
94
|
+
this._queueCallback(complete, this._element, this._config.animation)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
hide() {
|
|
98
|
+
if (!this.isShown()) {
|
|
99
|
+
return
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE)
|
|
103
|
+
|
|
104
|
+
if (hideEvent.defaultPrevented) {
|
|
105
|
+
return
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const complete = () => {
|
|
109
|
+
this._element.classList.add(CLASS_NAME_HIDE) // @deprecated
|
|
110
|
+
this._element.classList.remove(CLASS_NAME_SHOWING, CLASS_NAME_SHOW)
|
|
111
|
+
EventHandler.trigger(this._element, EVENT_HIDDEN)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
this._element.classList.add(CLASS_NAME_SHOWING)
|
|
115
|
+
this._queueCallback(complete, this._element, this._config.animation)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
dispose() {
|
|
119
|
+
this._clearTimeout()
|
|
120
|
+
|
|
121
|
+
if (this.isShown()) {
|
|
122
|
+
this._element.classList.remove(CLASS_NAME_SHOW)
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
super.dispose()
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
isShown() {
|
|
129
|
+
return this._element.classList.contains(CLASS_NAME_SHOW)
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Private
|
|
133
|
+
_maybeScheduleHide() {
|
|
134
|
+
if (!this._config.autohide) {
|
|
135
|
+
return
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (this._hasMouseInteraction || this._hasKeyboardInteraction) {
|
|
139
|
+
return
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
this._timeout = setTimeout(() => {
|
|
143
|
+
this.hide()
|
|
144
|
+
}, this._config.delay)
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
_onInteraction(event, isInteracting) {
|
|
148
|
+
switch (event.type) {
|
|
149
|
+
case 'mouseover':
|
|
150
|
+
case 'mouseout': {
|
|
151
|
+
this._hasMouseInteraction = isInteracting
|
|
152
|
+
break
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
case 'focusin':
|
|
156
|
+
case 'focusout': {
|
|
157
|
+
this._hasKeyboardInteraction = isInteracting
|
|
158
|
+
break
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
default: {
|
|
162
|
+
break
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
if (isInteracting) {
|
|
167
|
+
this._clearTimeout()
|
|
168
|
+
return
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const nextElement = event.relatedTarget
|
|
172
|
+
if (this._element === nextElement || this._element.contains(nextElement)) {
|
|
173
|
+
return
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
this._maybeScheduleHide()
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
_setListeners() {
|
|
180
|
+
EventHandler.on(this._element, EVENT_MOUSEOVER, event => this._onInteraction(event, true))
|
|
181
|
+
EventHandler.on(this._element, EVENT_MOUSEOUT, event => this._onInteraction(event, false))
|
|
182
|
+
EventHandler.on(this._element, EVENT_FOCUSIN, event => this._onInteraction(event, true))
|
|
183
|
+
EventHandler.on(this._element, EVENT_FOCUSOUT, event => this._onInteraction(event, false))
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
_clearTimeout() {
|
|
187
|
+
clearTimeout(this._timeout)
|
|
188
|
+
this._timeout = null
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Static
|
|
192
|
+
static getOrCreateInstance(element, config = {}) {
|
|
193
|
+
return element._baseLineComponent || new Toast(element, config)
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
static getInstance(element) {
|
|
197
|
+
return element._baseLineComponent || null
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
static jQueryInterface(config) {
|
|
201
|
+
return this.each(function () {
|
|
202
|
+
const data = Toast.getOrCreateInstance(this, config)
|
|
203
|
+
|
|
204
|
+
if (typeof config === 'string') {
|
|
205
|
+
if (typeof data[config] === 'undefined') {
|
|
206
|
+
throw new TypeError(`No method named "${config}"`)
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
data[config]()
|
|
210
|
+
}
|
|
211
|
+
})
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Data API implementation
|
|
217
|
+
*/
|
|
218
|
+
|
|
219
|
+
enableDismissTrigger(Toast)
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* jQuery
|
|
223
|
+
*/
|
|
224
|
+
|
|
225
|
+
defineJQueryPlugin(Toast)
|
|
226
|
+
|
|
227
|
+
export default Toast
|
|
228
|
+
|