@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.
Files changed (80) hide show
  1. package/README.md +472 -0
  2. package/dist/base-line.css +5 -0
  3. package/dist/base-line.css.map +1 -0
  4. package/dist/fonts/GoogleSansCode-Bold.ttf +0 -0
  5. package/dist/fonts/GoogleSansCode-BoldItalic.ttf +0 -0
  6. package/dist/fonts/GoogleSansCode-ExtraBold.ttf +0 -0
  7. package/dist/fonts/GoogleSansCode-ExtraBoldItalic.ttf +0 -0
  8. package/dist/fonts/GoogleSansCode-Italic-VariableFont_wght.ttf +0 -0
  9. package/dist/fonts/GoogleSansCode-Italic.ttf +0 -0
  10. package/dist/fonts/GoogleSansCode-Light.ttf +0 -0
  11. package/dist/fonts/GoogleSansCode-LightItalic.ttf +0 -0
  12. package/dist/fonts/GoogleSansCode-Medium.ttf +0 -0
  13. package/dist/fonts/GoogleSansCode-MediumItalic.ttf +0 -0
  14. package/dist/fonts/GoogleSansCode-Regular.ttf +0 -0
  15. package/dist/fonts/GoogleSansCode-SemiBold.ttf +0 -0
  16. package/dist/fonts/GoogleSansCode-SemiBoldItalic.ttf +0 -0
  17. package/dist/fonts/GoogleSansCode-VariableFont_wght.ttf +0 -0
  18. package/dist/fonts/RobotoCondensed-Black.ttf +0 -0
  19. package/dist/fonts/RobotoCondensed-BlackItalic.ttf +0 -0
  20. package/dist/fonts/RobotoCondensed-Bold.ttf +0 -0
  21. package/dist/fonts/RobotoCondensed-BoldItalic.ttf +0 -0
  22. package/dist/fonts/RobotoCondensed-ExtraBold.ttf +0 -0
  23. package/dist/fonts/RobotoCondensed-ExtraBoldItalic.ttf +0 -0
  24. package/dist/fonts/RobotoCondensed-ExtraLight.ttf +0 -0
  25. package/dist/fonts/RobotoCondensed-ExtraLightItalic.ttf +0 -0
  26. package/dist/fonts/RobotoCondensed-Italic-VariableFont_wght.ttf +0 -0
  27. package/dist/fonts/RobotoCondensed-Italic.ttf +0 -0
  28. package/dist/fonts/RobotoCondensed-Light.ttf +0 -0
  29. package/dist/fonts/RobotoCondensed-LightItalic.ttf +0 -0
  30. package/dist/fonts/RobotoCondensed-Medium.ttf +0 -0
  31. package/dist/fonts/RobotoCondensed-MediumItalic.ttf +0 -0
  32. package/dist/fonts/RobotoCondensed-Regular.ttf +0 -0
  33. package/dist/fonts/RobotoCondensed-SemiBold.ttf +0 -0
  34. package/dist/fonts/RobotoCondensed-SemiBoldItalic.ttf +0 -0
  35. package/dist/fonts/RobotoCondensed-Thin.ttf +0 -0
  36. package/dist/fonts/RobotoCondensed-ThinItalic.ttf +0 -0
  37. package/dist/fonts/RobotoCondensed-VariableFont_wght.ttf +0 -0
  38. package/dist/fonts/ZalandoSansExpanded-Black.ttf +0 -0
  39. package/dist/fonts/ZalandoSansExpanded-BlackItalic.ttf +0 -0
  40. package/dist/fonts/ZalandoSansExpanded-Bold.ttf +0 -0
  41. package/dist/fonts/ZalandoSansExpanded-BoldItalic.ttf +0 -0
  42. package/dist/fonts/ZalandoSansExpanded-ExtraBold.ttf +0 -0
  43. package/dist/fonts/ZalandoSansExpanded-ExtraBoldItalic.ttf +0 -0
  44. package/dist/fonts/ZalandoSansExpanded-ExtraLight.ttf +0 -0
  45. package/dist/fonts/ZalandoSansExpanded-ExtraLightItalic.ttf +0 -0
  46. package/dist/fonts/ZalandoSansExpanded-Italic-VariableFont_wght.ttf +0 -0
  47. package/dist/fonts/ZalandoSansExpanded-Italic.ttf +0 -0
  48. package/dist/fonts/ZalandoSansExpanded-Light.ttf +0 -0
  49. package/dist/fonts/ZalandoSansExpanded-LightItalic.ttf +0 -0
  50. package/dist/fonts/ZalandoSansExpanded-Medium.ttf +0 -0
  51. package/dist/fonts/ZalandoSansExpanded-MediumItalic.ttf +0 -0
  52. package/dist/fonts/ZalandoSansExpanded-Regular.ttf +0 -0
  53. package/dist/fonts/ZalandoSansExpanded-SemiBold.ttf +0 -0
  54. package/dist/fonts/ZalandoSansExpanded-SemiBoldItalic.ttf +0 -0
  55. package/dist/fonts/ZalandoSansExpanded-VariableFont_wght.ttf +0 -0
  56. package/dist/fonts/baseline-icons.woff +0 -0
  57. package/dist/fonts/baseline-icons.woff2 +0 -0
  58. package/dist/js/accordion.js +103 -0
  59. package/dist/js/alert.js +91 -0
  60. package/dist/js/base.js +146 -0
  61. package/dist/js/button.js +80 -0
  62. package/dist/js/carousel.js +427 -0
  63. package/dist/js/collapse.js +233 -0
  64. package/dist/js/color-modes.js +70 -0
  65. package/dist/js/component.js +114 -0
  66. package/dist/js/dropdown.js +348 -0
  67. package/dist/js/index.js +108 -0
  68. package/dist/js/modal.js +440 -0
  69. package/dist/js/offcanvas.js +356 -0
  70. package/dist/js/popover.js +241 -0
  71. package/dist/js/swipe.js +143 -0
  72. package/dist/js/tab.js +285 -0
  73. package/dist/js/toast.js +228 -0
  74. package/dist/js/tooltip.js +716 -0
  75. package/dist/js/util/backdrop.js +133 -0
  76. package/dist/js/util/component-functions.js +111 -0
  77. package/dist/js/util/focustrap.js +101 -0
  78. package/dist/js/util/scrollbar.js +111 -0
  79. package/dist/js/util.js +564 -0
  80. package/package.json +47 -0
