Compare commits

...

14 Commits

Author SHA1 Message Date
GeoSot 680b933f68 add more 2022-09-17 18:39:50 +03:00
GeoSot ce6a22159a Try web components. Proof of concept 2022-09-16 02:33:57 +03:00
Jérémie Broutier 6f65df4fae Fix modal event listeners (#37128)
* Fix modal event listeners (#37126)

Co-authored-by: GeoSot <geo.sotis@gmail.com>
2022-09-15 13:30:51 +03:00
GeoSot aedd7fb9de Docs: Add informative note for Tooltip/Popover selector option (#37142)
Co-authored-by: Julien Déramond <juderamond@gmail.com>
2022-09-14 22:03:39 +02:00
Gabriel R. Barbosa 9af1232c65 Docs: Fix typo Getting Started > Vite and Webpack guides (#37153)
* 'were to look' → 'where to look'

Co-authored-by: Julien Déramond <juderamond@gmail.com>
2022-09-14 21:28:10 +02:00
GeoSot 3bd5756414 fix: add trick to support tooltip selector usage on dynamic created tooltips that utilize title attribute (#36914) 2022-09-14 16:24:37 +03:00
Julien Déramond 4600a25404 Docs: minor fix for Navbar > Offcanvas examples (#37145) 2022-09-14 16:11:14 +03:00
dependabot[bot] a1b1e43ddc Bump @rollup/plugin-node-resolve from 13.3.0 to 14.1.0 (#37135)
Bumps [@rollup/plugin-node-resolve](https://github.com/rollup/plugins/tree/HEAD/packages/node-resolve) from 13.3.0 to 14.1.0.
- [Release notes](https://github.com/rollup/plugins/releases)
- [Changelog](https://github.com/rollup/plugins/blob/master/packages/node-resolve/CHANGELOG.md)
- [Commits](https://github.com/rollup/plugins/commits/node-resolve-v14.1.0/packages/node-resolve)

---
updated-dependencies:
- dependency-name: "@rollup/plugin-node-resolve"
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-09-13 19:38:31 +03:00
dependabot[bot] b5ee6694c1 Bump eslint from 8.23.0 to 8.23.1 (#37134)
Bumps [eslint](https://github.com/eslint/eslint) from 8.23.0 to 8.23.1.
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v8.23.0...v8.23.1)

---
updated-dependencies:
- dependency-name: eslint
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: XhmikosR <xhmikosr@gmail.com>
2022-09-13 19:37:36 +03:00
dependabot[bot] d6a38b347f Bump autoprefixer from 10.4.8 to 10.4.10 (#37140)
Bumps [autoprefixer](https://github.com/postcss/autoprefixer) from 10.4.8 to 10.4.10.
- [Release notes](https://github.com/postcss/autoprefixer/releases)
- [Changelog](https://github.com/postcss/autoprefixer/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/autoprefixer/compare/10.4.8...10.4.10)

---
updated-dependencies:
- dependency-name: autoprefixer
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-09-13 19:34:32 +03:00
dependabot[bot] 9cee77919d Bump sass from 1.54.8 to 1.54.9 (#37133)
Bumps [sass](https://github.com/sass/dart-sass) from 1.54.8 to 1.54.9.
- [Release notes](https://github.com/sass/dart-sass/releases)
- [Changelog](https://github.com/sass/dart-sass/blob/main/CHANGELOG.md)
- [Commits](https://github.com/sass/dart-sass/compare/1.54.8...1.54.9)

---
updated-dependencies:
- dependency-name: sass
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-09-13 19:32:12 +03:00
dependabot[bot] 6e55fa9297 Bump @babel/core from 7.18.13 to 7.19.0 (#37090)
Bumps [@babel/core](https://github.com/babel/babel/tree/HEAD/packages/babel-core) from 7.18.13 to 7.19.0.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.19.0/packages/babel-core)

---
updated-dependencies:
- dependency-name: "@babel/core"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-09-09 18:26:35 +03:00
dependabot[bot] 74184f8c61 Bump @babel/preset-env from 7.18.10 to 7.19.0 (#37088)
Bumps [@babel/preset-env](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env) from 7.18.10 to 7.19.0.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.19.0/packages/babel-preset-env)

---
updated-dependencies:
- dependency-name: "@babel/preset-env"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-09-09 18:22:57 +03:00
dependabot[bot] bcfc8d0d63 Bump stylelint-config-twbs-bootstrap from 5.0.0 to 6.0.0 (#37087)
Bumps [stylelint-config-twbs-bootstrap](https://github.com/twbs/stylelint-config-twbs-bootstrap) from 5.0.0 to 6.0.0.
- [Release notes](https://github.com/twbs/stylelint-config-twbs-bootstrap/releases)
- [Commits](https://github.com/twbs/stylelint-config-twbs-bootstrap/compare/v5.0.0...v6.0.0)

---
updated-dependencies:
- dependency-name: stylelint-config-twbs-bootstrap
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: XhmikosR <xhmikosr@gmail.com>
2022-09-09 18:17:11 +03:00
17 changed files with 642 additions and 318 deletions
+4
View File
@@ -5,6 +5,8 @@
* --------------------------------------------------------------------------
*/
import Toa from './src/toa'
export { default as Alert } from './src/alert'
export { default as Button } from './src/button'
export { default as Carousel } from './src/carousel'
@@ -17,3 +19,5 @@ export { default as ScrollSpy } from './src/scrollspy'
export { default as Tab } from './src/tab'
export { default as Toast } from './src/toast'
export { default as Tooltip } from './src/tooltip'
window.customElements.define('bs-toa', Toa)
+3
View File
@@ -16,6 +16,7 @@ import Popover from './src/popover'
import ScrollSpy from './src/scrollspy'
import Tab from './src/tab'
import Toast from './src/toast'
import Toa from './src/toa'
import Tooltip from './src/tooltip'
export default {
@@ -32,3 +33,5 @@ export default {
Toast,
Tooltip
}
window.customElements.define('bs-toa', Toa)
+35
View File
@@ -0,0 +1,35 @@
import { executeAfterTransition } from './util/index'
import Manipulator from './dom/manipulator'
class Base extends HTMLElement {
constructor(config) {
super()
this._config = this._mergeConfigObj(config, this)
}
_queueCallback(callback, element, isAnimated = true) {
executeAfterTransition(callback, element, isAnimated)
}
static get DATA_KEY() {
return `bs.${this.NAME}`
}
static get EVENT_KEY() {
return `.${this.DATA_KEY}`
}
_mergeConfigObj(config, element) {
const jsonConfig = Manipulator.getDataAttribute(element, 'config') // try to parse
return {
...this.constructor.Default,
...(typeof jsonConfig === 'object' ? jsonConfig : {}),
...Manipulator.getDataAttributes(element),
...(typeof config === 'object' ? config : {})
}
}
}
export default Base
+2 -2
View File
@@ -223,9 +223,9 @@ class Modal extends BaseComponent {
})
EventHandler.on(this._element, EVENT_MOUSEDOWN_DISMISS, event => {
// a bad trick to segregate clicks that may start inside dialog but end outside, and avoid listen to scrollbar clicks
EventHandler.one(this._element, EVENT_CLICK_DISMISS, event2 => {
// a bad trick to segregate clicks that may start inside dialog but end outside, and avoid listen to scrollbar clicks
if (this._dialog.contains(event.target) || this._dialog.contains(event2.target)) {
if (this._element !== event.target || this._element !== event2.target) {
return
}
+191
View File
@@ -0,0 +1,191 @@
/**
* --------------------------------------------------------------------------
* Bootstrap (v5.2.1): toa.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
import Base from './base'
import EventHandler from './dom/event-handler'
const NAME = 'toast'
const DATA_KEY = 'bs.toast'
const EVENT_KEY = `.${DATA_KEY}`
const EVENT_MOUSEOVER = `mouseover${EVENT_KEY}`
const EVENT_MOUSEOUT = `mouseout${EVENT_KEY}`
const EVENT_FOCUSIN = `focusin${EVENT_KEY}`
const EVENT_FOCUSOUT = `focusout${EVENT_KEY}`
const EVENT_HIDE = `hide${EVENT_KEY}`
const EVENT_HIDDEN = `hidden${EVENT_KEY}`
const EVENT_SHOW = `show${EVENT_KEY}`
const EVENT_SHOWN = `shown${EVENT_KEY}`
const CLASS_NAME_FADE = 'fade'
const CLASS_NAME_HIDE = 'hide' // @deprecated - kept here only for backwards compatibility
const CLASS_NAME_SHOW = 'show'
const CLASS_NAME_SHOWING = 'showing'
//
// const TEMPLATE = '<slot></slot>'
const DefaultType = {
animation: 'boolean',
autohide: 'boolean',
delay: 'number'
}
const Default = {
animation: true,
autohide: true,
delay: 5000
}
export default class Toa extends Base {
constructor() {
super()
console.log(this._config) // eslint-disable-line no-console
this.classList.add('toast', 'p-2')
this.setAttribute('role', 'alert')
this.setAttribute('aria-live', 'assertlive')
this.setAttribute('aria-atomic', 'true')
this._timeout = null
this._hasMouseInteraction = false
this._hasKeyboardInteraction = false
}
static get Default() {
return Default
}
static get DefaultType() {
return DefaultType
}
static get NAME() {
return NAME
}
show() {
const showEvent = EventHandler.trigger(this, EVENT_SHOW)
if (showEvent.defaultPrevented) {
return
}
this._clearTimeout()
if (this._config.animation) {
this.classList.add(CLASS_NAME_FADE)
}
const complete = () => {
this.classList.remove(CLASS_NAME_SHOWING)
EventHandler.trigger(this, EVENT_SHOWN)
this._maybeScheduleHide()
}
this.classList.remove(CLASS_NAME_HIDE) // @deprecated
// reflow(this)
this.style.display = 'block'
this.classList.add(CLASS_NAME_SHOW, CLASS_NAME_SHOWING)
this._queueCallback(complete, this, this._config.animation)
}
hide() {
if (!this.isShown()) {
return
}
const hideEvent = EventHandler.trigger(this, EVENT_HIDE)
if (hideEvent.defaultPrevented) {
return
}
const complete = () => {
this.classList.add(CLASS_NAME_HIDE) // @deprecated
this.classList.remove(CLASS_NAME_SHOWING, CLASS_NAME_SHOW)
EventHandler.trigger(this, EVENT_HIDDEN)
this.style.removeProperty('display')
}
this.classList.add(CLASS_NAME_SHOWING)
this._queueCallback(complete, this, this._config.animation)
}
isShown() {
return this.classList.contains(CLASS_NAME_SHOW)
}
// Private
_maybeScheduleHide() {
if (!this._config.autohide) {
return
}
if (this._hasMouseInteraction || this._hasKeyboardInteraction) {
return
}
this._timeout = setTimeout(() => {
this.hide()
}, this._config.delay)
}
_onInteraction(event, isInteracting) {
switch (event.type) {
case 'mouseover':
case 'mouseout':
this._hasMouseInteraction = isInteracting
break
case 'focusin':
case 'focusout':
this._hasKeyboardInteraction = isInteracting
break
default:
break
}
if (isInteracting) {
this._clearTimeout()
return
}
const nextElement = event.relatedTarget
if (this === nextElement || this.contains(nextElement)) {
return
}
this._maybeScheduleHide()
}
_setListeners() {
EventHandler.on(this, EVENT_MOUSEOVER, event => this._onInteraction(event, true))
EventHandler.on(this, EVENT_MOUSEOUT, event => this._onInteraction(event, false))
EventHandler.on(this, EVENT_FOCUSIN, event => this._onInteraction(event, true))
EventHandler.on(this, EVENT_FOCUSOUT, event => this._onInteraction(event, false))
}
_clearTimeout() {
clearTimeout(this._timeout)
this._timeout = null
}
connectedCallback() {
this._setListeners()
this.show()
}
//
// static get observedAttributes() {
// return ['duration'];
// }
//
// attributeChangedCallback(name, oldValue, newValue) {
// if (name === 'duration') {
// this.duration = newValue;
// }
// }
}
+18 -31
View File
@@ -121,6 +121,10 @@ class Tooltip extends BaseComponent {
this.tip = null
this._setListeners()
if (!this._config.selector) {
this._fixTitle()
}
}
// Getters
@@ -149,25 +153,12 @@ class Tooltip extends BaseComponent {
this._isEnabled = !this._isEnabled
}
toggle(event) {
toggle() {
if (!this._isEnabled) {
return
}
if (event) {
const context = this._initializeOnDelegatedTarget(event)
context._activeTrigger.click = !context._activeTrigger.click
if (context._isWithActiveTrigger()) {
context._enter()
} else {
context._leave()
}
return
}
this._activeTrigger.click = !this._activeTrigger.click
if (this._isShown()) {
this._leave()
return
@@ -185,8 +176,8 @@ class Tooltip extends BaseComponent {
this.tip.remove()
}
if (this._config.originalTitle) {
this._element.setAttribute('title', this._config.originalTitle)
if (this._element.getAttribute('data-bs-original-title')) {
this._element.setAttribute('title', this._element.getAttribute('data-bs-original-title'))
}
this._disposePopper()
@@ -375,7 +366,7 @@ class Tooltip extends BaseComponent {
}
_getTitle() {
return this._resolvePossibleFunction(this._config.title) || this._config.originalTitle
return this._resolvePossibleFunction(this._config.title) || this._element.getAttribute('data-bs-original-title')
}
// Private
@@ -469,7 +460,10 @@ class Tooltip extends BaseComponent {
for (const trigger of triggers) {
if (trigger === 'click') {
EventHandler.on(this._element, this.constructor.eventName(EVENT_CLICK), this._config.selector, event => this.toggle(event))
EventHandler.on(this._element, this.constructor.eventName(EVENT_CLICK), this._config.selector, event => {
const context = this._initializeOnDelegatedTarget(event)
context.toggle()
})
} else if (trigger !== TRIGGER_MANUAL) {
const eventIn = trigger === TRIGGER_HOVER ?
this.constructor.eventName(EVENT_MOUSEENTER) :
@@ -500,20 +494,10 @@ class Tooltip extends BaseComponent {
}
EventHandler.on(this._element.closest(SELECTOR_MODAL), EVENT_MODAL_HIDE, this._hideModalHandler)
if (this._config.selector) {
this._config = {
...this._config,
trigger: 'manual',
selector: ''
}
} else {
this._fixTitle()
}
}
_fixTitle() {
const title = this._config.originalTitle
const title = this._element.getAttribute('title')
if (!title) {
return
@@ -523,6 +507,7 @@ class Tooltip extends BaseComponent {
this._element.setAttribute('aria-label', title)
}
this._element.setAttribute('data-bs-original-title', title) // DO NOT USE IT. Is only for backwards compatibility
this._element.removeAttribute('title')
}
@@ -593,7 +578,6 @@ class Tooltip extends BaseComponent {
}
}
config.originalTitle = this._element.getAttribute('title') || ''
if (typeof config.title === 'number') {
config.title = config.title.toString()
}
@@ -614,6 +598,9 @@ class Tooltip extends BaseComponent {
}
}
config.selector = false
config.trigger = 'manual'
// In the future can be replaced with:
// const keysWithDifferentValues = Object.entries(this._config).filter(entry => this.constructor.Default[entry[0]] !== this._config[entry[0]])
// `Object.fromEntries(keysWithDifferentValues)`
+30
View File
@@ -734,6 +734,36 @@ describe('Modal', () => {
})
})
it('should not close modal when clicking on an element removed from modal content', () => {
return new Promise(resolve => {
fixtureEl.innerHTML = [
'<div class="modal">',
' <div class="modal-dialog">',
' <button class="btn">BTN</button>',
' </div>',
'</div>'
].join('')
const modalEl = fixtureEl.querySelector('.modal')
const buttonEl = modalEl.querySelector('.btn')
const modal = new Modal(modalEl)
const spy = spyOn(modal, 'hide')
buttonEl.addEventListener('click', () => {
buttonEl.remove()
})
modalEl.addEventListener('shown.bs.modal', () => {
modalEl.dispatchEvent(createEvent('mousedown'))
buttonEl.click()
expect(spy).not.toHaveBeenCalled()
resolve()
})
modal.show()
})
})
it('should do nothing is the modal is not shown', () => {
fixtureEl.innerHTML = '<div class="modal"><div class="modal-dialog"></div></div>'
+40 -14
View File
@@ -66,42 +66,68 @@
<div id="shadow" class="pt-5"></div>
</div>
<div id="customContainer"></div>
<div class="row mt-4 border-top">
<hr>
<div class="h4">Test Selector triggered tooltips</div>
<div id="wrapperTriggeredBySelector">
<div class="py-2 selectorButtonsBlock">
<button type="button" class="btn btn-secondary bs-dynamic-tooltip" title="random title">Using title</button>
<button type="button" class="btn btn-secondary bs-dynamic-tooltip" data-bs-title="random title">Using bs-title</button>
</div>
</div>
<div class="mt-3">
<button type="button" class="btn btn-primary" onclick="duplicateButtons()">Duplicate above two buttons</button>
</div>
</div>
</div>
<script src="../../../dist/js/bootstrap.bundle.js"></script>
<script>
if (typeof document.body.attachShadow === 'function') {
var shadowRoot = document.getElementById('shadow').attachShadow({ mode: 'open' })
const shadowRoot = document.getElementById('shadow').attachShadow({ mode: 'open' })
shadowRoot.innerHTML =
'<button type="button" class="btn btn-secondary" data-bs-toggle="tooltip" data-bs-placement="top" title="Tooltip on top in a shadow dom">' +
'<button id="firstShadowTooltip" type="button" class="btn btn-secondary" data-bs-toggle="tooltip" data-bs-placement="top" title="Tooltip on top in a shadow dom">' +
' Tooltip on top in a shadow dom' +
'</button>' +
'<button id="secondTooltip" type="button" class="btn btn-secondary" data-bs-toggle="tooltip" data-bs-placement="top" title="Tooltip on top in a shadow dom with container option">' +
'<button id="secondShadowTooltip" type="button" class="btn btn-secondary" data-bs-toggle="tooltip" data-bs-placement="top" title="Tooltip on top in a shadow dom with container option">' +
' Tooltip on top in a shadow dom' +
'</button>'
var firstChildTooltip = new bootstrap.Tooltip(shadowRoot.firstChild)
var secondChildTooltip = new bootstrap.Tooltip(shadowRoot.getElementById('secondTooltip'), {
new bootstrap.Tooltip(shadowRoot.firstChild)
new bootstrap.Tooltip(shadowRoot.getElementById('secondShadowTooltip'), {
container: shadowRoot
})
}
var tooltipElements = document.querySelectorAll('[data-bs-toggle="tooltip"]')
for (const tooltipEl of tooltipElements) {
new bootstrap.Tooltip(tooltipEl)
}
var tooltipElement = document.getElementById('tooltipElement')
var tooltipElementInstance = new bootstrap.Tooltip(tooltipElement, {
container: document.getElementById('customContainer')
new bootstrap.Tooltip('#tooltipElement', {
container: '#customContainer'
})
var target = document.getElementById('target')
var targetTooltip = new bootstrap.Tooltip(target, {
const targetTooltip = new bootstrap.Tooltip('#target', {
placement : 'top',
trigger : 'manual'
})
targetTooltip.show()
document.querySelectorAll('[data-bs-toggle="tooltip"]').forEach(tooltipEl=> new bootstrap.Tooltip(tooltipEl))
</script>
<script>
new bootstrap.Tooltip('#wrapperTriggeredBySelector', {
animation: false,
selector: '.bs-dynamic-tooltip'
})
function duplicateButtons() {
const buttonsBlock = document.querySelector('.selectorButtonsBlock')// get first
const buttonsBlockClone = buttonsBlock.cloneNode(true)
buttonsBlockClone.innerHTML+= new Date().toLocaleString()
document.querySelector('#wrapperTriggeredBySelector').append(buttonsBlockClone)
}
</script>
</body>
</html>
+298 -257
View File
File diff suppressed because it is too large Load Diff
+7 -7
View File
@@ -105,18 +105,18 @@
},
"devDependencies": {
"@babel/cli": "^7.18.10",
"@babel/core": "^7.18.13",
"@babel/preset-env": "^7.18.10",
"@babel/core": "^7.19.0",
"@babel/preset-env": "^7.19.0",
"@popperjs/core": "^2.11.6",
"@rollup/plugin-babel": "^5.3.1",
"@rollup/plugin-commonjs": "^22.0.2",
"@rollup/plugin-node-resolve": "^13.3.0",
"@rollup/plugin-node-resolve": "^14.1.0",
"@rollup/plugin-replace": "^4.0.0",
"autoprefixer": "^10.4.8",
"autoprefixer": "^10.4.10",
"bundlewatch": "^0.3.3",
"clean-css-cli": "^5.6.1",
"cross-env": "^7.0.3",
"eslint": "^8.23.0",
"eslint": "^8.23.1",
"eslint-config-xo": "^0.42.0",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-markdown": "^3.0.0",
@@ -144,10 +144,10 @@
"rollup": "^2.79.0",
"rollup-plugin-istanbul": "^3.0.0",
"rtlcss": "^4.0.0",
"sass": "^1.54.8",
"sass": "^1.54.9",
"shelljs": "^0.8.5",
"stylelint": "^14.11.0",
"stylelint-config-twbs-bootstrap": "^5.0.0",
"stylelint-config-twbs-bootstrap": "^6.0.0",
"terser": "^5.15.0",
"vnu-jar": "21.10.12"
},
+2 -2
View File
@@ -708,7 +708,7 @@ In the example below, to create an offcanvas navbar that is always collapsed acr
</ul>
</li>
</ul>
<form class="d-flex" role="search">
<form class="d-flex mt-3" role="search">
<input class="form-control me-2" type="search" placeholder="Search" aria-label="Search">
<button class="btn btn-outline-success" type="submit">Search</button>
</form>
@@ -768,7 +768,7 @@ When using offcanvas in a dark navbar, be aware that you may need to have a dark
</ul>
</li>
</ul>
<form class="d-flex" role="search">
<form class="d-flex mt-3" role="search">
<input class="form-control me-2" type="search" placeholder="Search" aria-label="Search">
<button class="btn btn-success" type="submit">Search</button>
</form>
+1 -1
View File
@@ -201,7 +201,7 @@ Note that for security reasons the `sanitize`, `sanitizeFn`, and `allowList` opt
| `popperConfig` | null, object, function | `null` | To change Bootstrap's default Popper config, see [Popper's configuration](https://popper.js.org/docs/v2/constructors/#options). When a function is used to create the Popper configuration, it's called with an object that contains the Bootstrap's default Popper configuration. It helps you use and merge the default with your own configuration. The function must return a configuration object for Popper. |
| `sanitize` | boolean | `true` | Enable or disable the sanitization. If activated `'template'`, `'content'` and `'title'` options will be sanitized. |
| `sanitizeFn` | null, function | `null` | Here you can supply your own sanitize function. This can be useful if you prefer to use a dedicated library to perform sanitization. |
| `selector` | string, false | `false` | If a selector is provided, popover objects will be delegated to the specified targets. In practice, this is used to also apply popovers to dynamically added DOM elements (`jQuery.on` support). See [this issue]({{< param repo >}}/issues/4215) and [an informative example](https://codepen.io/Johann-S/pen/djJYPb). |
| `selector` | string, false | `false` | If a selector is provided, popover objects will be delegated to the specified targets. In practice, this is used to also apply popovers to dynamically added DOM elements (`jQuery.on` support). See [this issue]({{< param repo >}}/issues/4215) and [an informative example](https://codepen.io/Johann-S/pen/djJYPb). <br>Note: `title` attribute must not be used as a selector. |
| `template` | string | `'<div class="popover" role="popover"><div class="popover-arrow"></div><div class="popover-inner"></div></div>'` | Base HTML to use when creating the popover. The popover's `title` will be injected into the `.popover-inner`. `.popover-arrow` will become the popover's arrow. The outermost wrapper element should have the `.popover` class and `role="popover"`. |
| `title` | string, element, function | `''` | Default title value if `title` attribute isn't present. If a function is given, it will be called with its `this` reference set to the element that the popover is attached to. |
| `trigger` | string | `'hover focus'` | How popover is triggered: click, hover, focus, manual. You may pass multiple triggers; separate them with a space. `'manual'` indicates that the popover will be triggered programmatically via the `.popover('show')`, `.popover('hide')` and `.popover('toggle')` methods; this value cannot be combined with any other trigger. `'hover'` on its own will result in popovers that cannot be triggered via the keyboard, and should only be used if alternative methods for conveying the same information for keyboard users is present. |
@@ -380,7 +380,7 @@ const scrollSpy = new bootstrap.ScrollSpy(document.body, {
| `rootMargin` | string | `0px 0px -25%` | Intersection Observer [rootMargin](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver/rootMargin) valid units, when calculating scroll position. |
| `smoothScroll` | boolean | `false` | Enables smooth scrolling when a user clicks on a link that refers to ScrollSpy observables. |
| `target` | string, DOM element | `null` | Specifies element to apply Scrollspy plugin. |
| `threshold` | array | `[0.1, 0.5, 1]` | `IntersectionObserver` [threshold](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver/IntersectionObserver#threshold) valid input, when calculating scroll position.|
| `threshold` | array | `[0.1, 0.5, 1]` | `IntersectionObserver` [threshold](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver/IntersectionObserver#threshold) valid input, when calculating scroll position. |
{{< /bs-table >}}
+1 -1
View File
@@ -219,7 +219,7 @@ Note that for security reasons the `sanitize`, `sanitizeFn`, and `allowList` opt
| `popperConfig` | null, object, function | `null` | To change Bootstrap's default Popper config, see [Popper's configuration](https://popper.js.org/docs/v2/constructors/#options). When a function is used to create the Popper configuration, it's called with an object that contains the Bootstrap's default Popper configuration. It helps you use and merge the default with your own configuration. The function must return a configuration object for Popper. |
| `sanitize` | boolean | `true` | Enable or disable the sanitization. If activated `'template'`, `'content'` and `'title'` options will be sanitized. |
| `sanitizeFn` | null, function | `null` | Here you can supply your own sanitize function. This can be useful if you prefer to use a dedicated library to perform sanitization. |
| `selector` | string, false | `false` | If a selector is provided, tooltip objects will be delegated to the specified targets. In practice, this is used to also apply tooltips to dynamically added DOM elements (`jQuery.on` support). See [this issue]({{< param repo >}}/issues/4215) and [an informative example](https://codepen.io/Johann-S/pen/djJYPb). |
| `selector` | string, false | `false` | If a selector is provided, tooltip objects will be delegated to the specified targets. In practice, this is used to also apply tooltips to dynamically added DOM elements (`jQuery.on` support). See [this issue]({{< param repo >}}/issues/4215) and [an informative example](https://codepen.io/Johann-S/pen/djJYPb). <br>Note: `title` attribute must not be used as a selector. |
| `template` | string | `'<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>'` | Base HTML to use when creating the tooltip. The tooltip's `title` will be injected into the `.tooltip-inner`. `.tooltip-arrow` will become the tooltip's arrow. The outermost wrapper element should have the `.tooltip` class and `role="tooltip"`. |
| `title` | string, element, function | `''` | Default title value if `title` attribute isn't present. If a function is given, it will be called with its `this` reference set to the element that the popover is attached to. |
| `trigger` | string | `'hover focus'` | How tooltip is triggered: click, hover, focus, manual. You may pass multiple triggers; separate them with a space. `'manual'` indicates that the tooltip will be triggered programmatically via the `.tooltip('show')`, `.tooltip('hide')` and `.tooltip('toggle')` methods; this value cannot be combined with any other trigger. `'hover'` on its own will result in tooltips that cannot be triggered via the keyboard, and should only be used if alternative methods for conveying the same information for keyboard users is present. |
@@ -73,7 +73,7 @@ At this point, everything is in the right place, but Vite won't work because we
With dependencies installed and our project folder ready for us to start coding, we can now configure Vite and run our project locally.
1. **Open `vite.config.js` in your editor.** Since it's blank, we'll need to add some boilerplate config to it so we can start our server. This part of the config tells Vite were to look for our project's JavaScript and how the development server should behave (pulling from the `src` folder with hot reload).
1. **Open `vite.config.js` in your editor.** Since it's blank, we'll need to add some boilerplate config to it so we can start our server. This part of the config tells Vite where to look for our project's JavaScript and how the development server should behave (pulling from the `src` folder with hot reload).
<!-- eslint-skip -->
```js
@@ -75,7 +75,7 @@ At this point, everything is in the right place, but Webpack won't work because
With dependencies installed and our project folder ready for us to start coding, we can now configure Webpack and run our project locally.
1. **Open `webpack.config.js` in your editor.** Since it's blank, we'll need to add some boilerplate config to it so we can start our server. This part of the config tells Webpack were to look for our project's JavaScript, where to output the compiled code to (`dist`), and how the development server should behave (pulling from the `dist` folder with hot reload).
1. **Open `webpack.config.js` in your editor.** Since it's blank, we'll need to add some boilerplate config to it so we can start our server. This part of the config tells Webpack where to look for our project's JavaScript, where to output the compiled code to (`dist`), and how the development server should behave (pulling from the `dist` folder with hot reload).
```js
const path = require('path')
+7
View File
@@ -1,6 +1,13 @@
<div class="bd-masthead mb-3" id="content">
<div class="container-xxl bd-gutter">
<div class="col-md-8 mx-auto text-center">
<div class="m-2 p-3 bg-white">
<bs-toa class="border"><div class="toast-body bg-info mb-2">dddddd</div></bs-toa>
<bs-toa class="border" autohide="false"><div class="toast-body bg-primary">dddddd</div></bs-toa>
<hr>
<button class="btn btn-sm btn-primary" onclick="document.querySelector('bs-toa').show()">show again</button>
</div>
<a class="d-flex flex-column flex-lg-row justify-content-center align-items-center mb-4 text-dark lh-sm text-decoration-none" href="https://blog.getbootstrap.com/2022/07/19/bootstrap-5-2-0/">
<strong class="d-sm-inline-block p-2 me-2 mb-2 mb-lg-0 rounded-3 masthead-notice">New in v5.2</strong>
<span class="text-muted">CSS variables, responsive offcanvas, new utilities, and more!</span>