@@ -0,0 +1,356 @@
1
+ /**
2
+ * Base-Line Offcanvas Component
3
+ * Baseline 2.0 compatible offcanvas with Base-Line naming
4
+ */
5
+
6
+ import { BaseComponent } from './base.js'
7
+ import { getElement, getElements, on, off, one, executeAfterTransition, reflow, getElementFromSelector, isDisabled, isVisible } from './util.js'
8
+ import { addClass, removeClass, hasClass } from './component.js'
9
+ import { enableDismissTrigger } from './util/component-functions.js'
10
+
11
+ const NAME = 'offcanvas'
12
+ const DATA_KEY = `c.${NAME}`
13
+ const EVENT_KEY = `.${DATA_KEY}`
14
+ const DATA_API_KEY = '.data-api'
15
+
16
+ const EVENT_SHOW = `show${EVENT_KEY}`
17
+ const EVENT_SHOWN = `shown${EVENT_KEY}`
18
+ const EVENT_HIDE = `hide${EVENT_KEY}`
19
+ const EVENT_HIDE_PREVENTED = `hidePrevented${EVENT_KEY}`
20
+ const EVENT_HIDDEN = `hidden${EVENT_KEY}`
21
+ const EVENT_RESIZE = `resize${EVENT_KEY}`
22
+ const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`
23
+ const EVENT_KEYDOWN_DISMISS = `keydown.dismiss${EVENT_KEY}`
24
+ const EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`
25
+
26
+ const ESCAPE_KEY = 'Escape'
27
+
28
+ const CLASS_NAME_SHOW = 'show'
29
+ const CLASS_NAME_SHOWING = 'showing'
30
+ const CLASS_NAME_HIDING = 'hiding'
31
+ const CLASS_NAME_BACKDROP = 'c-offcanvas-backdrop'
32
+ const OPEN_SELECTOR = '.c-offcanvas.show'
33
+
34
+ const SELECTOR_DATA_TOGGLE = '[data-c-toggle="offcanvas"]'
35
+ const SELECTOR_DATA_DISMISS = '[data-c-dismiss="offcanvas"]'
36
+
37
+ const Default = {
38
+ backdrop: true,
39
+ keyboard: true,
40
+ scroll: false
41
+ }
42
+
43
+ class Offcanvas extends BaseComponent {
44
+ constructor(element, config) {
45
+ super(element, config)
46
+ // Sync initial state with DOM - check if element already has 'show' class
47
+ const hasShowClass = element.classList.contains(CLASS_NAME_SHOW)
48
+ this._isShown = hasShowClass
49
+
50
+ // If element already has 'show' class, check if there's an existing backdrop in the DOM
51
+ if (hasShowClass) {
52
+ const existingBackdrop = element.parentElement?.querySelector(`.${CLASS_NAME_BACKDROP}`)
53
+ if (existingBackdrop) {
54
+ // Create backdrop instance but reuse the existing DOM element
55
+ this._backdrop = this._initializeBackDrop()
56
+ // Manually set the backdrop element to the existing one
57
+ this._backdrop._element = existingBackdrop
58
+ } else {
59
+ this._backdrop = this._initializeBackDrop()
60
+ }
61
+ } else {
62
+ this._backdrop = this._initializeBackDrop()
63
+ }
64
+
65
+ this._addEventListeners()
66
+ }
67
+
68
+ _configAfterMerge(config) {
69
+ // Read data attributes
70
+ const scroll = this._element.getAttribute('data-c-scroll')
71
+ const backdrop = this._element.getAttribute('data-c-backdrop')
72
+
73
+ if (scroll !== null) {
74
+ config.scroll = scroll === 'true'
75
+ }
76
+
77
+ if (backdrop !== null) {
78
+ config.backdrop = backdrop === 'true' ? true : backdrop === 'false' ? false : backdrop
79
+ }
80
+
81
+ return config
82
+ }
83
+
84
+ static get NAME() {
85
+ return NAME
86
+ }
87
+
88
+ static get Default() {
89
+ return Default
90
+ }
91
+
92
+ // Public
93
+ toggle(relatedTarget) {
94
+ return this._isShown ? this.hide() : this.show(relatedTarget)
95
+ }
96
+
97
+ show(relatedTarget) {
98
+ if (this._isShown) {
99
+ return
100
+ }
101
+
102
+ const showEvent = new CustomEvent(EVENT_SHOW, {
103
+ bubbles: true,
104
+ cancelable: true,
105
+ detail: { relatedTarget }
106
+ })
107
+
108
+ this._element.dispatchEvent(showEvent)
109
+
110
+ if (showEvent.defaultPrevented) {
111
+ return
112
+ }
113
+
114
+ this._isShown = true
115
+ this._backdrop.show()
116
+
117
+ if (!this._config.scroll) {
118
+ document.body.style.overflow = 'hidden'
119
+ }
120
+
121
+ this._element.setAttribute('aria-modal', 'true')
122
+ this._element.setAttribute('role', 'dialog')
123
+ addClass(this._element, CLASS_NAME_SHOWING)
124
+
125
+ const completeCallback = () => {
126
+ addClass(this._element, CLASS_NAME_SHOW)
127
+ removeClass(this._element, CLASS_NAME_SHOWING)
128
+ const shownEvent = new CustomEvent(EVENT_SHOWN, {
129
+ bubbles: true,
130
+ detail: { relatedTarget }
131
+ })
132
+ this._element.dispatchEvent(shownEvent)
133
+ }
134
+
135
+ this._queueCallback(completeCallback, this._element, true)
136
+ }
137
+
138
+ hide() {
139
+ // Check if element has 'show' class even if _isShown is false (state might be out of sync)
140
+ const hasShowClass = this._element.classList.contains(CLASS_NAME_SHOW)
141
+
142
+ if (!this._isShown && !hasShowClass) {
143
+ return
144
+ }
145
+
146
+ // If element has show class but _isShown is false, sync the state
147
+ if (!this._isShown && hasShowClass) {
148
+ this._isShown = true
149
+ }
150
+
151
+ const hideEvent = new CustomEvent(EVENT_HIDE, {
152
+ bubbles: true,
153
+ cancelable: true
154
+ })
155
+
156
+ this._element.dispatchEvent(hideEvent)
157
+
158
+ if (hideEvent.defaultPrevented) {
159
+ return
160
+ }
161
+
162
+ this._element.blur()
163
+ this._isShown = false
164
+ addClass(this._element, CLASS_NAME_HIDING)
165
+ if (this._backdrop && typeof this._backdrop.hide === 'function') {
166
+ this._backdrop.hide()
167
+ }
168
+
169
+ const completeCallback = () => {
170
+ removeClass(this._element, CLASS_NAME_SHOW)
171
+ removeClass(this._element, CLASS_NAME_HIDING)
172
+ this._element.removeAttribute('aria-modal')
173
+ this._element.removeAttribute('role')
174
+
175
+ if (!this._config.scroll) {
176
+ document.body.style.overflow = ''
177
+ }
178
+
179
+ const hiddenEvent = new CustomEvent(EVENT_HIDDEN, {
180
+ bubbles: true
181
+ })
182
+ this._element.dispatchEvent(hiddenEvent)
183
+ }
184
+
185
+ this._queueCallback(completeCallback, this._element, true)
186
+ }
187
+
188
+ dispose() {
189
+ this._backdrop.dispose()
190
+ super.dispose()
191
+ }
192
+
193
+ // Private
194
+ _initializeBackDrop() {
195
+ const clickCallback = () => {
196
+ if (this._config.backdrop === 'static') {
197
+ const hidePreventedEvent = new CustomEvent(EVENT_HIDE_PREVENTED, {
198
+ bubbles: true
199
+ })
200
+ this._element.dispatchEvent(hidePreventedEvent)
201
+ return
202
+ }
203
+
204
+ this.hide()
205
+ }
206
+
207
+ const isVisible = Boolean(this._config.backdrop)
208
+
209
+ return new Backdrop({
210
+ className: CLASS_NAME_BACKDROP,
211
+ isVisible,
212
+ isAnimated: true,
213
+ rootElement: this._element.parentNode,
214
+ clickCallback: isVisible ? clickCallback : null
215
+ })
216
+ }
217
+
218
+ _addEventListeners() {
219
+ on(this._element, EVENT_KEYDOWN_DISMISS, (event) => {
220
+ if (event.key !== ESCAPE_KEY) {
221
+ return
222
+ }
223
+
224
+ if (this._config.keyboard) {
225
+ this.hide()
226
+ return
227
+ }
228
+
229
+ const hidePreventedEvent = new CustomEvent(EVENT_HIDE_PREVENTED, {
230
+ bubbles: true
231
+ })
232
+ this._element.dispatchEvent(hidePreventedEvent)
233
+ })
234
+ }
235
+
236
+ static getOrCreateInstance(element, config = {}) {
237
+ if (element._baseLineComponent) {
238
+ // Sync state with DOM if instance already exists
239
+ const hasShowClass = element.classList.contains(CLASS_NAME_SHOW)
240
+ if (hasShowClass && !element._baseLineComponent._isShown) {
241
+ element._baseLineComponent._isShown = true
242
+ } else if (!hasShowClass && element._baseLineComponent._isShown) {
243
+ element._baseLineComponent._isShown = false
244
+ }
245
+ return element._baseLineComponent
246
+ }
247
+ return new Offcanvas(element, config)
248
+ }
249
+ }
250
+
251
+ // Backdrop helper class
252
+ class Backdrop {
253
+ constructor(config) {
254
+ this._config = config
255
+ this._element = null
256
+ }
257
+
258
+ show() {
259
+ if (!this._config.isVisible) {
260
+ return
261
+ }
262
+
263
+ if (!this._element) {
264
+ this._element = document.createElement('div')
265
+ this._element.className = `${this._config.className} c-fade`
266
+ if (this._config.rootElement) {
267
+ this._config.rootElement.appendChild(this._element)
268
+ } else {
269
+ document.body.appendChild(this._element)
270
+ }
271
+ }
272
+
273
+ reflow(this._element)
274
+
275
+ if (this._config.clickCallback) {
276
+ on(this._element, 'click', this._config.clickCallback)
277
+ }
278
+
279
+ addClass(this._element, 'show')
280
+ }
281
+
282
+ hide() {
283
+ if (!this._element) {
284
+ return
285
+ }
286
+
287
+ removeClass(this._element, 'show')
288
+
289
+ if (this._config.isAnimated) {
290
+ executeAfterTransition(() => {
291
+ this.dispose()
292
+ }, this._element)
293
+ } else {
294
+ this.dispose()
295
+ }
296
+ }
297
+
298
+ dispose() {
299
+ if (this._element) {
300
+ this._element.remove()
301
+ this._element = null
302
+ }
303
+ }
304
+ }
305
+
306
+ // Data API implementation
307
+ on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {
308
+ const target = getElementFromSelector(this)
309
+
310
+ if (['A', 'AREA'].includes(this.tagName)) {
311
+ event.preventDefault()
312
+ }
313
+
314
+ if (isDisabled(this)) {
315
+ return
316
+ }
317
+
318
+ one(target, EVENT_HIDDEN, () => {
319
+ // focus on trigger when it is closed
320
+ if (isVisible(this)) {
321
+ this.focus()
322
+ }
323
+ })
324
+
325
+ // avoid conflict when clicking a toggler of an offcanvas, while another is open
326
+ const alreadyOpen = getElement(OPEN_SELECTOR)
327
+ if (alreadyOpen && alreadyOpen !== target) {
328
+ Offcanvas.getOrCreateInstance(alreadyOpen).hide()
329
+ }
330
+
331
+ const data = Offcanvas.getOrCreateInstance(target)
332
+ data.toggle(this)
333
+ })
334
+
335
+ // Initialize on load
336
+ on(window, EVENT_LOAD_DATA_API, () => {
337
+ const elements = getElements(OPEN_SELECTOR)
338
+ for (const element of elements) {
339
+ Offcanvas.getOrCreateInstance(element).show()
340
+ }
341
+ })
342
+
343
+ // Handle resize
344
+ on(window, EVENT_RESIZE, () => {
345
+ const elements = getElements('[aria-modal][class*=show][class*=c-offcanvas-]')
346
+ for (const element of elements) {
347
+ if (window.getComputedStyle(element).position !== 'fixed') {
348
+ Offcanvas.getOrCreateInstance(element).hide()
349
+ }
350
+ }
351
+ })
352
+
353
+ // Enable dismiss trigger
354
+ enableDismissTrigger(Offcanvas)
355
+
356
+ export default Offcanvas
@@ -0,0 +1,241 @@
1
+ /**
2
+ * Base-Line Popover Component
3
+ * Baseline 2.0 compatible popover with Base-Line naming
4
+ * Based on Baseline-main architecture
5
+ */
6
+
7
+ import Tooltip from './tooltip.js'
8
+
9
+ const NAME = 'popover'
10
+ const DATA_KEY = `c.${NAME}`
11
+ const EVENT_KEY = `.${DATA_KEY}`
12
+
13
+ const SELECTOR_TITLE = '.c-popover-header'
14
+ const SELECTOR_CONTENT = '.c-popover-body'
15
+
16
+ class Popover extends Tooltip {
17
+ constructor(element, config) {
18
+ super(element, {
19
+ ...config,
20
+ template: '<div class="c-popover" role="tooltip"><div class="c-popover-arrow"></div><h3 class="c-popover-header"></h3><div class="c-popover-body"></div></div>'
21
+ })
22
+ }
23
+
24
+ static get NAME() {
25
+ return NAME
26
+ }
27
+
28
+ // Overrides
29
+ _isWithContent() {
30
+ return Boolean(this._getTitle() || this._getContent())
31
+ }
32
+
33
+ _getContentForTemplate() {
34
+ return {
35
+ [SELECTOR_TITLE]: this._getTitle(),
36
+ [SELECTOR_CONTENT]: this._getContent()
37
+ }
38
+ }
39
+
40
+ _copyCustomStyles(tip) {
41
+ // Copy CSS variables from trigger element to popover
42
+ // This allows custom styling via CSS variables on the trigger element
43
+ const elementStyle = this._element.style
44
+ const computedStyle = window.getComputedStyle(this._element)
45
+ const popoverStyles = tip.style
46
+ const header = tip.querySelector(SELECTOR_TITLE)
47
+ const body = tip.querySelector(SELECTOR_CONTENT)
48
+
49
+ // Get all CSS variables that start with --bl-popover-
50
+ // First check inline styles (for React style props)
51
+ const cssVariables = new Set()
52
+
53
+ // Check inline styles
54
+ for (let i = 0; i < elementStyle.length; i++) {
55
+ const property = elementStyle[i]
56
+ if (property.startsWith('--bl-popover-')) {
57
+ cssVariables.add(property)
58
+ }
59
+ }
60
+
61
+ // Also check computed styles (for CSS classes)
62
+ for (let i = 0; i < computedStyle.length; i++) {
63
+ const property = computedStyle[i]
64
+ if (property.startsWith('--bl-popover-')) {
65
+ cssVariables.add(property)
66
+ }
67
+ }
68
+
69
+ // Copy each CSS variable to the popover element
70
+ // Inline styles have higher specificity than CSS classes, so they will override dark mode
71
+ cssVariables.forEach(variable => {
72
+ // Prefer inline style value, fallback to computed style
73
+ const value = elementStyle.getPropertyValue(variable) || computedStyle.getPropertyValue(variable)
74
+ if (value) {
75
+ // Set on popover element - CSS variables will be inherited by header and body
76
+ popoverStyles.setProperty(variable, value)
77
+
78
+ // Also set directly on header/body if they are header/body specific variables
79
+ // This ensures they override dark mode styles even if inheritance doesn't work
80
+ if (variable.includes('header') && header) {
81
+ header.style.setProperty(variable, value)
82
+ } else if (variable.includes('body') && body) {
83
+ body.style.setProperty(variable, value)
84
+ }
85
+ }
86
+ })
87
+ }
88
+
89
+ _createTipElement(content) {
90
+ const tip = super._createTipElement(content)
91
+
92
+ // Copy custom CSS variables from trigger element
93
+ this._copyCustomStyles(tip)
94
+
95
+ // Set content for popover header and body
96
+ if (content && typeof content === 'object') {
97
+ const header = tip.querySelector(SELECTOR_TITLE)
98
+ const body = tip.querySelector(SELECTOR_CONTENT)
99
+
100
+ if (header) {
101
+ const titleContent = content[SELECTOR_TITLE] || ''
102
+ if (titleContent) {
103
+ if (this._config.html) {
104
+ header.innerHTML = titleContent
105
+ } else {
106
+ header.textContent = titleContent
107
+ }
108
+ header.style.display = ''
109
+ } else {
110
+ header.style.display = 'none'
111
+ }
112
+ }
113
+
114
+ if (body) {
115
+ const bodyContent = content[SELECTOR_CONTENT] || ''
116
+ if (this._config.html) {
117
+ body.innerHTML = bodyContent
118
+ } else {
119
+ body.textContent = bodyContent
120
+ }
121
+ }
122
+ }
123
+
124
+ return tip
125
+ }
126
+
127
+ _getTitle() {
128
+ return this._resolvePossibleFunction(this._config.title) ||
129
+ this._element.getAttribute('data-c-title') ||
130
+ this._element.getAttribute('data-bl-title') ||
131
+ super._getTitle() ||
132
+ ''
133
+ }
134
+
135
+ _getContent() {
136
+ return this._resolvePossibleFunction(this._config.content) ||
137
+ this._element.getAttribute('data-c-content') ||
138
+ this._element.getAttribute('data-bl-content') ||
139
+ this._element.getAttribute('data-c-body') ||
140
+ ''
141
+ }
142
+
143
+ show() {
144
+ super.show()
145
+
146
+ // Ensure custom CSS variables are applied after showing
147
+ // This ensures they override dark mode styles
148
+ // Use requestAnimationFrame to ensure DOM is ready
149
+ if (this.tip) {
150
+ requestAnimationFrame(() => {
151
+ this._copyCustomStyles(this.tip)
152
+ })
153
+ }
154
+ }
155
+
156
+ setContent(content) {
157
+ this._newContent = typeof content === 'object' ? content : {
158
+ [SELECTOR_TITLE]: this._getTitle(),
159
+ [SELECTOR_CONTENT]: content
160
+ }
161
+ if (this._isShown()) {
162
+ this._disposePopper()
163
+ this.show()
164
+ }
165
+ }
166
+
167
+ static get Default() {
168
+ return {
169
+ ...Tooltip.Default,
170
+ content: '',
171
+ offset: [0, 8],
172
+ placement: 'right',
173
+ template: '<div class="c-popover" role="tooltip"><div class="c-popover-arrow"></div><h3 class="c-popover-header"></h3><div class="c-popover-body"></div></div>',
174
+ trigger: 'click'
175
+ }
176
+ }
177
+
178
+ static get DefaultType() {
179
+ return {
180
+ ...Tooltip.DefaultType,
181
+ content: '(null|string|element|function)'
182
+ }
183
+ }
184
+
185
+ static getOrCreateInstance(element, config = {}) {
186
+ if (!element._baseLineComponent) {
187
+ element._baseLineComponent = new Popover(element, config)
188
+ }
189
+ return element._baseLineComponent
190
+ }
191
+ }
192
+
193
+ /**
194
+ * Data API implementation
195
+ */
196
+
197
+ // Support both data-c-toggle="popover" and data-bl-toggle="popover"
198
+ const SELECTOR_DATA_TOGGLE = '[data-c-toggle="popover"]'
199
+ const SELECTOR_DATA_TOGGLE_BS = '[data-bl-toggle="popover"]'
200
+
201
+ // Initialize popovers on DOM ready
202
+ import { onDOMContentLoaded } from './util.js'
203
+
204
+ onDOMContentLoaded(() => {
205
+ const popoverElements = document.querySelectorAll(`${SELECTOR_DATA_TOGGLE}, ${SELECTOR_DATA_TOGGLE_BS}`)
206
+ popoverElements.forEach(element => {
207
+ if (!element._baseLineComponent) {
208
+ const title = element.getAttribute('data-c-title') ||
209
+ element.getAttribute('data-bl-title') ||
210
+ element.getAttribute('title')
211
+ const content = element.getAttribute('data-c-content') ||
212
+ element.getAttribute('data-bl-content')
213
+ const placement = element.getAttribute('data-c-placement') ||
214
+ element.getAttribute('data-bl-placement') ||
215
+ 'right'
216
+ const container = element.getAttribute('data-c-container') ||
217
+ element.getAttribute('data-bl-container') ||
218
+ false
219
+ const html = element.getAttribute('data-c-html') === 'true' ||
220
+ element.getAttribute('data-bl-html') === 'true' ||
221
+ false
222
+ const trigger = element.getAttribute('data-c-trigger') ||
223
+ element.getAttribute('data-bl-trigger') ||
224
+ 'click'
225
+
226
+ if (title || content) {
227
+ Popover.getOrCreateInstance(element, {
228
+ title: title,
229
+ content: content,
230
+ placement: placement,
231
+ container: container,
232
+ html: html,
233
+ trigger: trigger
234
+ })
235
+ }
236
+ }
237
+ })
238
+ })
239
+
240
+ export default Popover
241
+