| /*! |
| * Bootstrap v6.0.0-alpha1 (https://getbootstrap.com/) |
| * Copyright 2011-2026 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) |
| * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) |
| */ |
| import { arrow, autoUpdate, computePosition, flip, offset, shift } from "@floating-ui/dom"; |
| import { Calendar } from "vanilla-calendar-pro"; |
| //#region js/src/dom/data.ts |
| /** |
| * -------------------------------------------------------------------------- |
| * Bootstrap dom/data.ts |
| * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) |
| * -------------------------------------------------------------------------- |
| */ |
| /** |
| * Constants |
| */ |
| const elementMap = /* @__PURE__ */ new Map(); |
| var data_default = { |
| set(element, key, instance) { |
| if (!elementMap.has(element)) elementMap.set(element, /* @__PURE__ */ new Map()); |
| const instanceMap = elementMap.get(element); |
| if (!instanceMap.has(key) && instanceMap.size !== 0) { |
| console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${[...instanceMap.keys()][0]}.`); |
| return; |
| } |
| instanceMap.set(key, instance); |
| }, |
| get(element, key) { |
| if (element && elementMap.has(element)) return elementMap.get(element).get(key) || null; |
| return null; |
| }, |
| getAny(element) { |
| if (element && elementMap.has(element)) return elementMap.get(element).values().next().value || null; |
| return null; |
| }, |
| remove(element, key) { |
| if (!elementMap.has(element)) return; |
| const instanceMap = elementMap.get(element); |
| instanceMap.delete(key); |
| if (instanceMap.size === 0) elementMap.delete(element); |
| } |
| }; |
| //#endregion |
| //#region js/src/dom/event-handler.ts |
| /** |
| * Constants |
| */ |
| const namespaceRegex = /[^.]*(?=\..*)\.|.*/; |
| const stripNameRegex = /\..*/; |
| const stripUidRegex = /::\d+$/; |
| const eventRegistry = {}; |
| let uidEvent = 1; |
| const customEvents = { |
| mouseenter: "mouseover", |
| mouseleave: "mouseout" |
| }; |
| const nativeEvents = /* @__PURE__ */ new Set([ |
| "click", |
| "dblclick", |
| "mouseup", |
| "mousedown", |
| "contextmenu", |
| "mousewheel", |
| "DOMMouseScroll", |
| "mouseover", |
| "mouseout", |
| "mousemove", |
| "selectstart", |
| "selectend", |
| "keydown", |
| "keypress", |
| "keyup", |
| "orientationchange", |
| "touchstart", |
| "touchmove", |
| "touchend", |
| "touchcancel", |
| "pointerdown", |
| "pointermove", |
| "pointerup", |
| "pointerleave", |
| "pointercancel", |
| "gesturestart", |
| "gesturechange", |
| "gestureend", |
| "focus", |
| "blur", |
| "change", |
| "reset", |
| "select", |
| "submit", |
| "focusin", |
| "focusout", |
| "load", |
| "unload", |
| "beforeunload", |
| "resize", |
| "move", |
| "DOMContentLoaded", |
| "readystatechange", |
| "error", |
| "abort", |
| "scroll", |
| "scrollend" |
| ]); |
| /** |
| * Private methods |
| */ |
| function makeEventUid(element, uid) { |
| return uid && `${uid}::${uidEvent++}` || element.uidEvent || uidEvent++; |
| } |
| function getElementEvents(element) { |
| const uid = makeEventUid(element); |
| element.uidEvent = uid; |
| eventRegistry[uid] = eventRegistry[uid] || {}; |
| return eventRegistry[uid]; |
| } |
| function isMouseEventWithinTarget(event) { |
| const { delegateTarget, relatedTarget } = event; |
| return Boolean(relatedTarget && delegateTarget.contains(relatedTarget)); |
| } |
| function bootstrapHandler(element, fn, handlerTypeEvent) { |
| const isCustomMouseEvent = handlerTypeEvent in customEvents; |
| return function handler(event) { |
| const bootstrapEvent = hydrateObj(event, { delegateTarget: element }); |
| if (isCustomMouseEvent && isMouseEventWithinTarget(bootstrapEvent)) return; |
| if (handler.oneOff) EventHandler.off(element, handlerTypeEvent, fn); |
| return fn.apply(element, [bootstrapEvent]); |
| }; |
| } |
| function bootstrapDelegationHandler(element, selector, fn, handlerTypeEvent) { |
| const isCustomMouseEvent = handlerTypeEvent in customEvents; |
| return function handler(event) { |
| const domElements = element.querySelectorAll(selector); |
| for (let { target } = event; target && target !== this; target = target.parentNode) for (const domElement of domElements) { |
| if (domElement !== target) continue; |
| const bootstrapEvent = hydrateObj(event, { delegateTarget: target }); |
| if (isCustomMouseEvent && isMouseEventWithinTarget(bootstrapEvent)) return; |
| if (handler.oneOff) EventHandler.off(element, handlerTypeEvent, selector, fn); |
| return fn.apply(target, [bootstrapEvent]); |
| } |
| }; |
| } |
| function findHandler(events, callable, handlerTypeEvent, delegationSelector = null) { |
| return Object.values(events).find((event) => event.callable === callable && event.handlerTypeEvent === handlerTypeEvent && event.delegationSelector === delegationSelector); |
| } |
| function normalizeParameters(originalTypeEvent, handler, delegationFunction) { |
| const isDelegated = typeof handler === "string"; |
| const callable = isDelegated ? delegationFunction : handler || delegationFunction; |
| const baseTypeEvent = originalTypeEvent.replace(stripNameRegex, ""); |
| let typeEvent = customEvents[baseTypeEvent] || baseTypeEvent; |
| if (!nativeEvents.has(typeEvent)) typeEvent = originalTypeEvent; |
| const handlerTypeEvent = baseTypeEvent in customEvents ? baseTypeEvent : typeEvent; |
| return { |
| isDelegated, |
| callable, |
| typeEvent, |
| handlerTypeEvent |
| }; |
| } |
| function addHandler(element, originalTypeEvent, handler, delegationFunction, oneOff) { |
| if (typeof originalTypeEvent !== "string" || !element) return; |
| const { isDelegated, callable, typeEvent, handlerTypeEvent } = normalizeParameters(originalTypeEvent, handler, delegationFunction); |
| const events = getElementEvents(element); |
| const handlers = events[typeEvent] || (events[typeEvent] = {}); |
| const previousFunction = findHandler(handlers, callable, handlerTypeEvent, isDelegated ? handler : null); |
| if (previousFunction) { |
| previousFunction.oneOff = previousFunction.oneOff && oneOff; |
| return; |
| } |
| const uid = makeEventUid(callable, originalTypeEvent.replace(namespaceRegex, "")); |
| const fn = isDelegated ? bootstrapDelegationHandler(element, handler, callable, handlerTypeEvent) : bootstrapHandler(element, callable, handlerTypeEvent); |
| fn.delegationSelector = isDelegated ? handler : null; |
| fn.callable = callable; |
| fn.handlerTypeEvent = handlerTypeEvent; |
| fn.oneOff = oneOff; |
| fn.uidEvent = uid; |
| handlers[uid] = fn; |
| element.addEventListener(typeEvent, fn, isDelegated); |
| } |
| function removeHandler(element, events, typeEvent, handler) { |
| element.removeEventListener(typeEvent, handler, Boolean(handler.delegationSelector)); |
| delete events[typeEvent][handler.uidEvent]; |
| } |
| function removeNamespacedHandlers(element, events, typeEvent, namespace) { |
| const storeElementEvent = events[typeEvent] || {}; |
| for (const [handlerKey, event] of Object.entries(storeElementEvent)) if (handlerKey.includes(namespace)) removeHandler(element, events, typeEvent, event); |
| } |
| function trigger(element, event, args) { |
| if (typeof event !== "string" || !element) return null; |
| const evt = hydrateObj(new Event(event, { |
| bubbles: true, |
| cancelable: true |
| }), args); |
| element.dispatchEvent(evt); |
| return evt; |
| } |
| const EventHandler = { |
| on(element, event, handler, delegationFunction) { |
| addHandler(element, event, handler, delegationFunction, false); |
| }, |
| one(element, event, handler, delegationFunction) { |
| addHandler(element, event, handler, delegationFunction, true); |
| }, |
| off(element, originalTypeEvent, handler, delegationFunction) { |
| if (typeof originalTypeEvent !== "string" || !element) return; |
| const { isDelegated, callable, typeEvent, handlerTypeEvent } = normalizeParameters(originalTypeEvent, handler, delegationFunction); |
| const inNamespace = typeEvent !== originalTypeEvent && handlerTypeEvent !== originalTypeEvent; |
| const events = getElementEvents(element); |
| const storeElementEvent = events[typeEvent] || {}; |
| const isNamespace = originalTypeEvent.startsWith("."); |
| if (typeof callable !== "undefined") { |
| if (!Object.keys(storeElementEvent).length) return; |
| const fn = findHandler(storeElementEvent, callable, handlerTypeEvent, isDelegated ? handler : null); |
| if (fn) removeHandler(element, events, typeEvent, fn); |
| return; |
| } |
| if (isNamespace) for (const elementEvent of Object.keys(events)) removeNamespacedHandlers(element, events, elementEvent, originalTypeEvent.slice(1)); |
| for (const [keyHandlers, event] of Object.entries(storeElementEvent)) { |
| const handlerKey = keyHandlers.replace(stripUidRegex, ""); |
| if (event.handlerTypeEvent === handlerTypeEvent && (!inNamespace || originalTypeEvent.includes(handlerKey))) removeHandler(element, events, typeEvent, event); |
| } |
| }, |
| trigger |
| }; |
| function hydrateObj(obj, meta = {}) { |
| for (const [key, value] of Object.entries(meta)) try { |
| obj[key] = value; |
| } catch { |
| Object.defineProperty(obj, key, { |
| configurable: true, |
| get() { |
| return value; |
| } |
| }); |
| } |
| return obj; |
| } |
| //#endregion |
| //#region js/src/dom/manipulator.ts |
| /** |
| * -------------------------------------------------------------------------- |
| * Bootstrap dom/manipulator.ts |
| * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) |
| * -------------------------------------------------------------------------- |
| */ |
| function normalizeData(value) { |
| if (value === "true") return true; |
| if (value === "false") return false; |
| if (value === Number(value).toString()) return Number(value); |
| if (value === "" || value === "null") return null; |
| if (typeof value !== "string") return value; |
| try { |
| return JSON.parse(decodeURIComponent(value)); |
| } catch { |
| return value; |
| } |
| } |
| function normalizeDataKey(key) { |
| return key.replace(/[A-Z]/g, (chr) => `-${chr.toLowerCase()}`); |
| } |
| const Manipulator = { |
| setDataAttribute(element, key, value) { |
| element.setAttribute(`data-bs-${normalizeDataKey(key)}`, value); |
| }, |
| removeDataAttribute(element, key) { |
| element.removeAttribute(`data-bs-${normalizeDataKey(key)}`); |
| }, |
| getDataAttributes(element) { |
| if (!element) return {}; |
| const attributes = {}; |
| const bsKeys = Object.keys(element.dataset).filter((key) => key.startsWith("bs") && !key.startsWith("bsConfig")); |
| for (const key of bsKeys) { |
| let pureKey = key.replace(/^bs/, ""); |
| pureKey = pureKey.charAt(0).toLowerCase() + pureKey.slice(1); |
| attributes[pureKey] = normalizeData(element.dataset[key]); |
| } |
| return attributes; |
| }, |
| getDataAttribute(element, key) { |
| return normalizeData(element.getAttribute(`data-bs-${normalizeDataKey(key)}`)); |
| } |
| }; |
| //#endregion |
| //#region js/src/util/index.ts |
| /** |
| * -------------------------------------------------------------------------- |
| * Bootstrap util/index.ts |
| * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) |
| * -------------------------------------------------------------------------- |
| */ |
| const MAX_UID = 1e6; |
| const MILLISECONDS_MULTIPLIER = 1e3; |
| const TRANSITION_END = "transitionend"; |
| /** |
| * Properly escape IDs selectors to handle weird IDs |
| */ |
| const parseSelector = (selector) => { |
| if (selector && window.CSS && window.CSS.escape) selector = selector.replace(/#([^\s"#']+)/g, (match, id) => `#${CSS.escape(id)}`); |
| return selector; |
| }; |
| const toType = (object) => { |
| if (object === null || object === void 0) return `${object}`; |
| return Object.prototype.toString.call(object).match(/\s([a-z]+)/i)[1].toLowerCase(); |
| }; |
| /** |
| * Public Util API |
| */ |
| const getUID = (prefix) => { |
| do |
| prefix += Math.floor(Math.random() * MAX_UID); |
| while (document.getElementById(prefix)); |
| return prefix; |
| }; |
| const getTransitionDurationFromElement = (element) => { |
| if (!element) return 0; |
| let { transitionDuration, transitionDelay } = window.getComputedStyle(element); |
| if (!Number.parseFloat(transitionDuration) && !Number.parseFloat(transitionDelay)) return 0; |
| transitionDuration = transitionDuration.split(",")[0]; |
| transitionDelay = transitionDelay.split(",")[0]; |
| return (Number.parseFloat(transitionDuration) + Number.parseFloat(transitionDelay)) * MILLISECONDS_MULTIPLIER; |
| }; |
| const triggerTransitionEnd = (element) => { |
| element.dispatchEvent(new Event(TRANSITION_END)); |
| }; |
| const isElement = (object) => { |
| if (!object || typeof object !== "object") return false; |
| return typeof object.nodeType !== "undefined"; |
| }; |
| const getElement = (object) => { |
| if (isElement(object)) return object; |
| if (typeof object === "string" && object.length > 0) return document.querySelector(parseSelector(object)); |
| return null; |
| }; |
| const isVisible = (element) => { |
| if (!isElement(element) || element.getClientRects().length === 0) return false; |
| const elementIsVisible = getComputedStyle(element).getPropertyValue("visibility") === "visible"; |
| const closedDetails = element.closest("details:not([open])"); |
| if (!closedDetails) return elementIsVisible; |
| if (closedDetails !== element) { |
| const summary = element.closest("summary"); |
| if (summary && summary.parentNode !== closedDetails) return false; |
| if (summary === null) return false; |
| } |
| return elementIsVisible; |
| }; |
| const isDisabled = (element) => { |
| if (!element || element.nodeType !== Node.ELEMENT_NODE) return true; |
| if (element.classList.contains("disabled")) return true; |
| const disableableElement = element; |
| if (typeof disableableElement.disabled !== "undefined") return disableableElement.disabled; |
| return element.hasAttribute("disabled") && element.getAttribute("disabled") !== "false"; |
| }; |
| const setAriaAttribute = (element, name, value) => { |
| element.setAttribute(name, String(value)); |
| }; |
| const findShadowRoot = (element) => { |
| if (!document.documentElement.attachShadow) return null; |
| if (typeof element.getRootNode === "function") { |
| const root = element.getRootNode(); |
| return root instanceof ShadowRoot ? root : null; |
| } |
| if (element instanceof ShadowRoot) return element; |
| if (!element.parentNode) return null; |
| return findShadowRoot(element.parentNode); |
| }; |
| const noop = () => {}; |
| const isRTL = () => document.documentElement.dir === "rtl"; |
| const execute = (possibleCallback, args = [], defaultValue = possibleCallback) => { |
| return typeof possibleCallback === "function" ? possibleCallback.call(...args) : defaultValue; |
| }; |
| const executeAfterTransition = (callback, transitionElement, waitForTransition = true) => { |
| if (!waitForTransition) { |
| execute(callback); |
| return; |
| } |
| const emulatedDuration = getTransitionDurationFromElement(transitionElement) + 5; |
| let called = false; |
| const handler = ({ target }) => { |
| if (target !== transitionElement) return; |
| called = true; |
| transitionElement.removeEventListener(TRANSITION_END, handler); |
| execute(callback); |
| }; |
| transitionElement.addEventListener(TRANSITION_END, handler); |
| setTimeout(() => { |
| if (!called) triggerTransitionEnd(transitionElement); |
| }, emulatedDuration); |
| }; |
| /** |
| * Return the previous/next element of a list. |
| * |
| * @param list The list of elements |
| * @param activeElement The active element |
| * @param shouldGetNext Choose to get next or previous element |
| * @param isCycleAllowed |
| * @return The proper element |
| */ |
| const getNextActiveElement = (list, activeElement, shouldGetNext, isCycleAllowed) => { |
| const listLength = list.length; |
| let index = list.indexOf(activeElement); |
| if (index === -1) return !shouldGetNext && isCycleAllowed ? list[listLength - 1] : list[0]; |
| index += shouldGetNext ? 1 : -1; |
| if (isCycleAllowed) index = (index + listLength) % listLength; |
| return list[Math.max(0, Math.min(index, listLength - 1))]; |
| }; |
| //#endregion |
| //#region js/src/util/config.ts |
| /** |
| * -------------------------------------------------------------------------- |
| * Bootstrap util/config.ts |
| * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) |
| * -------------------------------------------------------------------------- |
| */ |
| /** |
| * Class definition |
| */ |
| var Config = class { |
| static get Default() { |
| return {}; |
| } |
| static get DefaultType() { |
| return {}; |
| } |
| static get NAME() { |
| throw new Error("You have to implement the static method \"NAME\", for each component!"); |
| } |
| _getConfig(config) { |
| config = this._mergeConfigObj(config); |
| config = this._configAfterMerge(config); |
| this._typeCheckConfig(config); |
| return config; |
| } |
| _configAfterMerge(config) { |
| return config; |
| } |
| _mergeConfigObj(config, element) { |
| const jsonConfig = isElement(element) ? Manipulator.getDataAttribute(element, "config") : {}; |
| return { |
| ...this.constructor.Default, |
| ...typeof jsonConfig === "object" ? jsonConfig : {}, |
| ...isElement(element) ? Manipulator.getDataAttributes(element) : {}, |
| ...typeof config === "object" ? config : {} |
| }; |
| } |
| _typeCheckConfig(config, configTypes = this.constructor.DefaultType) { |
| for (const [property, expectedTypes] of Object.entries(configTypes)) { |
| const value = config[property]; |
| const valueType = isElement(value) ? "element" : toType(value); |
| if (!new RegExp(expectedTypes).test(valueType)) throw new TypeError(`${this.constructor.NAME.toUpperCase()}: Option "${property}" provided type "${valueType}" but expected type "${expectedTypes}".`); |
| } |
| } |
| }; |
| //#endregion |
| //#region js/src/base-component.ts |
| /** |
| * -------------------------------------------------------------------------- |
| * Bootstrap base-component.ts |
| * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) |
| * -------------------------------------------------------------------------- |
| */ |
| /** |
| * Constants |
| */ |
| const VERSION = "6.0.0-alpha1"; |
| /** |
| * Class definition |
| */ |
| var BaseComponent = class extends Config { |
| constructor(element, config) { |
| super(); |
| element = getElement(element); |
| if (!element) return; |
| this._element = element; |
| this._config = this._getConfig(config); |
| const existingInstance = data_default.get(this._element, this.constructor.DATA_KEY); |
| if (existingInstance) existingInstance.dispose(); |
| data_default.set(this._element, this.constructor.DATA_KEY, this); |
| } |
| dispose() { |
| data_default.remove(this._element, this.constructor.DATA_KEY); |
| EventHandler.off(this._element, this.constructor.EVENT_KEY); |
| for (const propertyName of Object.getOwnPropertyNames(this)) this[propertyName] = null; |
| } |
| _queueCallback(callback, element, isAnimated = true) { |
| return new Promise((resolve) => { |
| executeAfterTransition(() => { |
| if (this._element) callback(); |
| resolve(); |
| }, element, isAnimated); |
| }); |
| } |
| _getConfig(config) { |
| config = this._mergeConfigObj(config, this._element); |
| config = this._configAfterMerge(config); |
| this._typeCheckConfig(config); |
| return config; |
| } |
| static getInstance(element) { |
| return data_default.get(getElement(element), this.DATA_KEY); |
| } |
| static getOrCreateInstance(element, config = {}) { |
| return this.getInstance(element) || new this(element, typeof config === "object" ? config : null); |
| } |
| static get VERSION() { |
| return VERSION; |
| } |
| static get DATA_KEY() { |
| return `bs.${this.NAME}`; |
| } |
| static get EVENT_KEY() { |
| return `.${this.DATA_KEY}`; |
| } |
| static eventName(name) { |
| return `${name}${this.EVENT_KEY}`; |
| } |
| }; |
| //#endregion |
| //#region js/src/dom/selector-engine.ts |
| /** |
| * -------------------------------------------------------------------------- |
| * Bootstrap dom/selector-engine.ts |
| * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) |
| * -------------------------------------------------------------------------- |
| */ |
| const getSelector = (element) => { |
| let selector = element.getAttribute("data-bs-target"); |
| if (!selector || selector === "#") { |
| let hrefAttribute = element.getAttribute("href"); |
| if (!hrefAttribute || !hrefAttribute.includes("#") && !hrefAttribute.startsWith(".")) return null; |
| if (hrefAttribute.includes("#") && !hrefAttribute.startsWith("#")) hrefAttribute = `#${hrefAttribute.split("#")[1]}`; |
| selector = hrefAttribute && hrefAttribute !== "#" ? hrefAttribute.trim() : null; |
| } |
| return selector ? selector.split(",").map((sel) => parseSelector(sel)).join(",") : null; |
| }; |
| const SelectorEngine = { |
| find(selector, element = document.documentElement) { |
| return [...Element.prototype.querySelectorAll.call(element, selector)]; |
| }, |
| findOne(selector, element = document.documentElement) { |
| return Element.prototype.querySelector.call(element, selector); |
| }, |
| parents(element, selector) { |
| const parents = []; |
| let ancestor = element.parentNode.closest(selector); |
| while (ancestor) { |
| parents.push(ancestor); |
| ancestor = ancestor.parentNode.closest(selector); |
| } |
| return parents; |
| }, |
| closest(element, selector) { |
| return Element.prototype.closest.call(element, selector); |
| }, |
| prev(element, selector) { |
| let previous = element.previousElementSibling; |
| while (previous) { |
| if (previous.matches(selector)) return [previous]; |
| previous = previous.previousElementSibling; |
| } |
| return []; |
| }, |
| next(element, selector) { |
| let next = element.nextElementSibling; |
| while (next) { |
| if (next.matches(selector)) return [next]; |
| next = next.nextElementSibling; |
| } |
| return []; |
| }, |
| getSelectorFromElement(element) { |
| const selector = getSelector(element); |
| if (selector) return SelectorEngine.findOne(selector) ? selector : null; |
| return null; |
| }, |
| getElementFromSelector(element) { |
| const selector = getSelector(element); |
| return selector ? SelectorEngine.findOne(selector) : null; |
| }, |
| getMultipleElementsFromSelector(element) { |
| const selector = getSelector(element); |
| return selector ? SelectorEngine.find(selector) : []; |
| } |
| }; |
| //#endregion |
| //#region js/src/util/component-functions.ts |
| const enableDismissTrigger = (component, method = "hide") => { |
| const clickEvent = `click.dismiss${component.EVENT_KEY}`; |
| const name = component.NAME; |
| EventHandler.on(document, clickEvent, `[data-bs-dismiss="${name}"]`, function(event) { |
| if (["A", "AREA"].includes(this.tagName)) event.preventDefault(); |
| if (isDisabled(this)) return; |
| const target = SelectorEngine.getElementFromSelector(this) || this.closest(`.${name}, [class*=":${name}"]`); |
| component.getOrCreateInstance(target)[method](); |
| }); |
| }; |
| const eventActionOnPlugin = (Plugin, onEvent, stringSelector, method, callback = null) => { |
| eventAction(`${onEvent}.${Plugin.NAME}`, stringSelector, (data) => { |
| const instances = data.targets.filter(Boolean).map((element) => Plugin.getOrCreateInstance(element)); |
| if (typeof callback === "function") callback({ |
| ...data, |
| instances |
| }); |
| for (const instance of instances) instance[method](); |
| }); |
| }; |
| const eventAction = (onEvent, stringSelector, callback) => { |
| const selector = `${stringSelector}:not(.disabled):not(:disabled)`; |
| EventHandler.on(document, onEvent, selector, function(event) { |
| if (["A", "AREA"].includes(this.tagName)) event.preventDefault(); |
| const selector = SelectorEngine.getSelectorFromElement(this); |
| callback({ |
| targets: selector ? SelectorEngine.find(selector) : [this], |
| event |
| }); |
| }); |
| }; |
| //#endregion |
| //#region js/src/alert.ts |
| /** |
| * -------------------------------------------------------------------------- |
| * Bootstrap alert.ts |
| * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) |
| * -------------------------------------------------------------------------- |
| */ |
| /** |
| * Constants |
| */ |
| const NAME$21 = "alert"; |
| const EVENT_KEY$18 = `.bs.alert`; |
| const EVENT_CLOSE = `close${EVENT_KEY$18}`; |
| const EVENT_CLOSED = `closed${EVENT_KEY$18}`; |
| const CLASS_NAME_HIDING = "hiding"; |
| const CLASS_NAME_SHOW$6 = "show"; |
| /** |
| * Class definition |
| */ |
| var Alert = class extends BaseComponent { |
| static get NAME() { |
| return NAME$21; |
| } |
| async close() { |
| if (EventHandler.trigger(this._element, EVENT_CLOSE).defaultPrevented) return; |
| this._element.classList.remove(CLASS_NAME_SHOW$6); |
| this._element.classList.add(CLASS_NAME_HIDING); |
| const isAnimated = getTransitionDurationFromElement(this._element) > 0; |
| await this._queueCallback(() => this._destroyElement(), this._element, isAnimated); |
| } |
| _destroyElement() { |
| this._element.remove(); |
| EventHandler.trigger(this._element, EVENT_CLOSED); |
| this.dispose(); |
| } |
| }; |
| /** |
| * Data API implementation |
| */ |
| enableDismissTrigger(Alert, "close"); |
| //#endregion |
| //#region js/src/button.ts |
| /** |
| * -------------------------------------------------------------------------- |
| * Bootstrap button.ts |
| * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) |
| * -------------------------------------------------------------------------- |
| */ |
| /** |
| * Constants |
| */ |
| const NAME$20 = "button"; |
| const EVENT_KEY$17 = `.bs.button`; |
| const DATA_API_KEY$12 = ".data-api"; |
| const CLASS_NAME_ACTIVE$4 = "active"; |
| const SELECTOR_DATA_TOGGLE$10 = "[data-bs-toggle=\"button\"]"; |
| const EVENT_CLICK_DATA_API$8 = `click${EVENT_KEY$17}${DATA_API_KEY$12}`; |
| const EVENT_DOM_CONTENT_LOADED$1 = `DOMContentLoaded${EVENT_KEY$17}${DATA_API_KEY$12}`; |
| /** |
| * Class definition |
| */ |
| var Button = class extends BaseComponent { |
| static get NAME() { |
| return NAME$20; |
| } |
| toggle() { |
| setAriaAttribute(this._element, "aria-pressed", this._element.classList.toggle(CLASS_NAME_ACTIVE$4)); |
| } |
| }; |
| /** |
| * Data API implementation |
| */ |
| EventHandler.on(document, EVENT_CLICK_DATA_API$8, SELECTOR_DATA_TOGGLE$10, (event) => { |
| event.preventDefault(); |
| const button = event.target.closest(SELECTOR_DATA_TOGGLE$10); |
| Button.getOrCreateInstance(button).toggle(); |
| }); |
| EventHandler.on(document, EVENT_DOM_CONTENT_LOADED$1, () => { |
| for (const element of SelectorEngine.find(SELECTOR_DATA_TOGGLE$10)) if (!element.hasAttribute("aria-pressed")) setAriaAttribute(element, "aria-pressed", element.classList.contains(CLASS_NAME_ACTIVE$4)); |
| }); |
| //#endregion |
| //#region js/src/carousel.ts |
| /** |
| * -------------------------------------------------------------------------- |
| * Bootstrap carousel.ts |
| * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) |
| * -------------------------------------------------------------------------- |
| */ |
| /** |
| * Constants |
| */ |
| const NAME$19 = "carousel"; |
| const EVENT_KEY$16 = `.bs.carousel`; |
| const DATA_API_KEY$11 = ".data-api"; |
| const ARROW_LEFT_KEY$2 = "ArrowLeft"; |
| const ARROW_RIGHT_KEY$2 = "ArrowRight"; |
| const DIRECTION_LEFT = "left"; |
| const DIRECTION_RIGHT = "right"; |
| const EVENT_SLIDE = `slide${EVENT_KEY$16}`; |
| const EVENT_SLID = `slid${EVENT_KEY$16}`; |
| const EVENT_KEYDOWN$2 = `keydown${EVENT_KEY$16}`; |
| const EVENT_MOUSEENTER$2 = `mouseenter${EVENT_KEY$16}`; |
| const EVENT_MOUSELEAVE$1 = `mouseleave${EVENT_KEY$16}`; |
| const EVENT_POINTERDOWN$1 = `pointerdown${EVENT_KEY$16}`; |
| const EVENT_LOAD_DATA_API$3 = `load${EVENT_KEY$16}${DATA_API_KEY$11}`; |
| const EVENT_CLICK_DATA_API$7 = `click${EVENT_KEY$16}${DATA_API_KEY$11}`; |
| const CLASS_NAME_CAROUSEL = "carousel"; |
| const CLASS_NAME_ACTIVE$3 = "active"; |
| const CLASS_NAME_FADE = "carousel-fade"; |
| const CLASS_NAME_CENTER = "carousel-center"; |
| const CLASS_NAME_AUTO = "carousel-auto"; |
| const CLASS_NAME_CLONE = "carousel-item-clone"; |
| const CLASS_NAME_PAUSED = "paused"; |
| const CLASS_NAME_PLAYING = "carousel-playing"; |
| const PROPERTY_INTERVAL = "--bs-carousel-interval"; |
| const SCROLL_DURATION = 300; |
| const ACTIVE_RATIO_TOLERANCE = .05; |
| const SELECTOR_ACTIVE = ".active"; |
| const SELECTOR_ITEM = `.carousel-item:not(.${CLASS_NAME_CLONE})`; |
| const SELECTOR_ACTIVE_ITEM = SELECTOR_ACTIVE + SELECTOR_ITEM; |
| const SELECTOR_INNER$1 = ".carousel-inner"; |
| const SELECTOR_INDICATORS = ".carousel-indicators"; |
| const SELECTOR_PLAY_PAUSE = ".carousel-control-play-pause"; |
| const SELECTOR_DATA_SLIDE = "[data-bs-slide], [data-bs-slide-to]"; |
| const SELECTOR_DATA_SLIDE_PREV = "[data-bs-slide=\"prev\"]"; |
| const SELECTOR_DATA_SLIDE_NEXT = "[data-bs-slide=\"next\"]"; |
| const SELECTOR_DATA_AUTOPLAY = "[data-bs-autoplay=\"true\"]"; |
| const KEY_TO_DIRECTION = { |
| [ARROW_LEFT_KEY$2]: DIRECTION_RIGHT, |
| [ARROW_RIGHT_KEY$2]: DIRECTION_LEFT |
| }; |
| const ENDS_STOP = "stop"; |
| const ENDS_WRAP = "wrap"; |
| const ENDS_LOOP = "loop"; |
| const Default$18 = { |
| autoplay: false, |
| ends: ENDS_LOOP, |
| interval: 5e3, |
| keyboard: true, |
| pause: "hover" |
| }; |
| const DefaultType$18 = { |
| autoplay: "boolean", |
| ends: "string", |
| interval: "number", |
| keyboard: "boolean", |
| pause: "(string|boolean)" |
| }; |
| const easeInOutCubic = (progress) => progress < .5 ? 4 * progress * progress * progress : 1 - (-2 * progress + 2) ** 3 / 2; |
| /** |
| * Class definition |
| */ |
| var Carousel = class extends BaseComponent { |
| constructor(element, config) { |
| super(element, config); |
| this._viewport = SelectorEngine.findOne(SELECTOR_INNER$1, this._element) || this._element; |
| this._indicatorsElement = SelectorEngine.findOne(SELECTOR_INDICATORS, this._element); |
| this._playPauseElement = SelectorEngine.findOne(SELECTOR_PLAY_PAUSE, this._element); |
| this._prevControls = SelectorEngine.find(SELECTOR_DATA_SLIDE_PREV, this._element); |
| this._nextControls = SelectorEngine.find(SELECTOR_DATA_SLIDE_NEXT, this._element); |
| this._interval = null; |
| this._observer = null; |
| this._scrollFrame = null; |
| this._looping = false; |
| this._visibility = /* @__PURE__ */ new Map(); |
| this._playing = this._config.autoplay; |
| this._activeIndex = this._initialActiveIndex(); |
| this._addEventListeners(); |
| this._observeItems(); |
| this._refreshActiveState(); |
| if (this._playing) this.cycle(); |
| this._updatePlayPauseControl(); |
| } |
| static get Default() { |
| return Default$18; |
| } |
| static get DefaultType() { |
| return DefaultType$18; |
| } |
| static get NAME() { |
| return NAME$19; |
| } |
| next() { |
| this.to(this._navIndex() + 1); |
| } |
| nextWhenVisible() { |
| if (document.visibilityState === "visible" && isVisible(this._element)) this.next(); |
| } |
| prev() { |
| this.to(this._navIndex() - 1); |
| } |
| pause() { |
| this._clearInterval(); |
| this._element.classList.remove(CLASS_NAME_PLAYING); |
| } |
| cycle() { |
| this._clearInterval(); |
| this._scheduleAutoplay(); |
| this._element.classList.add(CLASS_NAME_PLAYING); |
| } |
| to(index) { |
| if (this._looping) return; |
| const items = this._getItems(); |
| const rawIndex = Number.parseInt(index, 10); |
| if (this._config.ends === ENDS_LOOP && !this._prefersReducedMotion() && this._canLoop()) { |
| if (rawIndex > items.length - 1) { |
| this._loopTransition(true); |
| return; |
| } |
| if (rawIndex < 0) { |
| this._loopTransition(false); |
| return; |
| } |
| } |
| const targetIndex = this._normalizeIndex(rawIndex, items.length); |
| const currentIndex = this._navIndex(); |
| if (targetIndex === null || targetIndex === currentIndex) return; |
| if (EventHandler.trigger(this._element, EVENT_SLIDE, { |
| relatedTarget: items[targetIndex], |
| direction: this._direction(currentIndex, targetIndex), |
| from: currentIndex, |
| to: targetIndex |
| }).defaultPrevented) return; |
| if (this._isFade()) { |
| this._fadeTo(targetIndex); |
| return; |
| } |
| this._scrollToIndex(targetIndex); |
| } |
| dispose() { |
| this._clearInterval(); |
| if (this._observer) this._observer.disconnect(); |
| if (this._scrollFrame !== null) cancelAnimationFrame(this._scrollFrame); |
| for (const clone of SelectorEngine.find(`.${CLASS_NAME_CLONE}`, this._viewport)) clone.remove(); |
| this._viewport.style.scrollSnapType = ""; |
| EventHandler.off(this._viewport, EVENT_KEY$16); |
| super.dispose(); |
| } |
| _configAfterMerge(config) { |
| if (![ |
| ENDS_STOP, |
| ENDS_WRAP, |
| ENDS_LOOP |
| ].includes(config.ends)) config.ends = Default$18.ends; |
| return config; |
| } |
| _initialActiveIndex() { |
| const active = SelectorEngine.findOne(SELECTOR_ACTIVE_ITEM, this._element); |
| const index = active ? this._getItems().indexOf(active) : 0; |
| return Math.max(index, 0); |
| } |
| _addEventListeners() { |
| if (this._config.keyboard) EventHandler.on(this._element, EVENT_KEYDOWN$2, (event) => this._keydown(event)); |
| if (this._config.pause === "hover") { |
| EventHandler.on(this._element, EVENT_MOUSEENTER$2, () => this.pause()); |
| EventHandler.on(this._element, EVENT_MOUSELEAVE$1, () => this._maybeEnableCycle()); |
| } |
| EventHandler.on(this._viewport, EVENT_POINTERDOWN$1, () => this._pauseFromInteraction()); |
| } |
| _keydown(event) { |
| if (/input|textarea/i.test(event.target.tagName)) return; |
| const direction = KEY_TO_DIRECTION[event.key]; |
| if (direction) { |
| event.preventDefault(); |
| this._pauseFromInteraction(); |
| if (direction === DIRECTION_RIGHT) this.prev(); |
| else this.next(); |
| } |
| } |
| _observeItems() { |
| if (this._isFade() || typeof IntersectionObserver === "undefined") return; |
| this._observer = new IntersectionObserver((entries) => this._handleIntersection(entries), { |
| root: this._viewport, |
| threshold: [ |
| 0, |
| .25, |
| .5, |
| .75, |
| 1 |
| ] |
| }); |
| for (const item of this._getItems()) this._observer.observe(item); |
| } |
| _handleIntersection(entries) { |
| if (this._looping) return; |
| for (const entry of entries) this._visibility.set(entry.target, entry.isIntersecting ? entry.intersectionRatio : 0); |
| const ratios = this._getItems().map((item) => this._visibility.get(item) ?? 0); |
| const maxRatio = Math.max(...ratios); |
| let bestIndex = this._activeIndex; |
| if (maxRatio > 0) bestIndex = ratios.findIndex((ratio) => ratio >= maxRatio - ACTIVE_RATIO_TOLERANCE); |
| this._setActive(bestIndex); |
| this._updateEndControls(); |
| } |
| _navIndex() { |
| if (this._isFade() || this._viewport.scrollWidth - this._viewport.clientWidth <= 0) return this._activeIndex; |
| let index = this._activeIndex; |
| let smallestDelta = Number.POSITIVE_INFINITY; |
| for (const [itemIndex, item] of this._getItems().entries()) { |
| const delta = Math.abs(this._scrollDelta(item)); |
| if (delta < smallestDelta) { |
| smallestDelta = delta; |
| index = itemIndex; |
| } |
| } |
| return index; |
| } |
| _scrollToIndex(index) { |
| const item = this._getItems()[index]; |
| if (!item) return; |
| const left = this._scrollDelta(item); |
| if (Math.abs(left) < 1) return; |
| const targetLeft = this._viewport.scrollLeft + left; |
| this._viewport.style.scrollSnapType = "none"; |
| this._animateScroll(targetLeft, () => { |
| this._viewport.style.scrollSnapType = ""; |
| if (!this._observer) this._setActive(index); |
| this._updateEndControls(); |
| }); |
| } |
| _animateScroll(targetLeft, onComplete) { |
| if (this._scrollFrame !== null) { |
| cancelAnimationFrame(this._scrollFrame); |
| this._scrollFrame = null; |
| } |
| const startLeft = this._viewport.scrollLeft; |
| const distance = targetLeft - startLeft; |
| if (this._prefersReducedMotion() || typeof requestAnimationFrame === "undefined") { |
| this._viewport.scrollTo({ |
| left: targetLeft, |
| behavior: "instant" |
| }); |
| onComplete(); |
| return; |
| } |
| let startTime = null; |
| const step = (now) => { |
| if (startTime === null) startTime = now; |
| const progress = Math.min((now - startTime) / SCROLL_DURATION, 1); |
| this._viewport.scrollTo({ |
| left: startLeft + distance * easeInOutCubic(progress), |
| behavior: "instant" |
| }); |
| if (progress < 1) { |
| this._scrollFrame = requestAnimationFrame(step); |
| return; |
| } |
| this._viewport.scrollTo({ |
| left: targetLeft, |
| behavior: "instant" |
| }); |
| this._scrollFrame = null; |
| onComplete(); |
| }; |
| this._scrollFrame = requestAnimationFrame(step); |
| } |
| _scrollDelta(element) { |
| const viewportRect = this._viewport.getBoundingClientRect(); |
| const rect = element.getBoundingClientRect(); |
| if (this._element.classList.contains(CLASS_NAME_CENTER)) return rect.left + rect.width / 2 - (viewportRect.left + viewportRect.width / 2); |
| const padStart = Number.parseFloat(getComputedStyle(this._viewport).scrollPaddingInlineStart) || 0; |
| return isRTL() ? rect.right - (viewportRect.right - padStart) : rect.left - (viewportRect.left + padStart); |
| } |
| _loopTransition(isNext) { |
| const items = this._getItems(); |
| const last = items.length - 1; |
| const fromIndex = this._activeIndex; |
| const toIndex = isNext ? 0 : last; |
| const direction = this._loopDirection(isNext); |
| if (EventHandler.trigger(this._element, EVENT_SLIDE, { |
| relatedTarget: items[toIndex], |
| direction, |
| from: fromIndex, |
| to: toIndex |
| }).defaultPrevented) return; |
| this._looping = true; |
| const clone = (isNext ? items[0] : items[last]).cloneNode(true); |
| clone.classList.add(CLASS_NAME_CLONE); |
| clone.classList.remove(CLASS_NAME_ACTIVE$3); |
| clone.removeAttribute("id"); |
| for (const node of SelectorEngine.find("[id]", clone)) node.removeAttribute("id"); |
| clone.setAttribute("aria-hidden", "true"); |
| clone.inert = true; |
| this._viewport.style.scrollSnapType = "none"; |
| if (isNext) this._viewport.append(clone); |
| else { |
| this._viewport.prepend(clone); |
| this._jumpScroll(this._scrollDelta(items[fromIndex])); |
| } |
| this._animateScroll(this._viewport.scrollLeft + this._scrollDelta(clone), () => { |
| clone.remove(); |
| this._jumpScroll(this._scrollDelta(items[toIndex])); |
| this._activeIndex = toIndex; |
| this._refreshActiveState(); |
| EventHandler.trigger(this._element, EVENT_SLID, { |
| relatedTarget: items[toIndex], |
| direction, |
| from: fromIndex, |
| to: toIndex |
| }); |
| this._viewport.style.scrollSnapType = ""; |
| this._looping = false; |
| }); |
| } |
| _loopDirection(isNext) { |
| if (isRTL()) return isNext ? DIRECTION_RIGHT : DIRECTION_LEFT; |
| return isNext ? DIRECTION_LEFT : DIRECTION_RIGHT; |
| } |
| _jumpScroll(delta) { |
| this._viewport.style.scrollSnapType = "none"; |
| this._viewport.scrollBy({ |
| left: delta, |
| top: 0, |
| behavior: "instant" |
| }); |
| } |
| _fadeTo(index) { |
| this._setActive(index); |
| } |
| _setActive(index) { |
| const items = this._getItems(); |
| if (index === this._activeIndex || !items[index]) return; |
| const from = this._activeIndex; |
| this._activeIndex = index; |
| this._refreshActiveState(); |
| EventHandler.trigger(this._element, EVENT_SLID, { |
| relatedTarget: items[index], |
| direction: this._direction(from, index), |
| from, |
| to: index |
| }); |
| } |
| _refreshActiveState() { |
| const items = this._getItems(); |
| for (const [index, item] of items.entries()) item.classList.toggle(CLASS_NAME_ACTIVE$3, index === this._activeIndex); |
| this._setActiveIndicatorElement(this._activeIndex); |
| this._updateEndControls(); |
| } |
| _updateEndControls() { |
| if (this._config.ends !== ENDS_STOP) return; |
| const viewport = this._viewport; |
| const maxScroll = viewport.scrollWidth - viewport.clientWidth; |
| let atStart; |
| let atEnd; |
| if (maxScroll > 0) { |
| const progress = Math.abs(viewport.scrollLeft); |
| atStart = progress <= 1; |
| atEnd = progress >= maxScroll - 1; |
| } else { |
| const last = this._getItems().length - 1; |
| atStart = this._activeIndex <= 0; |
| atEnd = this._activeIndex >= last; |
| } |
| this._setControlsDisabled(this._prevControls, atStart); |
| this._setControlsDisabled(this._nextControls, atEnd); |
| } |
| _setControlsDisabled(controls, disabled) { |
| for (const control of controls) { |
| if (disabled && control === document.activeElement) ((controls === this._prevControls ? this._nextControls : this._prevControls)[0] ?? this._viewport).focus({ preventScroll: true }); |
| control.disabled = disabled; |
| } |
| } |
| _setActiveIndicatorElement(index) { |
| if (!this._indicatorsElement) return; |
| const active = SelectorEngine.findOne(SELECTOR_ACTIVE, this._indicatorsElement); |
| if (active) { |
| active.classList.remove(CLASS_NAME_ACTIVE$3); |
| active.removeAttribute("aria-current"); |
| } |
| const newActive = SelectorEngine.findOne(`[data-bs-slide-to="${index}"]`, this._indicatorsElement); |
| if (newActive) { |
| newActive.classList.add(CLASS_NAME_ACTIVE$3); |
| newActive.setAttribute("aria-current", "true"); |
| } |
| } |
| _normalizeIndex(index, length) { |
| if (Number.isNaN(index) || length === 0) return null; |
| if (index < 0) return this._wrapsAround() ? length - 1 : null; |
| if (index > length - 1) return this._wrapsAround() ? 0 : null; |
| return index; |
| } |
| _wrapsAround() { |
| return this._config.ends === ENDS_WRAP || this._config.ends === ENDS_LOOP; |
| } |
| _canLoop() { |
| if (this._isFade() || this._getItems().length < 2) return false; |
| const styles = getComputedStyle(this._element); |
| const num = (name) => Number.parseFloat(styles.getPropertyValue(name)) || 0; |
| return (num("--bs-carousel-items") || 1) === 1 && num("--bs-carousel-items-peek") === 0 && !this._element.classList.contains(CLASS_NAME_CENTER) && !this._element.classList.contains(CLASS_NAME_AUTO); |
| } |
| _direction(from, to) { |
| const isNext = to > from; |
| if (isRTL()) return isNext ? DIRECTION_RIGHT : DIRECTION_LEFT; |
| return isNext ? DIRECTION_LEFT : DIRECTION_RIGHT; |
| } |
| _scheduleAutoplay(index = this._activeIndex) { |
| const interval = this._itemInterval(index); |
| this._element.style.setProperty(PROPERTY_INTERVAL, `${interval}ms`); |
| this._interval = setTimeout(() => { |
| const upcoming = this._upcomingIndex(); |
| this.nextWhenVisible(); |
| if (upcoming === null) { |
| this.pause(); |
| return; |
| } |
| this._scheduleAutoplay(upcoming); |
| }, interval); |
| } |
| _upcomingIndex() { |
| return this._normalizeIndex(this._navIndex() + 1, this._getItems().length); |
| } |
| _itemInterval(index = this._activeIndex) { |
| const item = this._getItems()[index]; |
| const interval = item ? Number.parseInt(item.getAttribute("data-bs-interval"), 10) : NaN; |
| return Number.isNaN(interval) ? this._config.interval : interval; |
| } |
| _maybeEnableCycle() { |
| if (!this._playing) return; |
| this.cycle(); |
| } |
| _pauseFromInteraction() { |
| this._playing = false; |
| this.pause(); |
| this._updatePlayPauseControl(); |
| } |
| _togglePlayPause() { |
| if (this._playing) { |
| this._pauseFromInteraction(); |
| return; |
| } |
| this._playing = true; |
| this.cycle(); |
| this._updatePlayPauseControl(); |
| } |
| _updatePlayPauseControl() { |
| if (!this._playPauseElement) return; |
| this._playPauseElement.classList.toggle(CLASS_NAME_PAUSED, !this._playing); |
| const label = this._playPauseElement.getAttribute(this._playing ? "data-bs-pause-label" : "data-bs-play-label"); |
| if (label) this._playPauseElement.setAttribute("aria-label", label); |
| } |
| _isFade() { |
| return this._element.classList.contains(CLASS_NAME_FADE); |
| } |
| _prefersReducedMotion() { |
| return typeof window !== "undefined" && typeof window.matchMedia === "function" && window.matchMedia("(prefers-reduced-motion: reduce)").matches; |
| } |
| _getItems() { |
| return SelectorEngine.find(SELECTOR_ITEM, this._element); |
| } |
| _clearInterval() { |
| if (this._interval) { |
| clearTimeout(this._interval); |
| this._interval = null; |
| } |
| } |
| }; |
| /** |
| * Data API implementation |
| */ |
| EventHandler.on(document, EVENT_CLICK_DATA_API$7, SELECTOR_DATA_SLIDE, function(event) { |
| const target = SelectorEngine.getElementFromSelector(this); |
| if (!target || !target.classList.contains(CLASS_NAME_CAROUSEL)) return; |
| event.preventDefault(); |
| const carousel = Carousel.getOrCreateInstance(target); |
| carousel._pauseFromInteraction(); |
| const slideIndex = this.getAttribute("data-bs-slide-to"); |
| if (slideIndex) { |
| carousel.to(slideIndex); |
| return; |
| } |
| if (Manipulator.getDataAttribute(this, "slide") === "next") { |
| carousel.next(); |
| return; |
| } |
| carousel.prev(); |
| }); |
| EventHandler.on(document, EVENT_CLICK_DATA_API$7, SELECTOR_PLAY_PAUSE, function(event) { |
| const target = SelectorEngine.getElementFromSelector(this); |
| if (!target || !target.classList.contains(CLASS_NAME_CAROUSEL)) return; |
| event.preventDefault(); |
| Carousel.getOrCreateInstance(target)._togglePlayPause(); |
| }); |
| EventHandler.on(window, EVENT_LOAD_DATA_API$3, () => { |
| const carousels = SelectorEngine.find(SELECTOR_DATA_AUTOPLAY); |
| for (const carousel of carousels) Carousel.getOrCreateInstance(carousel); |
| }); |
| //#endregion |
| //#region js/src/collapse.ts |
| /** |
| * -------------------------------------------------------------------------- |
| * Bootstrap collapse.ts |
| * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) |
| * -------------------------------------------------------------------------- |
| */ |
| /** |
| * Constants |
| */ |
| const NAME$18 = "collapse"; |
| const EVENT_KEY$15 = `.bs.collapse`; |
| const DATA_API_KEY$10 = ".data-api"; |
| const EVENT_SHOW$7 = `show${EVENT_KEY$15}`; |
| const EVENT_SHOWN$6 = `shown${EVENT_KEY$15}`; |
| const EVENT_HIDE$6 = `hide${EVENT_KEY$15}`; |
| const EVENT_HIDDEN$8 = `hidden${EVENT_KEY$15}`; |
| const EVENT_CLICK_DATA_API$6 = `click${EVENT_KEY$15}${DATA_API_KEY$10}`; |
| const CLASS_NAME_SHOW$5 = "show"; |
| const CLASS_NAME_COLLAPSE = "collapse"; |
| const CLASS_NAME_DEEPER_CHILDREN = `:scope .${CLASS_NAME_COLLAPSE} .${CLASS_NAME_COLLAPSE}`; |
| const SELECTOR_ACTIVES = ".collapse.show"; |
| const SELECTOR_DATA_TOGGLE$9 = "[data-bs-toggle=\"collapse\"]"; |
| const Default$17 = { parent: null }; |
| const DefaultType$17 = { parent: "(null|element)" }; |
| /** |
| * Class definition |
| */ |
| var Collapse = class Collapse extends BaseComponent { |
| constructor(element, config) { |
| super(element, config); |
| this._isTransitioning = false; |
| this._triggerArray = []; |
| const toggleList = SelectorEngine.find(SELECTOR_DATA_TOGGLE$9); |
| for (const elem of toggleList) { |
| const selector = SelectorEngine.getSelectorFromElement(elem); |
| const filterElement = SelectorEngine.find(selector).filter((foundElement) => foundElement === this._element); |
| if (selector !== null && filterElement.length) this._triggerArray.push(elem); |
| } |
| this._initializeChildren(); |
| if (!this._config.parent) this._setAriaExpanded(this._triggerArray, this._isShown()); |
| } |
| static get Default() { |
| return Default$17; |
| } |
| static get DefaultType() { |
| return DefaultType$17; |
| } |
| static get NAME() { |
| return NAME$18; |
| } |
| toggle() { |
| return this._isShown() ? this.hide() : this.show(); |
| } |
| async show() { |
| if (this._isTransitioning || this._isShown()) return; |
| let activeChildren = []; |
| if (this._config.parent) activeChildren = this._getFirstLevelChildren(SELECTOR_ACTIVES).filter((element) => element !== this._element && !this._sharesTrigger(element)).map((element) => Collapse.getOrCreateInstance(element)); |
| if (activeChildren.length && activeChildren[0]._isTransitioning) return; |
| if (EventHandler.trigger(this._element, EVENT_SHOW$7).defaultPrevented) return; |
| for (const activeInstance of activeChildren) activeInstance.hide(); |
| this._element.classList.add(CLASS_NAME_SHOW$5); |
| this._setAriaExpanded(this._triggerArray, true); |
| this._isTransitioning = true; |
| const complete = () => { |
| this._isTransitioning = false; |
| EventHandler.trigger(this._element, EVENT_SHOWN$6); |
| }; |
| await this._queueCallback(complete, this._element, this._isAnimated()); |
| } |
| async hide() { |
| if (this._isTransitioning || !this._isShown()) return; |
| if (EventHandler.trigger(this._element, EVENT_HIDE$6).defaultPrevented) return; |
| this._element.classList.remove(CLASS_NAME_SHOW$5); |
| for (const trigger of this._triggerArray) { |
| const element = SelectorEngine.getElementFromSelector(trigger); |
| if (element && !this._isShown(element)) this._setAriaExpanded([trigger], false); |
| } |
| this._isTransitioning = true; |
| const complete = () => { |
| this._isTransitioning = false; |
| EventHandler.trigger(this._element, EVENT_HIDDEN$8); |
| }; |
| await this._queueCallback(complete, this._element, this._isAnimated()); |
| } |
| _isShown(element = this._element) { |
| return element.classList.contains(CLASS_NAME_SHOW$5); |
| } |
| _isAnimated() { |
| return getTransitionDurationFromElement(this._element) > 0; |
| } |
| _sharesTrigger(element) { |
| return this._triggerArray.some((trigger) => SelectorEngine.getMultipleElementsFromSelector(trigger).includes(element)); |
| } |
| _configAfterMerge(config) { |
| config.parent = getElement(config.parent); |
| return config; |
| } |
| _initializeChildren() { |
| if (!this._config.parent) return; |
| const children = this._getFirstLevelChildren(SELECTOR_DATA_TOGGLE$9); |
| for (const element of children) { |
| const selected = SelectorEngine.getElementFromSelector(element); |
| if (selected) this._setAriaExpanded([element], this._isShown(selected)); |
| } |
| } |
| _getFirstLevelChildren(selector) { |
| const children = SelectorEngine.find(CLASS_NAME_DEEPER_CHILDREN, this._config.parent); |
| return SelectorEngine.find(selector, this._config.parent).filter((element) => !children.includes(element)); |
| } |
| _setAriaExpanded(triggerArray, isOpen) { |
| if (!triggerArray.length) return; |
| for (const element of triggerArray) setAriaAttribute(element, "aria-expanded", isOpen); |
| } |
| }; |
| /** |
| * Data API implementation |
| */ |
| EventHandler.on(document, EVENT_CLICK_DATA_API$6, SELECTOR_DATA_TOGGLE$9, function(event) { |
| if (event.target.tagName === "A" || event.delegateTarget && event.delegateTarget.tagName === "A") event.preventDefault(); |
| for (const element of SelectorEngine.getMultipleElementsFromSelector(this)) Collapse.getOrCreateInstance(element).toggle(); |
| }); |
| //#endregion |
| //#region js/src/util/floating-ui.ts |
| /** |
| * Breakpoints for responsive placement (matches SCSS $breakpoints) |
| */ |
| const BREAKPOINTS = { |
| sm: 576, |
| md: 768, |
| lg: 1024, |
| xl: 1280, |
| "2xl": 1536 |
| }; |
| /** |
| * Parse a placement string that may contain responsive prefixes |
| * Example: "bottom-start md:top-end lg:right" returns { xs: 'bottom-start', md: 'top-end', lg: 'right' } |
| * |
| * @param placementString - The placement string to parse |
| * @param defaultPlacement - The default placement to use for xs/base |
| * @returns Object with breakpoint keys and placement values, or null if not responsive |
| */ |
| const parseResponsivePlacement = (placementString, defaultPlacement = "bottom") => { |
| if (!placementString || !placementString.includes(":")) return null; |
| const parts = placementString.split(/\s+/); |
| const placements = { xs: defaultPlacement }; |
| for (const part of parts) if (part.includes(":")) { |
| const [breakpoint, placement] = part.split(":"); |
| if (BREAKPOINTS[breakpoint] !== void 0) placements[breakpoint] = placement; |
| } else placements.xs = part; |
| return placements; |
| }; |
| /** |
| * Get the active placement for the current viewport width |
| * |
| * @param responsivePlacements - Object with breakpoint keys and placement values |
| * @param defaultPlacement - Fallback placement |
| * @returns The active placement for current viewport |
| */ |
| const getResponsivePlacement = (responsivePlacements, defaultPlacement = "bottom") => { |
| if (!responsivePlacements) return defaultPlacement; |
| const viewportWidth = window.innerWidth; |
| let activePlacement = responsivePlacements.xs || defaultPlacement; |
| for (const breakpoint of [ |
| "sm", |
| "md", |
| "lg", |
| "xl", |
| "2xl" |
| ]) if (viewportWidth >= BREAKPOINTS[breakpoint] && responsivePlacements[breakpoint]) activePlacement = responsivePlacements[breakpoint]; |
| return activePlacement; |
| }; |
| /** |
| * Create media query listeners for responsive placement changes |
| * |
| * @param callback - Callback to run when breakpoint changes |
| * @returns Array of { mql, handler } objects for cleanup |
| */ |
| const createBreakpointListeners = (callback) => { |
| const listeners = []; |
| for (const breakpoint of Object.keys(BREAKPOINTS)) { |
| const minWidth = BREAKPOINTS[breakpoint]; |
| const mql = window.matchMedia(`(min-width: ${minWidth}px)`); |
| mql.addEventListener("change", callback); |
| listeners.push({ |
| mql, |
| handler: callback |
| }); |
| } |
| return listeners; |
| }; |
| /** |
| * Clean up media query listeners |
| * |
| * @param listeners - Array of { mql, handler } objects |
| */ |
| const disposeBreakpointListeners = (listeners) => { |
| for (const { mql, handler } of listeners) mql.removeEventListener("change", handler); |
| }; |
| /** |
| * Normalize an offset value into Floating UI's offset shape. |
| * A `[skidding, distance]` array becomes `{ mainAxis: distance, crossAxis: skidding }`; |
| * numbers and axis objects pass through unchanged. |
| */ |
| const toFloatingOffset = (value) => { |
| return Array.isArray(value) ? { |
| mainAxis: value[1] || 0, |
| crossAxis: value[0] || 0 |
| } : value; |
| }; |
| //#endregion |
| //#region js/src/menu.ts |
| /** |
| * -------------------------------------------------------------------------- |
| * Bootstrap menu.ts |
| * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) |
| * -------------------------------------------------------------------------- |
| */ |
| /** |
| * Constants |
| */ |
| const NAME$17 = "menu"; |
| const EVENT_KEY$14 = `.bs.menu`; |
| const DATA_API_KEY$9 = ".data-api"; |
| const ESCAPE_KEY$2 = "Escape"; |
| const TAB_KEY$1 = "Tab"; |
| const ARROW_UP_KEY$2 = "ArrowUp"; |
| const ARROW_DOWN_KEY$2 = "ArrowDown"; |
| const ARROW_LEFT_KEY$1 = "ArrowLeft"; |
| const ARROW_RIGHT_KEY$1 = "ArrowRight"; |
| const HOME_KEY$2 = "Home"; |
| const END_KEY$2 = "End"; |
| const ENTER_KEY$1 = "Enter"; |
| const SPACE_KEY$1 = " "; |
| const RIGHT_MOUSE_BUTTON = 2; |
| const SUBMENU_CLOSE_DELAY = 100; |
| const EVENT_HIDE$5 = `hide${EVENT_KEY$14}`; |
| const EVENT_HIDDEN$7 = `hidden${EVENT_KEY$14}`; |
| const EVENT_SHOW$6 = `show${EVENT_KEY$14}`; |
| const EVENT_SHOWN$5 = `shown${EVENT_KEY$14}`; |
| const EVENT_CLICK_DATA_API$5 = `click${EVENT_KEY$14}${DATA_API_KEY$9}`; |
| const EVENT_KEYDOWN_DATA_API = `keydown${EVENT_KEY$14}${DATA_API_KEY$9}`; |
| const EVENT_KEYUP_DATA_API = `keyup${EVENT_KEY$14}${DATA_API_KEY$9}`; |
| const CLASS_NAME_SHOW$4 = "show"; |
| const SELECTOR_DATA_TOGGLE$8 = "[data-bs-toggle=\"menu\"]:not(.disabled):not(:disabled)"; |
| const SELECTOR_MENU$2 = ".menu"; |
| const SELECTOR_SUBMENU = ".submenu"; |
| const SELECTOR_SUBMENU_TOGGLE = ".submenu > .menu-item"; |
| const SELECTOR_NAVBAR_NAV = ".navbar-nav"; |
| const SELECTOR_VISIBLE_ITEMS$1 = ".menu-item:not(.disabled):not(:disabled)"; |
| const DEFAULT_PLACEMENT = "bottom-start"; |
| const SUBMENU_PLACEMENT = "end-start"; |
| const resolveLogicalPlacement = (placement) => { |
| if (isRTL()) return placement.replace(/^start(?=-|$)/, "right").replace(/^end(?=-|$)/, "left"); |
| return placement.replace(/^start(?=-|$)/, "left").replace(/^end(?=-|$)/, "right"); |
| }; |
| const triangleSign = (p1, p2, p3) => (p1.x - p3.x) * (p2.y - p3.y) - (p2.x - p3.x) * (p1.y - p3.y); |
| const Default$16 = { |
| autoClose: true, |
| boundary: "clippingParents", |
| container: false, |
| display: "dynamic", |
| offset: [0, 2], |
| floatingConfig: null, |
| menu: null, |
| placement: DEFAULT_PLACEMENT, |
| reference: "toggle", |
| strategy: "absolute", |
| submenuTrigger: "both", |
| submenuDelay: SUBMENU_CLOSE_DELAY |
| }; |
| const DefaultType$16 = { |
| autoClose: "(boolean|string)", |
| boundary: "(string|element)", |
| container: "(string|element|boolean)", |
| display: "string", |
| offset: "(array|string|function)", |
| floatingConfig: "(null|object|function)", |
| menu: "(null|element)", |
| placement: "string", |
| reference: "(string|element|object)", |
| strategy: "string", |
| submenuTrigger: "string", |
| submenuDelay: "number" |
| }; |
| /** |
| * Class definition |
| */ |
| var Menu = class Menu extends BaseComponent { |
| static _openInstances = /* @__PURE__ */ new Set(); |
| constructor(element, config) { |
| if (typeof computePosition === "undefined") throw new TypeError("Bootstrap's menus require Floating UI (https://floating-ui.com)"); |
| super(element, config); |
| this._floatingCleanup = null; |
| this._mediaQueryListeners = []; |
| this._responsivePlacements = null; |
| this._parent = this._element.parentNode; |
| this._openSubmenus = /* @__PURE__ */ new Map(); |
| this._submenuCloseTimeouts = /* @__PURE__ */ new Map(); |
| this._hoverIntentData = null; |
| this._menu = this._config.menu || this._findMenu(); |
| if (!this._config.menu && this._menu) this._parent = this._findWrapper(this._menu); |
| this._isSubmenu = this._parent.classList?.contains("submenu"); |
| this._menuOriginalParent = this._menu?.parentNode; |
| this._parseResponsivePlacements(); |
| this._setupSubmenuListeners(); |
| this._initSubmenuTriggers(); |
| } |
| static get Default() { |
| return Default$16; |
| } |
| static get DefaultType() { |
| return DefaultType$16; |
| } |
| static get NAME() { |
| return NAME$17; |
| } |
| toggle() { |
| return this._isShown() ? this.hide() : this.show(); |
| } |
| async show() { |
| if (isDisabled(this._element) || this._isShown()) return; |
| const relatedTarget = { relatedTarget: this._element }; |
| if (EventHandler.trigger(this._element, EVENT_SHOW$6, relatedTarget).defaultPrevented) return; |
| this._moveMenuToContainer(); |
| this._createFloating(); |
| if ("ontouchstart" in document.documentElement && !this._parent.closest(SELECTOR_NAVBAR_NAV)) for (const element of document.body.children) EventHandler.on(element, "mouseover", noop); |
| this._element.focus({ focusVisible: false }); |
| this._element.setAttribute("aria-expanded", "true"); |
| this._menu.classList.add(CLASS_NAME_SHOW$4); |
| this._element.classList.add(CLASS_NAME_SHOW$4); |
| if (this._parent) this._parent.classList.add(CLASS_NAME_SHOW$4); |
| Menu._openInstances.add(this); |
| await this._queueCallback(() => { |
| if (this._isShown()) EventHandler.trigger(this._element, EVENT_SHOWN$5, relatedTarget); |
| }, this._menu, this._isAnimated()); |
| } |
| async hide() { |
| if (isDisabled(this._element) || !this._isShown()) return; |
| const relatedTarget = { relatedTarget: this._element }; |
| await this._completeHide(relatedTarget); |
| } |
| dispose() { |
| this._disposeFloating(); |
| this._restoreMenuToOriginalParent(); |
| this._disposeMediaQueryListeners(); |
| this._closeAllSubmenus(); |
| this._clearAllSubmenuTimeouts(); |
| Menu._openInstances.delete(this); |
| super.dispose(); |
| } |
| update() { |
| if (this._floatingCleanup) this._updateFloatingPosition(); |
| } |
| _findMenu() { |
| const wrapper = SelectorEngine.closest(this._element, `:has(${SELECTOR_MENU$2})`); |
| return SelectorEngine.next(this._element, SELECTOR_MENU$2)[0] || SelectorEngine.prev(this._element, SELECTOR_MENU$2)[0] || SelectorEngine.findOne(SELECTOR_MENU$2, wrapper || this._parent); |
| } |
| _findWrapper(menu) { |
| let wrapper = this._element.parentNode; |
| while (wrapper instanceof Element && !wrapper.contains(menu)) wrapper = wrapper.parentNode; |
| return wrapper instanceof Element ? wrapper : this._element.parentNode; |
| } |
| async _completeHide(relatedTarget) { |
| if (EventHandler.trigger(this._element, EVENT_HIDE$5, relatedTarget).defaultPrevented) return; |
| this._closeAllSubmenus(); |
| if ("ontouchstart" in document.documentElement) for (const element of document.body.children) EventHandler.off(element, "mouseover", noop); |
| this._menu.classList.remove(CLASS_NAME_SHOW$4); |
| this._element.classList.remove(CLASS_NAME_SHOW$4); |
| if (this._parent) this._parent.classList.remove(CLASS_NAME_SHOW$4); |
| this._element.setAttribute("aria-expanded", "false"); |
| Menu._openInstances.delete(this); |
| await this._queueCallback(() => { |
| if (this._isShown()) return; |
| this._disposeFloating(); |
| this._restoreMenuToOriginalParent(); |
| Manipulator.removeDataAttribute(this._menu, "placement"); |
| Manipulator.removeDataAttribute(this._menu, "display"); |
| EventHandler.trigger(this._element, EVENT_HIDDEN$7, relatedTarget); |
| }, this._menu, this._isAnimated()); |
| } |
| _getConfig(config) { |
| config = super._getConfig(config); |
| if (typeof config.reference === "object" && !isElement(config.reference) && typeof config.reference.getBoundingClientRect !== "function") throw new TypeError(`${NAME$17.toUpperCase()}: Option "reference" provided type "object" without a required "getBoundingClientRect" method.`); |
| return config; |
| } |
| _createFloating() { |
| if (this._config.display === "static") { |
| Manipulator.setDataAttribute(this._menu, "display", "static"); |
| return; |
| } |
| let referenceElement = this._element; |
| if (this._config.reference === "parent") referenceElement = this._parent; |
| else if (isElement(this._config.reference)) referenceElement = getElement(this._config.reference); |
| else if (typeof this._config.reference === "object") referenceElement = this._config.reference; |
| this._updateFloatingPosition(referenceElement); |
| this._floatingCleanup = autoUpdate(referenceElement, this._menu, () => this._updateFloatingPosition(referenceElement)); |
| } |
| async _updateFloatingPosition(referenceElement = null) { |
| if (!this._menu) return; |
| if (!referenceElement) if (this._config.reference === "parent") referenceElement = this._parent; |
| else if (isElement(this._config.reference)) referenceElement = getElement(this._config.reference); |
| else if (typeof this._config.reference === "object") referenceElement = this._config.reference; |
| else referenceElement = this._element; |
| const placement = this._getPlacement(); |
| const middleware = this._getFloatingMiddleware(); |
| const floatingConfig = this._getFloatingConfig(placement, middleware); |
| await this._applyFloatingPosition(referenceElement, this._menu, floatingConfig.placement, floatingConfig.middleware, floatingConfig.strategy); |
| } |
| _isShown() { |
| return this._menu.classList.contains(CLASS_NAME_SHOW$4); |
| } |
| _isAnimated() { |
| return getTransitionDurationFromElement(this._menu) > 0; |
| } |
| _getPlacement() { |
| const placement = this._responsivePlacements ? getResponsivePlacement(this._responsivePlacements, DEFAULT_PLACEMENT) : this._config.placement; |
| return resolveLogicalPlacement(placement); |
| } |
| _parseResponsivePlacements() { |
| this._responsivePlacements = parseResponsivePlacement(this._config.placement, DEFAULT_PLACEMENT); |
| if (this._responsivePlacements) this._setupMediaQueryListeners(); |
| } |
| _setupMediaQueryListeners() { |
| this._disposeMediaQueryListeners(); |
| this._mediaQueryListeners = createBreakpointListeners(() => { |
| if (this._isShown()) this._updateFloatingPosition(); |
| }); |
| } |
| _disposeMediaQueryListeners() { |
| disposeBreakpointListeners(this._mediaQueryListeners); |
| this._mediaQueryListeners = []; |
| } |
| _getOffset() { |
| const { offset: offsetConfig } = this._config; |
| if (typeof offsetConfig === "string") return offsetConfig.split(",").map((value) => Number.parseInt(value, 10)); |
| if (typeof offsetConfig === "function") return ({ placement, rects }) => { |
| return toFloatingOffset(offsetConfig({ |
| placement, |
| reference: rects.reference, |
| floating: rects.floating |
| }, this._element)); |
| }; |
| return offsetConfig; |
| } |
| _getFloatingMiddleware() { |
| const offsetValue = this._getOffset(); |
| return [ |
| offset(typeof offsetValue === "function" ? offsetValue : toFloatingOffset(offsetValue)), |
| flip({ |
| fallbackPlacements: this._getFallbackPlacements(), |
| fallbackStrategy: "initialPlacement" |
| }), |
| shift({ boundary: this._config.boundary === "clippingParents" ? "clippingAncestors" : this._config.boundary }) |
| ]; |
| } |
| _getFallbackPlacements() { |
| return { |
| bottom: [ |
| "top", |
| "bottom-start", |
| "bottom-end", |
| "top-start", |
| "top-end" |
| ], |
| "bottom-start": [ |
| "top-start", |
| "bottom-end", |
| "top-end" |
| ], |
| "bottom-end": [ |
| "top-end", |
| "bottom-start", |
| "top-start" |
| ], |
| top: [ |
| "bottom", |
| "top-start", |
| "top-end", |
| "bottom-start", |
| "bottom-end" |
| ], |
| "top-start": [ |
| "bottom-start", |
| "top-end", |
| "bottom-end" |
| ], |
| "top-end": [ |
| "bottom-end", |
| "top-start", |
| "bottom-start" |
| ], |
| right: [ |
| "left", |
| "right-start", |
| "right-end", |
| "left-start", |
| "left-end" |
| ], |
| "right-start": [ |
| "left-start", |
| "right-end", |
| "left-end", |
| "top-start", |
| "bottom-start" |
| ], |
| "right-end": [ |
| "left-end", |
| "right-start", |
| "left-start", |
| "top-end", |
| "bottom-end" |
| ], |
| left: [ |
| "right", |
| "left-start", |
| "left-end", |
| "right-start", |
| "right-end" |
| ], |
| "left-start": [ |
| "right-start", |
| "left-end", |
| "right-end", |
| "top-start", |
| "bottom-start" |
| ], |
| "left-end": [ |
| "right-end", |
| "left-start", |
| "right-start", |
| "top-end", |
| "bottom-end" |
| ] |
| }[this._getPlacement()] || [ |
| "top", |
| "bottom", |
| "right", |
| "left" |
| ]; |
| } |
| _getFloatingConfig(placement, middleware) { |
| const defaultConfig = { |
| placement, |
| middleware, |
| strategy: this._config.strategy |
| }; |
| return { |
| ...defaultConfig, |
| ...execute(this._config.floatingConfig, [void 0, defaultConfig]) |
| }; |
| } |
| _disposeFloating() { |
| if (this._floatingCleanup) { |
| this._floatingCleanup(); |
| this._floatingCleanup = null; |
| } |
| } |
| _getContainer() { |
| const { container } = this._config; |
| if (container === false) return null; |
| return container === true ? document.body : getElement(container); |
| } |
| _moveMenuToContainer() { |
| const container = this._getContainer(); |
| if (!container || !this._menu) return; |
| if (this._menu.parentNode !== container) container.append(this._menu); |
| } |
| _restoreMenuToOriginalParent() { |
| if (!this._menuOriginalParent || !this._menu) return; |
| if (this._menu.parentNode !== this._menuOriginalParent) this._menuOriginalParent.append(this._menu); |
| } |
| async _applyFloatingPosition(reference, floating, placement, middleware, strategy = "absolute") { |
| if (!floating.isConnected) return null; |
| const { x, y, placement: finalPlacement } = await computePosition(reference, floating, { |
| placement, |
| middleware, |
| strategy |
| }); |
| if (!floating.isConnected) return null; |
| Object.assign(floating.style, { |
| position: strategy, |
| left: `${x}px`, |
| top: `${y}px`, |
| margin: "0" |
| }); |
| Manipulator.setDataAttribute(floating, "placement", finalPlacement); |
| return finalPlacement; |
| } |
| _setupSubmenuListeners() { |
| if (this._config.submenuTrigger === "hover" || this._config.submenuTrigger === "both") { |
| EventHandler.on(this._menu, "mouseenter", SELECTOR_SUBMENU_TOGGLE, (event) => { |
| this._onSubmenuTriggerEnter(event); |
| }); |
| EventHandler.on(this._menu, "mouseleave", SELECTOR_SUBMENU, (event) => { |
| this._onSubmenuLeave(event); |
| }); |
| EventHandler.on(this._menu, "mousemove", (event) => { |
| this._trackMousePosition(event); |
| }); |
| } |
| if (this._config.submenuTrigger === "click" || this._config.submenuTrigger === "both") EventHandler.on(this._menu, "click", SELECTOR_SUBMENU_TOGGLE, (event) => { |
| this._onSubmenuTriggerClick(event); |
| }); |
| } |
| _onSubmenuTriggerEnter(event) { |
| const trigger = event.target.closest(SELECTOR_SUBMENU_TOGGLE); |
| if (!trigger) return; |
| const submenuWrapper = trigger.closest(SELECTOR_SUBMENU); |
| const submenu = SelectorEngine.findOne(SELECTOR_MENU$2, submenuWrapper); |
| if (!submenu) return; |
| this._cancelSubmenuCloseTimeout(submenu); |
| this._closeSiblingSubmenus(submenuWrapper); |
| this._openSubmenu(trigger, submenu, submenuWrapper); |
| } |
| _onSubmenuLeave(event) { |
| const submenuWrapper = event.target.closest(SELECTOR_SUBMENU); |
| const submenu = SelectorEngine.findOne(SELECTOR_MENU$2, submenuWrapper); |
| if (!submenu || !this._openSubmenus.has(submenu)) return; |
| if (this._isMovingTowardSubmenu(event, submenu)) return; |
| this._scheduleSubmenuClose(submenu, submenuWrapper); |
| } |
| _onSubmenuTriggerClick(event) { |
| const trigger = event.target.closest(SELECTOR_SUBMENU_TOGGLE); |
| if (!trigger) return; |
| event.preventDefault(); |
| event.stopPropagation(); |
| const submenuWrapper = trigger.closest(SELECTOR_SUBMENU); |
| const submenu = SelectorEngine.findOne(SELECTOR_MENU$2, submenuWrapper); |
| if (!submenu) return; |
| if (this._openSubmenus.has(submenu)) this._closeSubmenu(submenu, submenuWrapper); |
| else { |
| this._closeSiblingSubmenus(submenuWrapper); |
| this._openSubmenu(trigger, submenu, submenuWrapper); |
| } |
| } |
| _initSubmenuTriggers() { |
| if (!this._menu) return; |
| for (const trigger of SelectorEngine.find(SELECTOR_SUBMENU_TOGGLE, this._menu)) { |
| if (!SelectorEngine.findOne(SELECTOR_MENU$2, trigger.parentElement)) continue; |
| trigger.setAttribute("aria-haspopup", "true"); |
| if (!trigger.hasAttribute("aria-expanded")) trigger.setAttribute("aria-expanded", "false"); |
| } |
| } |
| _openSubmenu(trigger, submenu, submenuWrapper) { |
| if (this._openSubmenus.has(submenu)) return; |
| trigger.setAttribute("aria-expanded", "true"); |
| trigger.setAttribute("aria-haspopup", "true"); |
| submenu.style.opacity = "0"; |
| submenu.classList.add(CLASS_NAME_SHOW$4); |
| submenuWrapper.classList.add(CLASS_NAME_SHOW$4); |
| const cleanup = this._createSubmenuFloating(trigger, submenu, submenuWrapper); |
| this._openSubmenus.set(submenu, cleanup); |
| EventHandler.on(submenu, "mouseenter", () => { |
| this._cancelSubmenuCloseTimeout(submenu); |
| }); |
| } |
| _closeSubmenu(submenu, submenuWrapper) { |
| if (!this._openSubmenus.has(submenu)) return; |
| const nestedSubmenus = SelectorEngine.find(`${SELECTOR_SUBMENU} ${SELECTOR_MENU$2}.${CLASS_NAME_SHOW$4}`, submenu); |
| for (const nested of nestedSubmenus) { |
| const nestedWrapper = nested.closest(SELECTOR_SUBMENU); |
| this._closeSubmenu(nested, nestedWrapper); |
| } |
| const trigger = SelectorEngine.findOne(SELECTOR_SUBMENU_TOGGLE, submenuWrapper); |
| const cleanup = this._openSubmenus.get(submenu); |
| if (cleanup) cleanup(); |
| this._openSubmenus.delete(submenu); |
| EventHandler.off(submenu, "mouseenter"); |
| if (trigger) trigger.setAttribute("aria-expanded", "false"); |
| submenu.classList.remove(CLASS_NAME_SHOW$4); |
| submenuWrapper.classList.remove(CLASS_NAME_SHOW$4); |
| submenu.style.opacity = ""; |
| } |
| _closeAllSubmenus() { |
| for (const [submenu] of this._openSubmenus) { |
| const submenuWrapper = submenu.closest(SELECTOR_SUBMENU); |
| this._closeSubmenu(submenu, submenuWrapper); |
| } |
| } |
| _closeSiblingSubmenus(currentSubmenuWrapper) { |
| const parent = currentSubmenuWrapper.parentNode; |
| const siblingSubmenus = SelectorEngine.find(`${SELECTOR_SUBMENU} > ${SELECTOR_MENU$2}.${CLASS_NAME_SHOW$4}`, parent); |
| for (const siblingMenu of siblingSubmenus) { |
| const siblingWrapper = siblingMenu.closest(SELECTOR_SUBMENU); |
| if (siblingWrapper !== currentSubmenuWrapper) this._closeSubmenu(siblingMenu, siblingWrapper); |
| } |
| } |
| _createSubmenuFloating(trigger, submenu, submenuWrapper) { |
| const referenceElement = submenuWrapper; |
| const placement = resolveLogicalPlacement(SUBMENU_PLACEMENT); |
| const middleware = [ |
| offset({ |
| mainAxis: 0, |
| crossAxis: -4 |
| }), |
| flip({ fallbackPlacements: [ |
| resolveLogicalPlacement("start-start"), |
| resolveLogicalPlacement("end-end"), |
| resolveLogicalPlacement("start-end") |
| ] }), |
| shift({ padding: 8 }) |
| ]; |
| const updatePosition = () => this._applyFloatingPosition(referenceElement, submenu, placement, middleware).then((finalPlacement) => { |
| submenu.style.opacity = ""; |
| return finalPlacement; |
| }); |
| updatePosition(); |
| return autoUpdate(referenceElement, submenu, updatePosition); |
| } |
| _scheduleSubmenuClose(submenu, submenuWrapper) { |
| this._cancelSubmenuCloseTimeout(submenu); |
| const timeoutId = setTimeout(() => { |
| this._closeSubmenu(submenu, submenuWrapper); |
| this._submenuCloseTimeouts.delete(submenu); |
| }, this._config.submenuDelay); |
| this._submenuCloseTimeouts.set(submenu, timeoutId); |
| } |
| _cancelSubmenuCloseTimeout(submenu) { |
| const timeoutId = this._submenuCloseTimeouts.get(submenu); |
| if (timeoutId) { |
| clearTimeout(timeoutId); |
| this._submenuCloseTimeouts.delete(submenu); |
| } |
| } |
| _clearAllSubmenuTimeouts() { |
| for (const timeoutId of this._submenuCloseTimeouts.values()) clearTimeout(timeoutId); |
| this._submenuCloseTimeouts.clear(); |
| } |
| _trackMousePosition(event) { |
| this._hoverIntentData = { |
| x: event.clientX, |
| y: event.clientY, |
| timestamp: Date.now() |
| }; |
| } |
| _isMovingTowardSubmenu(event, submenu) { |
| if (!this._hoverIntentData) return false; |
| const submenuRect = submenu.getBoundingClientRect(); |
| const currentPos = { |
| x: event.clientX, |
| y: event.clientY |
| }; |
| const lastPos = { |
| x: this._hoverIntentData.x, |
| y: this._hoverIntentData.y |
| }; |
| const targetX = isRTL() ? submenuRect.right : submenuRect.left; |
| const topCorner = { |
| x: targetX, |
| y: submenuRect.top |
| }; |
| const bottomCorner = { |
| x: targetX, |
| y: submenuRect.bottom |
| }; |
| return this._pointInTriangle(currentPos, lastPos, topCorner, bottomCorner); |
| } |
| _pointInTriangle(point, v1, v2, v3) { |
| const d1 = triangleSign(point, v1, v2); |
| const d2 = triangleSign(point, v2, v3); |
| const d3 = triangleSign(point, v3, v1); |
| return !((d1 < 0 || d2 < 0 || d3 < 0) && (d1 > 0 || d2 > 0 || d3 > 0)); |
| } |
| _getItemsInMenu(menu) { |
| return SelectorEngine.find(`:scope > ${SELECTOR_VISIBLE_ITEMS$1}, :scope > ${SELECTOR_SUBMENU} > ${SELECTOR_VISIBLE_ITEMS$1}`, menu).filter((element) => isVisible(element)); |
| } |
| _selectMenuItem({ key, target }) { |
| const currentMenu = target.closest(SELECTOR_MENU$2) || this._menu; |
| const items = this._getItemsInMenu(currentMenu); |
| if (!items.length) return; |
| const nextItem = getNextActiveElement(items, target, key === ARROW_DOWN_KEY$2, !items.includes(target)); |
| nextItem.focus(); |
| this._closeUnrelatedSubmenus(currentMenu, nextItem); |
| } |
| _closeUnrelatedSubmenus(currentMenu, focusedElement) { |
| for (const [submenu] of this._openSubmenus) { |
| const submenuWrapper = submenu.closest(SELECTOR_SUBMENU); |
| if (!submenuWrapper || submenuWrapper.parentElement !== currentMenu || submenuWrapper.contains(focusedElement)) continue; |
| this._closeSubmenu(submenu, submenuWrapper); |
| } |
| } |
| _handleSubmenuKeydown(event) { |
| const { key, target } = event; |
| const isRtl = isRTL(); |
| const enterKey = isRtl ? ARROW_LEFT_KEY$1 : ARROW_RIGHT_KEY$1; |
| const exitKey = isRtl ? ARROW_RIGHT_KEY$1 : ARROW_LEFT_KEY$1; |
| const submenuWrapper = target.closest(SELECTOR_SUBMENU); |
| const isSubmenuToggle = target.matches(SELECTOR_SUBMENU_TOGGLE); |
| if ((key === ENTER_KEY$1 || key === SPACE_KEY$1 || key === enterKey) && submenuWrapper && isSubmenuToggle) { |
| event.preventDefault(); |
| event.stopPropagation(); |
| const submenu = SelectorEngine.findOne(SELECTOR_MENU$2, submenuWrapper); |
| if (submenu) { |
| this._closeSiblingSubmenus(submenuWrapper); |
| this._openSubmenu(target, submenu, submenuWrapper); |
| requestAnimationFrame(() => { |
| const firstItem = SelectorEngine.findOne(SELECTOR_VISIBLE_ITEMS$1, submenu); |
| if (firstItem) firstItem.focus(); |
| }); |
| } |
| return true; |
| } |
| if (key === exitKey) { |
| const currentMenu = target.closest(SELECTOR_MENU$2); |
| const parentSubmenuWrapper = currentMenu?.closest(SELECTOR_SUBMENU); |
| if (parentSubmenuWrapper) { |
| event.preventDefault(); |
| event.stopPropagation(); |
| const parentTrigger = SelectorEngine.findOne(SELECTOR_SUBMENU_TOGGLE, parentSubmenuWrapper); |
| this._closeSubmenu(currentMenu, parentSubmenuWrapper); |
| if (parentTrigger) parentTrigger.focus(); |
| return true; |
| } |
| } |
| if (key === HOME_KEY$2 || key === END_KEY$2) { |
| event.preventDefault(); |
| event.stopPropagation(); |
| const currentMenu = target.closest(SELECTOR_MENU$2); |
| const items = this._getItemsInMenu(currentMenu); |
| if (items.length) { |
| const targetItem = key === HOME_KEY$2 ? items[0] : items.at(-1); |
| targetItem.focus(); |
| this._closeUnrelatedSubmenus(currentMenu, targetItem); |
| } |
| return true; |
| } |
| return false; |
| } |
| static clearMenus(event) { |
| if (event.button === RIGHT_MOUSE_BUTTON || event.type === "keyup" && event.key !== TAB_KEY$1) return; |
| for (const instance of Menu._openInstances) { |
| if (instance._config.autoClose === false) continue; |
| const composedPath = event.composedPath(); |
| const isMenuTarget = composedPath.includes(instance._menu); |
| if (composedPath.includes(instance._element) || instance._config.autoClose === "inside" && !isMenuTarget || instance._config.autoClose === "outside" && isMenuTarget) continue; |
| const formAncestor = event.target.closest?.("form"); |
| const isInsideMenuForm = Boolean(formAncestor) && instance._menu.contains(formAncestor); |
| if (instance._menu.contains(event.target) && (event.type === "keyup" && event.key === TAB_KEY$1 || /input|select|option|textarea|form/i.test(event.target.tagName) || isInsideMenuForm)) continue; |
| const relatedTarget = { relatedTarget: instance._element }; |
| if (event.type === "click") relatedTarget.clickEvent = event; |
| instance._completeHide(relatedTarget); |
| } |
| } |
| static _getToggleFromKeydownContext(element, event) { |
| if (element.matches(SELECTOR_DATA_TOGGLE$8)) return element; |
| for (const instance of Menu._openInstances) if (instance._element === event.target || instance._menu?.contains(event.target)) return instance._element; |
| return SelectorEngine.prev(element, SELECTOR_DATA_TOGGLE$8)[0] || SelectorEngine.next(element, SELECTOR_DATA_TOGGLE$8)[0] || SelectorEngine.findOne(SELECTOR_DATA_TOGGLE$8, event.delegateTarget.parentNode); |
| } |
| static dataApiKeydownHandler(event) { |
| const isInput = /input|textarea/i.test(event.target.tagName) || event.target.isContentEditable; |
| const isEscapeEvent = event.key === ESCAPE_KEY$2; |
| const isUpOrDownEvent = [ARROW_UP_KEY$2, ARROW_DOWN_KEY$2].includes(event.key); |
| const isLeftOrRightEvent = [ARROW_LEFT_KEY$1, ARROW_RIGHT_KEY$1].includes(event.key); |
| const isHomeOrEndEvent = [HOME_KEY$2, END_KEY$2].includes(event.key); |
| const isEnterOrSpaceEvent = [ENTER_KEY$1, SPACE_KEY$1].includes(event.key); |
| const isSubmenuTrigger = event.target.matches(SELECTOR_SUBMENU_TOGGLE); |
| if (!isUpOrDownEvent && !isEscapeEvent && !isLeftOrRightEvent && !isHomeOrEndEvent && !(isEnterOrSpaceEvent && isSubmenuTrigger)) return; |
| if (isInput && !isEscapeEvent) return; |
| const getToggleButton = Menu._getToggleFromKeydownContext(this, event); |
| if (!getToggleButton) return; |
| const instance = Menu.getOrCreateInstance(getToggleButton); |
| if ((isLeftOrRightEvent || isHomeOrEndEvent || isEnterOrSpaceEvent && isSubmenuTrigger) && instance._handleSubmenuKeydown(event)) return; |
| if (isUpOrDownEvent) { |
| event.preventDefault(); |
| event.stopPropagation(); |
| instance.show(); |
| instance._selectMenuItem(event); |
| return; |
| } |
| if (isEscapeEvent && instance._isShown()) { |
| event.preventDefault(); |
| event.stopPropagation(); |
| const currentMenu = event.target.closest(SELECTOR_MENU$2); |
| const parentSubmenuWrapper = currentMenu?.closest(SELECTOR_SUBMENU); |
| if (parentSubmenuWrapper && instance._openSubmenus.size > 0) { |
| const parentTrigger = SelectorEngine.findOne(SELECTOR_SUBMENU_TOGGLE, parentSubmenuWrapper); |
| instance._closeSubmenu(currentMenu, parentSubmenuWrapper); |
| if (parentTrigger) parentTrigger.focus(); |
| return; |
| } |
| instance.hide(); |
| getToggleButton.focus(); |
| } |
| } |
| }; |
| /** |
| * Data API implementation |
| */ |
| EventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_DATA_TOGGLE$8, Menu.dataApiKeydownHandler); |
| EventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_MENU$2, Menu.dataApiKeydownHandler); |
| EventHandler.on(document, EVENT_CLICK_DATA_API$5, Menu.clearMenus); |
| EventHandler.on(document, EVENT_KEYUP_DATA_API, Menu.clearMenus); |
| EventHandler.on(document, EVENT_CLICK_DATA_API$5, SELECTOR_DATA_TOGGLE$8, function(event) { |
| event.preventDefault(); |
| Menu.getOrCreateInstance(this).toggle(); |
| }); |
| //#endregion |
| //#region js/src/combobox.ts |
| /** |
| * -------------------------------------------------------------------------- |
| * Bootstrap combobox.ts |
| * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) |
| * -------------------------------------------------------------------------- |
| */ |
| /** |
| * Constants |
| */ |
| const NAME$16 = "combobox"; |
| const EVENT_KEY$13 = `.bs.combobox`; |
| const DATA_API_KEY$8 = ".data-api"; |
| const ESCAPE_KEY$1 = "Escape"; |
| const TAB_KEY = "Tab"; |
| const ARROW_UP_KEY$1 = "ArrowUp"; |
| const ARROW_DOWN_KEY$1 = "ArrowDown"; |
| const HOME_KEY$1 = "Home"; |
| const END_KEY$1 = "End"; |
| const ENTER_KEY = "Enter"; |
| const SPACE_KEY = " "; |
| const EVENT_CHANGE$3 = `change${EVENT_KEY$13}`; |
| const EVENT_SHOW$5 = `show${EVENT_KEY$13}`; |
| const EVENT_SHOWN$4 = `shown${EVENT_KEY$13}`; |
| const EVENT_HIDE$4 = `hide${EVENT_KEY$13}`; |
| const EVENT_HIDDEN$6 = `hidden${EVENT_KEY$13}`; |
| const EVENT_CLICK_DATA_API$4 = `click${EVENT_KEY$13}${DATA_API_KEY$8}`; |
| const CLASS_NAME_SHOW$3 = "show"; |
| const CLASS_NAME_SELECTED = "selected"; |
| const CLASS_NAME_PLACEHOLDER = "combobox-placeholder"; |
| const SELECTOR_DATA_TOGGLE$7 = "[data-bs-toggle=\"combobox\"]"; |
| const SELECTOR_MENU$1 = ".menu"; |
| const SELECTOR_MENU_ITEM = ".menu-item[data-bs-value]"; |
| const SELECTOR_VISIBLE_ITEMS = ".menu-item[data-bs-value]:not(.disabled):not(:disabled)"; |
| const SELECTOR_VALUE = ".combobox-value"; |
| const SELECTOR_SEARCH_INPUT = ".combobox-search-input"; |
| const SELECTOR_NO_RESULTS = ".combobox-no-results"; |
| const Default$15 = { |
| boundary: "clippingParents", |
| multiple: false, |
| name: null, |
| offset: [0, 2], |
| placeholder: "", |
| placement: "bottom-start", |
| search: false, |
| searchNormalize: false |
| }; |
| const DefaultType$15 = { |
| boundary: "(string|element)", |
| multiple: "boolean", |
| name: "(string|null)", |
| offset: "(array|string|function)", |
| placeholder: "string", |
| placement: "string", |
| search: "boolean", |
| searchNormalize: "boolean" |
| }; |
| /** |
| * Class definition |
| */ |
| var Combobox = class extends BaseComponent { |
| constructor(element, config) { |
| super(element, config); |
| this._toggle = this._element; |
| this._menu = SelectorEngine.next(this._toggle, SELECTOR_MENU$1)[0]; |
| this._valueDisplay = SelectorEngine.findOne(SELECTOR_VALUE, this._toggle); |
| this._searchInput = SelectorEngine.findOne(SELECTOR_SEARCH_INPUT, this._menu); |
| this._noResults = SelectorEngine.findOne(SELECTOR_NO_RESULTS, this._menu); |
| this._hiddenInput = null; |
| this._menuInstance = null; |
| this._createHiddenInput(); |
| this._createMenuInstance(); |
| this._syncInitialSelection(); |
| this._addEventListeners(); |
| } |
| static get Default() { |
| return Default$15; |
| } |
| static get DefaultType() { |
| return DefaultType$15; |
| } |
| static get NAME() { |
| return NAME$16; |
| } |
| toggle() { |
| return this._isShown() ? this.hide() : this.show(); |
| } |
| async show() { |
| if (isDisabled(this._toggle) || this._isShown()) return; |
| if (EventHandler.trigger(this._toggle, EVENT_SHOW$5).defaultPrevented) return; |
| this._menuInstance.show(); |
| if (this._searchInput) { |
| this._searchInput.value = ""; |
| this._filterItems(""); |
| requestAnimationFrame(() => this._searchInput.focus()); |
| } |
| EventHandler.trigger(this._toggle, EVENT_SHOWN$4); |
| } |
| async hide() { |
| if (!this._isShown()) return; |
| if (EventHandler.trigger(this._toggle, EVENT_HIDE$4).defaultPrevented) return; |
| this._menuInstance.hide(); |
| EventHandler.trigger(this._toggle, EVENT_HIDDEN$6); |
| } |
| dispose() { |
| if (this._menuInstance) { |
| this._menuInstance.dispose(); |
| this._menuInstance = null; |
| } |
| if (this._hiddenInput) { |
| this._hiddenInput.remove(); |
| this._hiddenInput = null; |
| } |
| EventHandler.off(this._menu, EVENT_KEY$13); |
| EventHandler.off(this._toggle, EVENT_KEY$13); |
| super.dispose(); |
| } |
| _isShown() { |
| return this._menu.classList.contains(CLASS_NAME_SHOW$3); |
| } |
| _createHiddenInput() { |
| const { name } = this._config; |
| if (!name) return; |
| this._hiddenInput = document.createElement("input"); |
| this._hiddenInput.type = "hidden"; |
| this._hiddenInput.name = name; |
| this._hiddenInput.value = ""; |
| this._toggle.parentNode.insertBefore(this._hiddenInput, this._toggle); |
| } |
| _createMenuInstance() { |
| this._menuInstance = new Menu(this._toggle, { |
| menu: this._menu, |
| autoClose: this._config.multiple ? "outside" : true, |
| boundary: this._config.boundary, |
| offset: this._config.offset, |
| placement: this._config.placement |
| }); |
| } |
| _syncInitialSelection() { |
| if (this._getSelectedItems().length > 0) { |
| this._updateToggleText(); |
| this._updateHiddenInput(); |
| } else this._showPlaceholder(); |
| } |
| _addEventListeners() { |
| EventHandler.on(this._menu, "click", SELECTOR_MENU_ITEM, (event) => { |
| const item = event.target.closest(SELECTOR_MENU_ITEM); |
| if (!item || isDisabled(item)) return; |
| event.preventDefault(); |
| event.stopPropagation(); |
| this._selectItem(item); |
| }); |
| EventHandler.on(this._toggle, "keydown", (event) => { |
| this._handleToggleKeydown(event); |
| }); |
| EventHandler.on(this._menu, "keydown", (event) => { |
| this._handleMenuKeydown(event); |
| }); |
| if (this._searchInput) { |
| EventHandler.on(this._searchInput, "input", () => { |
| this._filterItems(this._searchInput.value); |
| }); |
| EventHandler.on(this._searchInput, "keydown", (event) => { |
| if (event.key === ARROW_DOWN_KEY$1) { |
| event.preventDefault(); |
| const items = this._getVisibleItems(); |
| if (items.length > 0) items[0].focus(); |
| } |
| if (event.key === ESCAPE_KEY$1) { |
| this.hide(); |
| this._toggle.focus(); |
| } |
| }); |
| } |
| } |
| _selectItem(item) { |
| if (this._config.multiple) { |
| item.classList.toggle(CLASS_NAME_SELECTED); |
| setAriaAttribute(item, "aria-selected", item.classList.contains(CLASS_NAME_SELECTED)); |
| } else { |
| const previouslySelected = SelectorEngine.find(`.${CLASS_NAME_SELECTED}`, this._menu); |
| for (const prev of previouslySelected) { |
| prev.classList.remove(CLASS_NAME_SELECTED); |
| prev.setAttribute("aria-selected", "false"); |
| } |
| item.classList.add(CLASS_NAME_SELECTED); |
| item.setAttribute("aria-selected", "true"); |
| } |
| this._updateToggleText(); |
| this._updateHiddenInput(); |
| const value = this._config.multiple ? this._getSelectedItems().map((el) => el.dataset.bsValue) : item.dataset.bsValue; |
| EventHandler.trigger(this._toggle, EVENT_CHANGE$3, { |
| value, |
| item |
| }); |
| if (!this._config.multiple) { |
| this.hide(); |
| this._toggle.focus(); |
| } |
| } |
| _updateToggleText() { |
| const selectedItems = this._getSelectedItems(); |
| if (selectedItems.length === 0) { |
| this._showPlaceholder(); |
| return; |
| } |
| this._valueDisplay.classList.remove(CLASS_NAME_PLACEHOLDER); |
| if (this._config.multiple && selectedItems.length > 1) this._valueDisplay.textContent = `${selectedItems.length} selected`; |
| else { |
| const item = selectedItems[0]; |
| const label = SelectorEngine.findOne(".menu-item-content > span:first-child", item); |
| this._valueDisplay.textContent = label ? label.textContent : item.textContent.trim(); |
| } |
| } |
| _showPlaceholder() { |
| const { placeholder } = this._config; |
| if (placeholder) { |
| this._valueDisplay.textContent = placeholder; |
| this._valueDisplay.classList.add(CLASS_NAME_PLACEHOLDER); |
| } |
| } |
| _updateHiddenInput() { |
| if (!this._hiddenInput) return; |
| const values = this._getSelectedItems().map((el) => el.dataset.bsValue); |
| this._hiddenInput.value = this._config.multiple ? values.join(",") : values[0] || ""; |
| } |
| _getSelectedItems() { |
| return SelectorEngine.find(`.${CLASS_NAME_SELECTED}`, this._menu); |
| } |
| _getVisibleItems() { |
| return SelectorEngine.find(SELECTOR_VISIBLE_ITEMS, this._menu).filter((item) => isVisible(item)); |
| } |
| _filterItems(query) { |
| const normalizedQuery = this._normalizeText(query.toLowerCase().trim()); |
| const items = SelectorEngine.find(SELECTOR_MENU_ITEM, this._menu); |
| let visibleCount = 0; |
| for (const item of items) { |
| const text = this._normalizeText(item.textContent.toLowerCase().trim()); |
| const matches = !normalizedQuery || text.includes(normalizedQuery); |
| item.style.display = matches ? "" : "none"; |
| if (matches) visibleCount++; |
| } |
| if (this._noResults) this._noResults.classList.toggle("d-none", visibleCount > 0); |
| } |
| _normalizeText(text) { |
| if (this._config.searchNormalize) return text.normalize("NFD").replace(/[\u0300-\u036F]/g, ""); |
| return text; |
| } |
| _handleToggleKeydown(event) { |
| const { key } = event; |
| if (key === ARROW_DOWN_KEY$1 || key === ARROW_UP_KEY$1) { |
| event.preventDefault(); |
| if (!this._isShown()) this.show(); |
| const items = this._getVisibleItems(); |
| if (items.length > 0) (key === ARROW_DOWN_KEY$1 ? items[0] : items.at(-1)).focus(); |
| return; |
| } |
| if ((key === ENTER_KEY || key === SPACE_KEY) && !this._isShown()) { |
| event.preventDefault(); |
| this.show(); |
| } |
| } |
| _handleMenuKeydown(event) { |
| const { key, target } = event; |
| if (key === ESCAPE_KEY$1) { |
| event.preventDefault(); |
| event.stopPropagation(); |
| this.hide(); |
| this._toggle.focus(); |
| return; |
| } |
| if (key === TAB_KEY) { |
| this.hide(); |
| return; |
| } |
| const isInput = target.matches("input"); |
| if (key === ARROW_DOWN_KEY$1 || key === ARROW_UP_KEY$1) { |
| event.preventDefault(); |
| const items = this._getVisibleItems(); |
| if (items.length > 0) getNextActiveElement(items, target, key === ARROW_DOWN_KEY$1, !items.includes(target)).focus(); |
| return; |
| } |
| if (key === HOME_KEY$1 || key === END_KEY$1) { |
| event.preventDefault(); |
| const items = this._getVisibleItems(); |
| if (items.length > 0) (key === HOME_KEY$1 ? items[0] : items.at(-1)).focus(); |
| return; |
| } |
| if ((key === ENTER_KEY || key === SPACE_KEY) && !isInput) { |
| event.preventDefault(); |
| const item = target.closest(SELECTOR_MENU_ITEM); |
| if (item && !isDisabled(item)) this._selectItem(item); |
| } |
| } |
| }; |
| /** |
| * Data API implementation |
| */ |
| EventHandler.on(document, EVENT_CLICK_DATA_API$4, SELECTOR_DATA_TOGGLE$7, function(event) { |
| event.preventDefault(); |
| Combobox.getOrCreateInstance(this).toggle(); |
| }); |
| EventHandler.on(document, "DOMContentLoaded", () => { |
| for (const toggle of SelectorEngine.find(SELECTOR_DATA_TOGGLE$7)) Combobox.getOrCreateInstance(toggle); |
| }); |
| //#endregion |
| //#region js/src/datepicker.ts |
| /** |
| * -------------------------------------------------------------------------- |
| * Bootstrap datepicker.ts |
| * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) |
| * -------------------------------------------------------------------------- |
| */ |
| /** |
| * Constants |
| */ |
| const NAME$15 = "datepicker"; |
| const EVENT_KEY$12 = `.bs.datepicker`; |
| const DATA_API_KEY$7 = ".data-api"; |
| const EVENT_CHANGE$2 = `change${EVENT_KEY$12}`; |
| const EVENT_SHOW$4 = `show${EVENT_KEY$12}`; |
| const EVENT_SHOWN$3 = `shown${EVENT_KEY$12}`; |
| const EVENT_HIDE$3 = `hide${EVENT_KEY$12}`; |
| const EVENT_HIDDEN$5 = `hidden${EVENT_KEY$12}`; |
| const EVENT_FOCUSIN$3 = `focusin${EVENT_KEY$12}`; |
| const EVENT_CLICK_DATA_API$3 = `click${EVENT_KEY$12}${DATA_API_KEY$7}`; |
| const EVENT_FOCUSIN_DATA_API = `focusin${EVENT_KEY$12}${DATA_API_KEY$7}`; |
| const SELECTOR_DATA_TOGGLE$6 = "[data-bs-toggle=\"datepicker\"]"; |
| const HIDE_DELAY = 100; |
| const Default$14 = { |
| datepickerTheme: null, |
| dateMin: null, |
| dateMax: null, |
| dateFormat: null, |
| displayElement: null, |
| displayMonthsCount: 1, |
| firstWeekday: 1, |
| inline: false, |
| locale: "default", |
| positionElement: null, |
| selectedDates: [], |
| selectionMode: "single", |
| placement: "left", |
| vcpOptions: {} |
| }; |
| const DefaultType$14 = { |
| datepickerTheme: "(null|string)", |
| dateMin: "(null|string|number|object)", |
| dateMax: "(null|string|number|object)", |
| dateFormat: "(null|object|function)", |
| displayElement: "(null|string|element|boolean)", |
| displayMonthsCount: "number", |
| firstWeekday: "number", |
| inline: "boolean", |
| locale: "string", |
| positionElement: "(null|string|element)", |
| selectedDates: "array", |
| selectionMode: "string", |
| placement: "string", |
| vcpOptions: "object" |
| }; |
| /** |
| * Class definition |
| */ |
| var Datepicker = class extends BaseComponent { |
| constructor(element, config) { |
| super(element, config); |
| this._calendar = null; |
| this._isShown = false; |
| this._initCalendar(); |
| } |
| static get Default() { |
| return Default$14; |
| } |
| static get DefaultType() { |
| return DefaultType$14; |
| } |
| static get NAME() { |
| return NAME$15; |
| } |
| toggle() { |
| if (this._config.inline) return Promise.resolve(); |
| return this._isShown ? this.hide() : this.show(); |
| } |
| async show() { |
| if (this._config.inline) return; |
| if (!this._calendar || isDisabled(this._element) || this._isShown) return; |
| if (EventHandler.trigger(this._element, EVENT_SHOW$4).defaultPrevented) return; |
| this._calendar.show(); |
| this._isShown = true; |
| EventHandler.trigger(this._element, EVENT_SHOWN$3); |
| } |
| async hide() { |
| if (this._config.inline) return; |
| if (!this._calendar || !this._isShown) return; |
| if (EventHandler.trigger(this._element, EVENT_HIDE$3).defaultPrevented) return; |
| this._calendar.hide(); |
| this._isShown = false; |
| EventHandler.trigger(this._element, EVENT_HIDDEN$5); |
| } |
| dispose() { |
| if (this._themeObserver) { |
| this._themeObserver.disconnect(); |
| this._themeObserver = null; |
| } |
| if (this._onFocusIn) EventHandler.off(document, EVENT_FOCUSIN$3, this._onFocusIn); |
| if (this._calendar) this._calendar.destroy(); |
| this._calendar = null; |
| super.dispose(); |
| } |
| getSelectedDates() { |
| const dates = this._calendar?.context?.selectedDates; |
| return dates ? [...dates] : []; |
| } |
| setSelectedDates(dates) { |
| if (this._calendar) this._calendar.set({ selectedDates: dates }); |
| } |
| _initCalendar() { |
| this._isInput = this._element.tagName === "INPUT"; |
| this._isInline = this._config.inline; |
| if (this._isInline && !this._isInput) this._boundInput = this._element.querySelector("input[type=\"hidden\"], input[name]"); |
| this._positionElement = this._resolvePositionElement(); |
| this._displayElement = this._resolveDisplayElement(); |
| const calendarOptions = this._buildCalendarOptions(); |
| this._calendar = new Calendar(this._positionElement, calendarOptions); |
| this._calendar.init(); |
| this._setupThemeObserver(); |
| this._setupDismissOnFocus(); |
| if (this._isInput && this._element.value) this._parseInputValue(); |
| this._updateDisplayWithSelectedDates(); |
| } |
| _updateDisplayWithSelectedDates() { |
| const { selectedDates } = this._config; |
| if (!selectedDates || selectedDates.length === 0) return; |
| const formattedDate = this._formatDateForInput(selectedDates); |
| if (this._isInput) this._element.value = formattedDate; |
| if (this._boundInput) this._boundInput.value = selectedDates.join(","); |
| if (this._displayElement) this._displayElement.textContent = formattedDate; |
| } |
| _resolvePositionElement() { |
| let { positionElement } = this._config; |
| if (typeof positionElement === "string") positionElement = document.querySelector(positionElement); |
| if (!positionElement && this._isInput && !this._isInline) { |
| const parent = this._element.closest(".form-adorn"); |
| if (parent) positionElement = parent; |
| } |
| return positionElement || this._element; |
| } |
| _resolveDisplayElement() { |
| const { displayElement } = this._config; |
| if (typeof displayElement === "string") return document.querySelector(displayElement); |
| if (displayElement === true || displayElement === null && !this._isInput && !this._isInline) return this._element.querySelector("[data-bs-datepicker-display]") || this._element; |
| return displayElement; |
| } |
| _getThemeAncestor() { |
| return this._element.closest("[data-bs-theme]"); |
| } |
| _getEffectiveTheme() { |
| const { datepickerTheme } = this._config; |
| if (datepickerTheme) return datepickerTheme; |
| return this._getThemeAncestor()?.getAttribute("data-bs-theme") || null; |
| } |
| _syncThemeAttribute(element) { |
| if (!element) return; |
| const theme = this._getEffectiveTheme(); |
| if (theme) element.setAttribute("data-bs-theme", theme); |
| else element.removeAttribute("data-bs-theme"); |
| } |
| _setupThemeObserver() { |
| const ancestor = this._getThemeAncestor(); |
| if (!ancestor || this._config.datepickerTheme) return; |
| this._themeObserver = new MutationObserver(() => { |
| this._syncThemeAttribute(this._calendar?.context?.mainElement); |
| }); |
| this._themeObserver.observe(ancestor, { |
| attributes: true, |
| attributeFilter: ["data-bs-theme"] |
| }); |
| } |
| _setupDismissOnFocus() { |
| if (this._isInline) return; |
| this._onFocusIn = (event) => { |
| if (!this._isShown) return; |
| const { target } = event; |
| const mainElement = this._calendar?.context?.mainElement; |
| if (target instanceof Node && (this._element.contains(target) || mainElement?.contains(target))) return; |
| this.hide(); |
| }; |
| EventHandler.on(document, EVENT_FOCUSIN$3, this._onFocusIn); |
| } |
| _buildCalendarOptions() { |
| const theme = this._getEffectiveTheme(); |
| const vcpTheme = !theme || theme === "auto" ? "system" : theme; |
| const calendarOptions = { |
| ...this._config.vcpOptions, |
| inputMode: !this._isInline, |
| positionToInput: this._config.placement, |
| firstWeekday: this._config.firstWeekday, |
| locale: this._config.locale, |
| selectionDatesMode: this._config.selectionMode, |
| selectedDates: this._config.selectedDates, |
| displayMonthsCount: this._config.displayMonthsCount, |
| type: this._config.displayMonthsCount > 1 ? "multiple" : "default", |
| selectedTheme: vcpTheme, |
| themeAttrDetect: "[data-bs-theme]", |
| onClickDate: (self, event) => this._handleDateClick(self, event), |
| onInit: (self) => { |
| this._syncThemeAttribute(self.context.mainElement); |
| }, |
| onShow: () => { |
| if (!this._calendar) return; |
| this._isShown = true; |
| this._syncThemeAttribute(this._calendar.context.mainElement); |
| }, |
| onHide: () => { |
| this._isShown = false; |
| } |
| }; |
| if (this._config.selectedDates.length > 0) { |
| const firstDate = this._parseDate(this._config.selectedDates[0]); |
| calendarOptions.selectedMonth = firstDate.getMonth(); |
| calendarOptions.selectedYear = firstDate.getFullYear(); |
| } |
| if (this._config.dateMin) calendarOptions.dateMin = this._config.dateMin; |
| if (this._config.dateMax) calendarOptions.dateMax = this._config.dateMax; |
| return calendarOptions; |
| } |
| _handleDateClick(self, event) { |
| const selectedDates = [...self.context.selectedDates]; |
| if (selectedDates.length > 0) { |
| const formattedDate = this._formatDateForInput(selectedDates); |
| if (this._isInput) this._element.value = formattedDate; |
| if (this._boundInput) this._boundInput.value = selectedDates.join(","); |
| if (this._displayElement) this._displayElement.textContent = formattedDate; |
| } |
| EventHandler.trigger(this._element, EVENT_CHANGE$2, { |
| dates: selectedDates, |
| event |
| }); |
| this._maybeHideAfterSelection(selectedDates); |
| } |
| _maybeHideAfterSelection(selectedDates) { |
| if (this._isInline) return; |
| if (this._config.selectionMode === "single" && selectedDates.length > 0 || this._config.selectionMode === "multiple-ranged" && selectedDates.length >= 2) setTimeout(() => this.hide(), HIDE_DELAY); |
| } |
| _parseDate(dateStr) { |
| const [year, month, day] = dateStr.split("-"); |
| return new Date(year, month - 1, day); |
| } |
| _formatDate(dateStr) { |
| const date = this._parseDate(dateStr); |
| const locale = this._config.locale === "default" ? void 0 : this._config.locale; |
| const { dateFormat } = this._config; |
| if (typeof dateFormat === "function") return dateFormat(date, locale); |
| if (dateFormat && typeof dateFormat === "object") return new Intl.DateTimeFormat(locale, dateFormat).format(date); |
| return date.toLocaleDateString(locale); |
| } |
| _formatDateForInput(dates) { |
| if (dates.length === 0) return ""; |
| if (dates.length === 1) return this._formatDate(dates[0]); |
| const separator = this._config.selectionMode === "multiple-ranged" ? " – " : ", "; |
| return dates.map((d) => this._formatDate(d)).join(separator); |
| } |
| _parseInputValue() { |
| const value = this._element.value.trim(); |
| if (!value) return; |
| const date = new Date(value); |
| if (!Number.isNaN(date.getTime())) { |
| const formatted = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}-${String(date.getDate()).padStart(2, "0")}`; |
| this._calendar.set({ selectedDates: [formatted] }); |
| } |
| } |
| }; |
| /** |
| * Data API implementation |
| */ |
| EventHandler.on(document, EVENT_CLICK_DATA_API$3, SELECTOR_DATA_TOGGLE$6, function(event) { |
| if (this.tagName === "INPUT" || this.dataset.bsInline === "true") return; |
| event.preventDefault(); |
| Datepicker.getOrCreateInstance(this).toggle(); |
| }); |
| EventHandler.on(document, EVENT_FOCUSIN_DATA_API, SELECTOR_DATA_TOGGLE$6, function() { |
| if (this.tagName !== "INPUT") return; |
| Datepicker.getOrCreateInstance(this).show(); |
| }); |
| EventHandler.on(document, `DOMContentLoaded${EVENT_KEY$12}${DATA_API_KEY$7}`, () => { |
| const selector = `${SELECTOR_DATA_TOGGLE$6}[data-bs-inline="true"], ${SELECTOR_DATA_TOGGLE$6}[data-bs-selected-dates]`; |
| for (const element of document.querySelectorAll(selector)) Datepicker.getOrCreateInstance(element); |
| }); |
| //#endregion |
| //#region js/src/dialog-base.ts |
| /** |
| * -------------------------------------------------------------------------- |
| * Bootstrap dialog-base.ts |
| * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) |
| * -------------------------------------------------------------------------- |
| */ |
| /** |
| * Constants |
| */ |
| const CLASS_NAME_OPEN = "dialog-open"; |
| /** |
| * Class definition |
| * |
| * Shared base class for Dialog and Drawer components that use |
| * the native <dialog> element. Provides common behavior for: |
| * - Show/hide/toggle lifecycle with events |
| * - Opening/closing via showModal()/show()/close() |
| * - Escape key handling (modal and non-modal) |
| * - Backdrop click handling |
| * - Static backdrop transition ("bounce") |
| * - Body scroll prevention |
| * - Transition coordination |
| * - Child component cleanup (tooltips, popovers, toasts) |
| */ |
| var DialogBase = class extends BaseComponent { |
| constructor(element, config) { |
| super(element, config); |
| this._isTransitioning = false; |
| this._openedAsModal = false; |
| this._addDialogListeners(); |
| } |
| static get NAME() { |
| return "dialogbase"; |
| } |
| toggle(relatedTarget) { |
| return this._element.open ? this.hide() : this.show(relatedTarget); |
| } |
| async show(relatedTarget) { |
| if (this._element.open || this._isTransitioning) return; |
| if (EventHandler.trigger(this._element, this.constructor.eventName("show"), { relatedTarget }).defaultPrevented) return; |
| this._isTransitioning = true; |
| this._onBeforeShow(); |
| const { modal, preventBodyScroll } = this._getShowOptions(); |
| this._showElement({ |
| modal, |
| preventBodyScroll |
| }); |
| await this._queueCallback(() => { |
| this._isTransitioning = false; |
| EventHandler.trigger(this._element, this.constructor.eventName("shown"), { relatedTarget }); |
| }, this._element, this._isAnimated()); |
| } |
| async hide() { |
| if (!this._element.open || this._isTransitioning) return; |
| if (EventHandler.trigger(this._element, this.constructor.eventName("hide")).defaultPrevented) return; |
| this._isTransitioning = true; |
| this._hideElement(); |
| await this._queueCallback(() => { |
| if (this._element.open) this._closeAndCleanup(); |
| this._element.classList.remove("hiding"); |
| this._onAfterHide(); |
| this._isTransitioning = false; |
| EventHandler.trigger(this._element, this.constructor.eventName("hidden")); |
| }, this._element, this._isAnimated()); |
| } |
| dispose() { |
| if (this._element.open) this._closeAndCleanup(); |
| EventHandler.off(this._element, "cancel", this._cancelHandler); |
| super.dispose(); |
| } |
| _getShowOptions() { |
| return { |
| modal: true, |
| preventBodyScroll: true |
| }; |
| } |
| _onBeforeShow() {} |
| _onAfterHide() {} |
| _isAnimated() { |
| return !this._element.classList.contains(this._getInstantClassName()); |
| } |
| _getInstantClassName() { |
| return "dialog-instant"; |
| } |
| _getStaticClassName() { |
| return "dialog-static"; |
| } |
| _onCancel() {} |
| _showElement({ modal = true, preventBodyScroll = true } = {}) { |
| this._openedAsModal = modal; |
| if (modal) this._element.showModal(); |
| else this._element.show(); |
| if (preventBodyScroll) document.documentElement.classList.add(CLASS_NAME_OPEN); |
| } |
| _hideElement() { |
| this._hideChildComponents(); |
| this._element.classList.add("hiding"); |
| if (!this._shouldDeferClose()) this._closeAndCleanup(); |
| } |
| _closeAndCleanup() { |
| this._element.close(); |
| this._openedAsModal = false; |
| if (!document.querySelector("dialog[open]:modal")) document.documentElement.classList.remove(CLASS_NAME_OPEN); |
| } |
| _shouldDeferClose() { |
| return false; |
| } |
| _triggerBackdropTransition() { |
| if (EventHandler.trigger(this._element, this.constructor.eventName("hidePrevented")).defaultPrevented) return; |
| const staticClass = this._getStaticClassName(); |
| this._element.classList.add(staticClass); |
| this._queueCallback(() => { |
| this._element.classList.remove(staticClass); |
| }, this._element); |
| } |
| _hideChildComponents() { |
| for (const el of SelectorEngine.find("[data-bs-toggle=\"tooltip\"], [data-bs-toggle=\"popover\"]", this._element)) { |
| const instance = data_default.getAny(el); |
| if (instance && typeof instance.hide === "function") instance.hide(); |
| } |
| for (const el of SelectorEngine.find(".toast.show", this._element)) { |
| const instance = data_default.getAny(el); |
| if (instance && typeof instance.hide === "function") instance.hide(); |
| } |
| } |
| _addDialogListeners() { |
| const eventKey = this.constructor.EVENT_KEY; |
| this._cancelHandler = (event) => { |
| event.preventDefault(); |
| if (!this._config.keyboard) { |
| this._triggerBackdropTransition(); |
| return; |
| } |
| this._onCancel(); |
| this.hide(); |
| }; |
| EventHandler.on(this._element, "cancel", this._cancelHandler); |
| EventHandler.on(this._element, `keydown${eventKey}`, (event) => { |
| if (event.key !== "Escape" || this._openedAsModal) return; |
| event.preventDefault(); |
| if (!this._config.keyboard) return; |
| this._onCancel(); |
| this.hide(); |
| }); |
| EventHandler.on(this._element, `click${eventKey}`, (event) => { |
| if (event.target !== this._element || !this._openedAsModal) return; |
| if (this._config.backdrop === "static") { |
| this._triggerBackdropTransition(); |
| return; |
| } |
| this.hide(); |
| }); |
| } |
| }; |
| //#endregion |
| //#region js/src/dialog.ts |
| /** |
| * -------------------------------------------------------------------------- |
| * Bootstrap dialog.ts |
| * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) |
| * -------------------------------------------------------------------------- |
| */ |
| /** |
| * Constants |
| */ |
| const NAME$14 = "dialog"; |
| const EVENT_KEY$11 = `.bs.dialog`; |
| const DATA_API_KEY$6 = ".data-api"; |
| const EVENT_SHOW$3 = `show${EVENT_KEY$11}`; |
| const EVENT_HIDDEN$4 = `hidden${EVENT_KEY$11}`; |
| const EVENT_CANCEL = `cancel${EVENT_KEY$11}`; |
| const EVENT_CLICK_DATA_API$2 = `click${EVENT_KEY$11}${DATA_API_KEY$6}`; |
| const CLASS_NAME_NONMODAL = "dialog-nonmodal"; |
| const CLASS_NAME_INSTANT$1 = "dialog-instant"; |
| const CLASS_NAME_SWAP_IN = "dialog-swap-in"; |
| const SELECTOR_DATA_TOGGLE$5 = "[data-bs-toggle=\"dialog\"]"; |
| const Default$13 = { |
| backdrop: true, |
| keyboard: true, |
| modal: true |
| }; |
| const DefaultType$13 = { |
| backdrop: "(boolean|string)", |
| keyboard: "boolean", |
| modal: "boolean" |
| }; |
| /** |
| * Class definition |
| */ |
| var Dialog = class extends DialogBase { |
| constructor(element, config) { |
| super(element, config); |
| } |
| static get Default() { |
| return Default$13; |
| } |
| static get DefaultType() { |
| return DefaultType$13; |
| } |
| static get NAME() { |
| return NAME$14; |
| } |
| handleUpdate() {} |
| _getShowOptions() { |
| return { |
| modal: this._config.modal, |
| preventBodyScroll: this._config.modal |
| }; |
| } |
| _onBeforeShow() { |
| if (!this._config.modal) this._element.classList.add(CLASS_NAME_NONMODAL); |
| } |
| _onAfterHide() { |
| this._element.classList.remove(CLASS_NAME_NONMODAL); |
| } |
| _shouldDeferClose() { |
| return this._isAnimated(); |
| } |
| _onCancel() { |
| EventHandler.trigger(this._element, EVENT_CANCEL); |
| } |
| }; |
| /** |
| * Data API implementation |
| */ |
| EventHandler.on(document, EVENT_CLICK_DATA_API$2, SELECTOR_DATA_TOGGLE$5, function(event) { |
| const target = SelectorEngine.getElementFromSelector(this); |
| if (["A", "AREA"].includes(this.tagName)) event.preventDefault(); |
| EventHandler.one(target, EVENT_SHOW$3, (showEvent) => { |
| if (showEvent.defaultPrevented) return; |
| EventHandler.one(target, EVENT_HIDDEN$4, () => { |
| if (isVisible(this)) this.focus({ preventScroll: true }); |
| }); |
| }); |
| const config = Manipulator.getDataAttributes(this); |
| const currentDialog = this.closest("dialog[open]"); |
| if (currentDialog && currentDialog !== target) { |
| const newDialog = Dialog.getOrCreateInstance(target, config); |
| target.classList.add(CLASS_NAME_SWAP_IN); |
| newDialog.show(this); |
| EventHandler.one(target, `shown${EVENT_KEY$11}`, () => { |
| target.classList.remove(CLASS_NAME_SWAP_IN); |
| }); |
| const currentInstance = Dialog.getInstance(currentDialog); |
| if (currentInstance) { |
| currentDialog.classList.add(CLASS_NAME_INSTANT$1); |
| EventHandler.one(currentDialog, EVENT_HIDDEN$4, () => { |
| currentDialog.classList.remove(CLASS_NAME_INSTANT$1); |
| }); |
| currentInstance.hide(); |
| } |
| return; |
| } |
| Dialog.getOrCreateInstance(target, config).toggle(this); |
| }); |
| enableDismissTrigger(Dialog); |
| //#endregion |
| //#region js/src/util/sanitizer.ts |
| const ARIA_ATTRIBUTE_PATTERN = /^aria-[\w-]*$/i; |
| const DefaultAllowlist = { |
| "*": [ |
| "class", |
| "dir", |
| "id", |
| "lang", |
| "role", |
| ARIA_ATTRIBUTE_PATTERN |
| ], |
| a: [ |
| "target", |
| "href", |
| "title", |
| "rel" |
| ], |
| area: [], |
| b: [], |
| br: [], |
| col: [], |
| code: [], |
| dd: [], |
| div: [], |
| dl: [], |
| dt: [], |
| em: [], |
| hr: [], |
| h1: [], |
| h2: [], |
| h3: [], |
| h4: [], |
| h5: [], |
| h6: [], |
| i: [], |
| img: [ |
| "src", |
| "srcset", |
| "alt", |
| "title", |
| "width", |
| "height" |
| ], |
| li: [], |
| ol: [], |
| p: [], |
| pre: [], |
| s: [], |
| small: [], |
| span: [], |
| sub: [], |
| sup: [], |
| strong: [], |
| u: [], |
| ul: [] |
| }; |
| /** |
| * Allowlist for icon HTML options (Chips `dismissIcon`, NavOverflow `moreIcon`, |
| * and markup supplied via `[data-bs-overflow-icon]`). Covers the default SVG |
| * icons plus common inline-icon markup. Event-handler attributes and tags not |
| * listed here are stripped by `sanitizeHtml`. |
| */ |
| const DefaultIconAllowlist = { |
| "*": [ |
| "class", |
| "role", |
| ARIA_ATTRIBUTE_PATTERN |
| ], |
| svg: [ |
| "xmlns", |
| "width", |
| "height", |
| "viewbox", |
| "fill", |
| "stroke", |
| "stroke-width", |
| "stroke-linecap", |
| "stroke-linejoin", |
| "focusable" |
| ], |
| path: [ |
| "d", |
| "fill", |
| "stroke", |
| "stroke-width", |
| "fill-rule", |
| "clip-rule" |
| ], |
| line: [ |
| "x1", |
| "y1", |
| "x2", |
| "y2", |
| "stroke", |
| "stroke-width", |
| "stroke-linecap" |
| ], |
| circle: [ |
| "cx", |
| "cy", |
| "r", |
| "fill", |
| "stroke", |
| "stroke-width" |
| ], |
| rect: [ |
| "x", |
| "y", |
| "width", |
| "height", |
| "rx", |
| "ry", |
| "fill", |
| "stroke", |
| "stroke-width" |
| ], |
| polyline: [ |
| "points", |
| "fill", |
| "stroke", |
| "stroke-width" |
| ], |
| polygon: [ |
| "points", |
| "fill", |
| "stroke", |
| "stroke-width" |
| ], |
| g: [ |
| "fill", |
| "stroke", |
| "stroke-width", |
| "transform" |
| ], |
| span: [], |
| i: [] |
| }; |
| const uriAttributes = /* @__PURE__ */ new Set([ |
| "background", |
| "cite", |
| "href", |
| "itemtype", |
| "longdesc", |
| "poster", |
| "src", |
| "xlink:href" |
| ]); |
| /** |
| * A pattern that recognizes URLs that are safe wrt. XSS in URL navigation |
| * contexts. |
| * |
| * Shout-out to Angular https://github.com/angular/angular/blob/15.2.8/packages/core/src/sanitization/url_sanitizer.ts#L38 |
| */ |
| const SAFE_URL_PATTERN = /^(?!(?:javascript|data|vbscript):)(?:[a-z0-9+.-]+:|[^&:/?#]*(?:[/?#]|$))/i; |
| /** |
| * A pattern that matches safe data URLs. Only matches image, video and audio |
| * types — notably NOT `data:text/html`, which is an XSS vector. |
| * |
| * Shout-out to Angular https://github.com/angular/angular/blob/15.2.8/packages/core/src/sanitization/url_sanitizer.ts#L49 |
| */ |
| const DATA_URL_PATTERN = /^data:(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\/(?:mpeg|mp4|ogg|webm)|audio\/(?:mp3|oga|ogg|opus));base64,[\d+/a-z=]+$/i; |
| const allowedAttribute = (attribute, allowedAttributeList) => { |
| const attributeName = attribute.nodeName.toLowerCase(); |
| if (allowedAttributeList.includes(attributeName)) { |
| if (uriAttributes.has(attributeName)) return Boolean(SAFE_URL_PATTERN.test(attribute.nodeValue) || DATA_URL_PATTERN.test(attribute.nodeValue)); |
| return true; |
| } |
| return allowedAttributeList.filter((attributeRegex) => attributeRegex instanceof RegExp).some((regex) => regex.test(attributeName)); |
| }; |
| function sanitizeHtml(unsafeHtml, allowList, sanitizeFunction) { |
| if (!unsafeHtml.length) return unsafeHtml; |
| if (sanitizeFunction && typeof sanitizeFunction === "function") return sanitizeFunction(unsafeHtml); |
| const createdDocument = new window.DOMParser().parseFromString(unsafeHtml, "text/html"); |
| const elements = [...createdDocument.body.querySelectorAll("*")]; |
| for (const element of elements) { |
| const elementName = element.nodeName.toLowerCase(); |
| if (!Object.keys(allowList).includes(elementName)) { |
| element.remove(); |
| continue; |
| } |
| const attributeList = [...element.attributes]; |
| const allowedAttributes = [...allowList["*"] || [], ...allowList[elementName] || []]; |
| for (const attribute of attributeList) if (!allowedAttribute(attribute, allowedAttributes)) element.removeAttribute(attribute.nodeName); |
| } |
| return createdDocument.body.innerHTML; |
| } |
| //#endregion |
| //#region js/src/nav-overflow.ts |
| /** |
| * -------------------------------------------------------------------------- |
| * Bootstrap nav-overflow.ts |
| * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) |
| * -------------------------------------------------------------------------- |
| */ |
| /** |
| * Constants |
| */ |
| const NAME$13 = "navoverflow"; |
| const EVENT_KEY$10 = `.bs.navoverflow`; |
| const EVENT_UPDATE = `update${EVENT_KEY$10}`; |
| const EVENT_OVERFLOW = `overflow${EVENT_KEY$10}`; |
| const EVENT_RESIZE$2 = `resize${EVENT_KEY$10}`; |
| const CLASS_NAME_OVERFLOW = "nav-overflow"; |
| const CLASS_NAME_OVERFLOW_MENU = "nav-overflow-menu"; |
| const CLASS_NAME_HIDDEN = "d-none"; |
| const CLASS_NAME_KEEP = "nav-overflow-keep"; |
| const SELECTOR_NAV = ".nav"; |
| const SELECTOR_NAV_ITEM = ".nav-item"; |
| const SELECTOR_NAV_LINK = ".nav-link"; |
| const SELECTOR_OVERFLOW_TOGGLE = ".nav-overflow-toggle"; |
| const SELECTOR_OVERFLOW_MENU = ".nav-overflow-menu"; |
| const SELECTOR_CUSTOM_ICON = "[data-bs-overflow-icon]"; |
| const DEFAULT_TEXT = "More"; |
| const Default$12 = { |
| collapseBelow: 0, |
| iconPlacement: "start", |
| menuPlacement: "bottom-end", |
| moreText: DEFAULT_TEXT, |
| moreIcon: "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" fill=\"currentColor\" viewBox=\"0 0 16 16\"><path d=\"M3 9.5a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3m5 0a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3m5 0a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3\"/></svg>", |
| threshold: 0 |
| }; |
| const DefaultType$12 = { |
| collapseBelow: "(number|string)", |
| iconPlacement: "string", |
| menuPlacement: "string", |
| moreText: "(string|boolean)", |
| moreIcon: "string", |
| threshold: "number" |
| }; |
| /** |
| * Class definition |
| */ |
| var NavOverflow = class extends BaseComponent { |
| constructor(element, config) { |
| super(element, config); |
| const nav = SelectorEngine.findOne(SELECTOR_NAV, this._element); |
| if (!nav) throw new TypeError(`${this._element.outerHTML} has no child ${SELECTOR_NAV} to collapse`); |
| this._nav = nav; |
| this._items = []; |
| this._overflowItems = []; |
| this._overflowMenu = null; |
| this._overflowToggle = null; |
| this._resizeObserver = null; |
| this._resizeHandler = null; |
| this._collapseBelow = 0; |
| this._init(); |
| } |
| static get Default() { |
| return Default$12; |
| } |
| static get DefaultType() { |
| return DefaultType$12; |
| } |
| static get NAME() { |
| return NAME$13; |
| } |
| update() { |
| this._calculateOverflow(); |
| EventHandler.trigger(this._element, EVENT_UPDATE); |
| } |
| dispose() { |
| if (this._resizeObserver) this._resizeObserver.disconnect(); |
| if (this._resizeHandler) EventHandler.off(window, EVENT_RESIZE$2, this._resizeHandler); |
| this._restoreItems(); |
| if (this._overflowToggle && this._overflowToggle.parentElement) this._overflowToggle.parentElement.remove(); |
| super.dispose(); |
| } |
| _init() { |
| this._element.classList.add(CLASS_NAME_OVERFLOW); |
| this._items = SelectorEngine.find(SELECTOR_NAV_ITEM, this._nav).filter((item) => !item.querySelector(SELECTOR_OVERFLOW_TOGGLE)); |
| for (const [index, item] of this._items.entries()) item.dataset.bsNavOrder = index; |
| this._collapseBelow = this._resolveCollapseBelow(); |
| this._createOverflowMenu(); |
| this._setupResizeObserver(); |
| this._calculateOverflow(); |
| } |
| _createOverflowMenu() { |
| this._overflowToggle = SelectorEngine.findOne(SELECTOR_OVERFLOW_TOGGLE, this._element); |
| if (this._overflowToggle) { |
| this._overflowMenu = SelectorEngine.findOne(SELECTOR_OVERFLOW_MENU, this._element); |
| return; |
| } |
| const { moreText } = this._config; |
| const label = typeof moreText === "string" ? moreText : ""; |
| const overflowItem = document.createElement("li"); |
| overflowItem.className = "nav-item nav-overflow-item"; |
| const button = document.createElement("button"); |
| button.type = "button"; |
| button.className = "nav-link nav-overflow-toggle"; |
| button.setAttribute("data-bs-toggle", "menu"); |
| button.setAttribute("data-bs-placement", this._config.menuPlacement); |
| button.setAttribute("aria-expanded", "false"); |
| if (label === "") button.setAttribute("aria-label", DEFAULT_TEXT); |
| const iconSpan = document.createElement("span"); |
| iconSpan.className = "nav-overflow-icon"; |
| iconSpan.innerHTML = sanitizeHtml(this._resolveIcon(), DefaultIconAllowlist); |
| if (label === "") button.append(iconSpan); |
| else { |
| const textSpan = document.createElement("span"); |
| textSpan.className = "nav-overflow-text"; |
| textSpan.textContent = label; |
| if (this._config.iconPlacement === "end") button.append(textSpan, iconSpan); |
| else button.append(iconSpan, textSpan); |
| } |
| const menu = document.createElement("div"); |
| menu.className = `${CLASS_NAME_OVERFLOW_MENU} menu`; |
| overflowItem.append(button, menu); |
| this._nav.append(overflowItem); |
| this._overflowToggle = button; |
| this._overflowMenu = menu; |
| } |
| _resolveIcon() { |
| const customIconElement = SelectorEngine.findOne(SELECTOR_CUSTOM_ICON, this._element); |
| if (!customIconElement) return this._config.moreIcon; |
| const iconClone = customIconElement.cloneNode(true); |
| iconClone.removeAttribute("data-bs-overflow-icon"); |
| const iconHtml = iconClone.outerHTML; |
| customIconElement.remove(); |
| return iconHtml; |
| } |
| _resolveCollapseBelow() { |
| const value = this._config.collapseBelow; |
| if (typeof value === "number") return value; |
| if (typeof value === "string" && value !== "") { |
| const cssValue = getComputedStyle(document.documentElement).getPropertyValue(`--bs-breakpoint-${value}`); |
| return Number.parseFloat(cssValue) || 0; |
| } |
| return 0; |
| } |
| _setupResizeObserver() { |
| if (typeof ResizeObserver === "undefined") { |
| this._resizeHandler = () => this._calculateOverflow(); |
| EventHandler.on(window, EVENT_RESIZE$2, this._resizeHandler); |
| return; |
| } |
| this._resizeObserver = new ResizeObserver(() => { |
| this._calculateOverflow(); |
| }); |
| this._resizeObserver.observe(this._element); |
| } |
| _availableWidth() { |
| const { paddingInlineStart, paddingInlineEnd } = getComputedStyle(this._element); |
| const padding = (Number.parseFloat(paddingInlineStart) || 0) + (Number.parseFloat(paddingInlineEnd) || 0); |
| return this._element.clientWidth - padding; |
| } |
| _navGap() { |
| return Number.parseFloat(getComputedStyle(this._nav).columnGap) || 0; |
| } |
| _calculateOverflow() { |
| this._restoreItems(); |
| const availableWidth = this._availableWidth(); |
| const overflowItem = this._overflowToggle?.closest(SELECTOR_NAV_ITEM) ?? null; |
| const candidates = this._items.filter((item) => !item.classList.contains(CLASS_NAME_KEEP)); |
| if (this._collapseBelow > 0 && availableWidth < this._collapseBelow) { |
| this._applyOverflow(candidates, overflowItem); |
| return; |
| } |
| const gap = this._navGap(); |
| const keepWidth = this._items.filter((item) => item.classList.contains(CLASS_NAME_KEEP)).reduce((sum, item) => sum + item.offsetWidth + gap, 0); |
| const overflowWidth = overflowItem ? overflowItem.offsetWidth + gap : 0; |
| const limit = availableWidth - keepWidth - overflowWidth; |
| let usedWidth = 0; |
| let itemsToOverflow = []; |
| for (const item of candidates) { |
| usedWidth += item.offsetWidth + gap; |
| if (usedWidth > limit + 1) itemsToOverflow.push(item); |
| } |
| if (this._items.length - itemsToOverflow.length < this._config.threshold && this._items.length > this._config.threshold) itemsToOverflow = this._items.slice(this._config.threshold).filter((item) => !item.classList.contains(CLASS_NAME_KEEP)); |
| this._applyOverflow(itemsToOverflow, overflowItem); |
| } |
| _applyOverflow(items, overflowItem) { |
| this._moveToOverflow(items); |
| overflowItem?.classList.toggle(CLASS_NAME_HIDDEN, items.length === 0); |
| if (items.length > 0) EventHandler.trigger(this._element, EVENT_OVERFLOW, { |
| overflowCount: items.length, |
| visibleCount: this._items.length - items.length |
| }); |
| } |
| _moveToOverflow(items) { |
| if (!this._overflowMenu) return; |
| this._overflowMenu.innerHTML = ""; |
| this._overflowItems = []; |
| for (const item of items) { |
| const link = SelectorEngine.findOne(SELECTOR_NAV_LINK, item); |
| if (!link) continue; |
| const clonedLink = link.cloneNode(true); |
| clonedLink.className = "menu-item"; |
| if (link.classList.contains("active")) clonedLink.classList.add("active"); |
| if (link.classList.contains("disabled") || link.hasAttribute("disabled")) clonedLink.classList.add("disabled"); |
| this._overflowMenu.append(clonedLink); |
| item.classList.add(CLASS_NAME_HIDDEN); |
| item.dataset.bsNavOverflow = "true"; |
| this._overflowItems.push(item); |
| } |
| } |
| _restoreItems() { |
| for (const item of this._items) { |
| item.classList.remove(CLASS_NAME_HIDDEN); |
| delete item.dataset.bsNavOverflow; |
| } |
| this._overflowToggle?.closest(SELECTOR_NAV_ITEM)?.classList.remove(CLASS_NAME_HIDDEN); |
| if (this._overflowMenu) this._overflowMenu.innerHTML = ""; |
| this._overflowItems = []; |
| } |
| }; |
| /** |
| * Data API implementation |
| */ |
| EventHandler.on(document, "DOMContentLoaded", () => { |
| for (const element of SelectorEngine.find("[data-bs-toggle=\"nav-overflow\"]")) NavOverflow.getOrCreateInstance(element); |
| }); |
| //#endregion |
| //#region js/src/util/swipe.ts |
| /** |
| * -------------------------------------------------------------------------- |
| * Bootstrap util/swipe.ts |
| * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) |
| * -------------------------------------------------------------------------- |
| */ |
| /** |
| * Constants |
| */ |
| const NAME$12 = "swipe"; |
| const EVENT_KEY$9 = ".bs.swipe"; |
| const EVENT_TOUCHSTART = `touchstart${EVENT_KEY$9}`; |
| const EVENT_TOUCHMOVE = `touchmove${EVENT_KEY$9}`; |
| const EVENT_TOUCHEND = `touchend${EVENT_KEY$9}`; |
| const EVENT_POINTERDOWN = `pointerdown${EVENT_KEY$9}`; |
| const EVENT_POINTERUP = `pointerup${EVENT_KEY$9}`; |
| const POINTER_TYPE_TOUCH = "touch"; |
| const POINTER_TYPE_PEN = "pen"; |
| const CLASS_NAME_POINTER_EVENT = "pointer-event"; |
| const SWIPE_THRESHOLD = 40; |
| const Default$11 = { |
| endCallback: null, |
| leftCallback: null, |
| rightCallback: null, |
| upCallback: null, |
| downCallback: null |
| }; |
| const DefaultType$11 = { |
| endCallback: "(function|null)", |
| leftCallback: "(function|null)", |
| rightCallback: "(function|null)", |
| upCallback: "(function|null)", |
| downCallback: "(function|null)" |
| }; |
| /** |
| * Class definition |
| */ |
| var Swipe = class Swipe extends Config { |
| constructor(element, config) { |
| super(); |
| this._element = element; |
| if (!element || !Swipe.isSupported()) return; |
| this._config = this._getConfig(config); |
| this._deltaX = 0; |
| this._deltaY = 0; |
| this._supportPointerEvents = Boolean(window.PointerEvent); |
| this._initEvents(); |
| } |
| static get Default() { |
| return Default$11; |
| } |
| static get DefaultType() { |
| return DefaultType$11; |
| } |
| static get NAME() { |
| return NAME$12; |
| } |
| dispose() { |
| EventHandler.off(this._element, EVENT_KEY$9); |
| } |
| _start(event) { |
| if (!this._supportPointerEvents) { |
| this._deltaX = event.touches[0].clientX; |
| this._deltaY = event.touches[0].clientY; |
| return; |
| } |
| if (this._eventIsPointerPenTouch(event)) { |
| this._deltaX = event.clientX; |
| this._deltaY = event.clientY; |
| } |
| } |
| _end(event) { |
| if (this._eventIsPointerPenTouch(event)) { |
| this._deltaX = event.clientX - this._deltaX; |
| this._deltaY = event.clientY - this._deltaY; |
| } |
| this._handleSwipe(); |
| execute(this._config.endCallback); |
| } |
| _move(event) { |
| if (event.touches && event.touches.length > 1) { |
| this._deltaX = 0; |
| this._deltaY = 0; |
| return; |
| } |
| this._deltaX = event.touches[0].clientX - this._deltaX; |
| this._deltaY = event.touches[0].clientY - this._deltaY; |
| } |
| _handleSwipe() { |
| const absDeltaX = Math.abs(this._deltaX); |
| const absDeltaY = Math.abs(this._deltaY); |
| if (absDeltaY > absDeltaX && absDeltaY > SWIPE_THRESHOLD) { |
| const direction = this._deltaY > 0 ? "down" : "up"; |
| this._deltaX = 0; |
| this._deltaY = 0; |
| execute(direction === "down" ? this._config.downCallback : this._config.upCallback); |
| return; |
| } |
| if (absDeltaX > SWIPE_THRESHOLD) { |
| const direction = absDeltaX / this._deltaX; |
| this._deltaX = 0; |
| this._deltaY = 0; |
| if (!direction) return; |
| execute(direction > 0 ? this._config.rightCallback : this._config.leftCallback); |
| return; |
| } |
| this._deltaX = 0; |
| this._deltaY = 0; |
| } |
| _initEvents() { |
| if (this._supportPointerEvents) { |
| EventHandler.on(this._element, EVENT_POINTERDOWN, (event) => this._start(event)); |
| EventHandler.on(this._element, EVENT_POINTERUP, (event) => this._end(event)); |
| this._element.classList.add(CLASS_NAME_POINTER_EVENT); |
| } else { |
| EventHandler.on(this._element, EVENT_TOUCHSTART, (event) => this._start(event)); |
| EventHandler.on(this._element, EVENT_TOUCHMOVE, (event) => this._move(event)); |
| EventHandler.on(this._element, EVENT_TOUCHEND, (event) => this._end(event)); |
| } |
| } |
| _eventIsPointerPenTouch(event) { |
| return this._supportPointerEvents && (event.pointerType === POINTER_TYPE_PEN || event.pointerType === POINTER_TYPE_TOUCH); |
| } |
| static isSupported() { |
| return "ontouchstart" in document.documentElement || navigator.maxTouchPoints > 0; |
| } |
| }; |
| //#endregion |
| //#region js/src/drawer.ts |
| /** |
| * -------------------------------------------------------------------------- |
| * Bootstrap drawer.ts |
| * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) |
| * -------------------------------------------------------------------------- |
| */ |
| /** |
| * Constants |
| */ |
| const NAME$11 = "drawer"; |
| const EVENT_KEY$8 = `.bs.drawer`; |
| const DATA_API_KEY$5 = ".data-api"; |
| const EVENT_LOAD_DATA_API$2 = `load${EVENT_KEY$8}${DATA_API_KEY$5}`; |
| const EVENT_HIDDEN$3 = `hidden${EVENT_KEY$8}`; |
| const EVENT_RESIZE$1 = `resize${EVENT_KEY$8}`; |
| const EVENT_CLICK_DATA_API$1 = `click${EVENT_KEY$8}${DATA_API_KEY$5}`; |
| const SELECTOR_DATA_TOGGLE$4 = "[data-bs-toggle=\"drawer\"]"; |
| const Default$10 = { |
| backdrop: true, |
| keyboard: true, |
| scroll: false |
| }; |
| const DefaultType$10 = { |
| backdrop: "(boolean|string)", |
| keyboard: "boolean", |
| scroll: "boolean" |
| }; |
| /** |
| * Class definition |
| */ |
| var Drawer = class extends DialogBase { |
| constructor(element, config) { |
| super(element, config); |
| this._swipeHelper = null; |
| } |
| static get Default() { |
| return Default$10; |
| } |
| static get DefaultType() { |
| return DefaultType$10; |
| } |
| static get NAME() { |
| return NAME$11; |
| } |
| dispose() { |
| if (this._swipeHelper) this._swipeHelper.dispose(); |
| super.dispose(); |
| } |
| _getShowOptions() { |
| return { |
| modal: Boolean(this._config.backdrop) || !this._config.scroll, |
| preventBodyScroll: !this._config.scroll |
| }; |
| } |
| _onBeforeShow() { |
| this._initSwipe(); |
| } |
| _getInstantClassName() { |
| return "drawer-instant"; |
| } |
| _getStaticClassName() { |
| return "drawer-static"; |
| } |
| _initSwipe() { |
| if (this._swipeHelper || !Swipe.isSupported()) return; |
| const swipeConfig = {}; |
| const element = this._element; |
| if (element.classList.contains("drawer-bottom")) swipeConfig.downCallback = () => this.hide(); |
| else if (element.classList.contains("drawer-top")) swipeConfig.upCallback = () => this.hide(); |
| else if (element.classList.contains("drawer-end")) if (isRTL()) swipeConfig.leftCallback = () => this.hide(); |
| else swipeConfig.rightCallback = () => this.hide(); |
| else if (isRTL()) swipeConfig.rightCallback = () => this.hide(); |
| else swipeConfig.leftCallback = () => this.hide(); |
| this._swipeHelper = new Swipe(element, swipeConfig); |
| } |
| }; |
| /** |
| * Data API implementation |
| */ |
| EventHandler.on(document, EVENT_CLICK_DATA_API$1, SELECTOR_DATA_TOGGLE$4, function(event) { |
| const target = SelectorEngine.getElementFromSelector(this); |
| if (["A", "AREA"].includes(this.tagName)) event.preventDefault(); |
| if (isDisabled(this)) return; |
| EventHandler.one(target, EVENT_HIDDEN$3, () => { |
| if (isVisible(this)) this.focus({ preventScroll: true }); |
| }); |
| const alreadyOpen = SelectorEngine.findOne("dialog.drawer[open]"); |
| if (alreadyOpen && alreadyOpen !== target) Drawer.getInstance(alreadyOpen).hide(); |
| Drawer.getOrCreateInstance(target).toggle(this); |
| }); |
| EventHandler.on(window, EVENT_LOAD_DATA_API$2, () => { |
| for (const selector of SelectorEngine.find("dialog.drawer[open]")) Drawer.getOrCreateInstance(selector).show(); |
| }); |
| EventHandler.on(window, EVENT_RESIZE$1, () => { |
| for (const element of SelectorEngine.find("dialog[open][class*=\"\\:drawer\"]")) if (getComputedStyle(element).position !== "fixed") Drawer.getOrCreateInstance(element).hide(); |
| }); |
| enableDismissTrigger(Drawer); |
| //#endregion |
| //#region js/src/strength.ts |
| /** |
| * -------------------------------------------------------------------------- |
| * Bootstrap strength.ts |
| * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) |
| * -------------------------------------------------------------------------- |
| */ |
| /** |
| * Constants |
| */ |
| const NAME$10 = "strength"; |
| const EVENT_KEY$7 = `.bs.strength`; |
| const DATA_API_KEY$4 = ".data-api"; |
| const EVENT_STRENGTH_CHANGE = `strengthChange${EVENT_KEY$7}`; |
| const SELECTOR_DATA_STRENGTH = "[data-bs-strength]"; |
| const STRENGTH_LEVELS = [ |
| "weak", |
| "fair", |
| "good", |
| "strong" |
| ]; |
| const Default$9 = { |
| input: null, |
| minLength: 8, |
| messages: { |
| weak: "Weak", |
| fair: "Fair", |
| good: "Good", |
| strong: "Strong" |
| }, |
| weights: { |
| minLength: 1, |
| extraLength: 1, |
| lowercase: 1, |
| uppercase: 1, |
| numbers: 1, |
| special: 1, |
| multipleSpecial: 1, |
| longPassword: 1 |
| }, |
| thresholds: [ |
| 2, |
| 4, |
| 6 |
| ], |
| scorer: null |
| }; |
| const DefaultType$9 = { |
| input: "(string|element|null)", |
| minLength: "number", |
| messages: "object", |
| weights: "object", |
| thresholds: "array", |
| scorer: "(function|null)" |
| }; |
| /** |
| * Class definition |
| */ |
| var Strength = class extends BaseComponent { |
| constructor(element, config) { |
| super(element, config); |
| this._input = this._getInput(); |
| this._segments = SelectorEngine.find(".strength-segment", this._element); |
| this._textElement = SelectorEngine.findOne(".strength-text", this._element.parentElement); |
| this._currentStrength = null; |
| if (this._input) { |
| this._addEventListeners(); |
| this._evaluate(); |
| } |
| } |
| static get Default() { |
| return Default$9; |
| } |
| static get DefaultType() { |
| return DefaultType$9; |
| } |
| static get NAME() { |
| return NAME$10; |
| } |
| getStrength() { |
| return this._currentStrength; |
| } |
| evaluate() { |
| this._evaluate(); |
| } |
| _getInput() { |
| if (this._config.input) return typeof this._config.input === "string" ? SelectorEngine.findOne(this._config.input) : this._config.input; |
| const parent = this._element.parentElement; |
| return SelectorEngine.findOne("input[type=\"password\"]", parent); |
| } |
| _addEventListeners() { |
| EventHandler.on(this._input, "input", () => this._evaluate()); |
| EventHandler.on(this._input, "change", () => this._evaluate()); |
| } |
| _evaluate() { |
| const password = this._input.value; |
| const score = this._calculateScore(password); |
| const strength = this._scoreToStrength(score); |
| if (strength !== this._currentStrength) { |
| this._currentStrength = strength; |
| this._updateUI(strength); |
| EventHandler.trigger(this._element, EVENT_STRENGTH_CHANGE, { |
| strength, |
| score, |
| password: password.length > 0 ? "***" : "" |
| }); |
| } |
| } |
| _calculateScore(password) { |
| if (!password) return 0; |
| if (typeof this._config.scorer === "function") return this._config.scorer(password); |
| const { weights } = this._config; |
| let score = 0; |
| if (password.length >= this._config.minLength) score += weights.minLength; |
| if (password.length >= this._config.minLength + 4) score += weights.extraLength; |
| if (/[a-z]/.test(password)) score += weights.lowercase; |
| if (/[A-Z]/.test(password)) score += weights.uppercase; |
| if (/\d/.test(password)) score += weights.numbers; |
| if (/[!@#$%^&*(),.?":{}|<>]/.test(password)) score += weights.special; |
| if (/[!@#$%^&*(),.?":{}|<>].*[!@#$%^&*(),.?":{}|<>]/.test(password)) score += weights.multipleSpecial; |
| if (password.length >= 16) score += weights.longPassword; |
| return score; |
| } |
| _scoreToStrength(score) { |
| if (score === 0) return null; |
| const [weak, fair, good] = this._config.thresholds; |
| if (score <= weak) return "weak"; |
| if (score <= fair) return "fair"; |
| if (score <= good) return "good"; |
| return "strong"; |
| } |
| _updateUI(strength) { |
| if (strength) this._element.dataset.bsStrength = strength; |
| else delete this._element.dataset.bsStrength; |
| const strengthIndex = strength ? STRENGTH_LEVELS.indexOf(strength) : -1; |
| for (const [index, segment] of this._segments.entries()) if (index <= strengthIndex) segment.classList.add("active"); |
| else segment.classList.remove("active"); |
| if (this._textElement) if (strength && this._config.messages[strength]) { |
| this._textElement.textContent = this._config.messages[strength]; |
| this._textElement.dataset.bsStrength = strength; |
| this._textElement.style.setProperty("--strength-color", `var(--${{ |
| weak: "danger", |
| fair: "warning", |
| good: "info", |
| strong: "success" |
| }[strength]}-text)`); |
| } else { |
| this._textElement.textContent = ""; |
| delete this._textElement.dataset.bsStrength; |
| } |
| } |
| }; |
| /** |
| * Data API implementation |
| */ |
| EventHandler.on(document, `DOMContentLoaded${EVENT_KEY$7}${DATA_API_KEY$4}`, () => { |
| for (const element of SelectorEngine.find(SELECTOR_DATA_STRENGTH)) Strength.getOrCreateInstance(element); |
| }); |
| //#endregion |
| //#region js/src/otp-input.ts |
| /** |
| * -------------------------------------------------------------------------- |
| * Bootstrap otp-input.ts |
| * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) |
| * -------------------------------------------------------------------------- |
| */ |
| /** |
| * Constants |
| */ |
| const NAME$9 = "otpInput"; |
| const EVENT_KEY$6 = `.bs.otpInput`; |
| const DATA_API_KEY$3 = ".data-api"; |
| const EVENT_COMPLETE = `complete${EVENT_KEY$6}`; |
| const EVENT_INPUT$1 = `input${EVENT_KEY$6}`; |
| const EVENT_DOMCONTENT_LOADED = `DOMContentLoaded${EVENT_KEY$6}${DATA_API_KEY$3}`; |
| const SELECTOR_DATA_OTP = "[data-bs-otp]"; |
| const SELECTOR_INPUT$1 = "input"; |
| const SYNC_EVENTS = [ |
| "blur", |
| "keyup", |
| "select" |
| ]; |
| const CLASS_NAME_INPUT = "otp-input"; |
| const CLASS_NAME_RENDERED = "otp-rendered"; |
| const CLASS_NAME_SLOTS = "otp-slots"; |
| const CLASS_NAME_SLOT = "otp-slot"; |
| const CLASS_NAME_SLOT_FILLED = "otp-slot-filled"; |
| const CLASS_NAME_SLOT_ACTIVE = "otp-slot-active"; |
| const CLASS_NAME_SEPARATOR = "otp-separator"; |
| const MASK_CHARACTER = "•"; |
| const TYPES = { |
| numeric: { |
| inputmode: "numeric", |
| pattern: "[0-9]*", |
| filter: /[^0-9]/g |
| }, |
| alphanumeric: { |
| inputmode: "text", |
| pattern: "[A-Za-z0-9]*", |
| filter: /[^A-Za-z0-9]/g |
| }, |
| alpha: { |
| inputmode: "text", |
| pattern: "[A-Za-z]*", |
| filter: /[^A-Za-z]/g |
| } |
| }; |
| const Default$8 = { |
| groups: null, |
| length: null, |
| mask: false, |
| separator: "·", |
| type: "numeric" |
| }; |
| const DefaultType$8 = { |
| groups: "(array|null)", |
| length: "(number|null)", |
| mask: "boolean", |
| separator: "string", |
| type: "string" |
| }; |
| /** |
| * Class definition |
| */ |
| var OtpInput = class extends BaseComponent { |
| constructor(element, config) { |
| super(element, config); |
| const input = SelectorEngine.findOne(SELECTOR_INPUT$1, this._element); |
| if (!input) return; |
| this._input = input; |
| this._type = TYPES[this._config.type] || TYPES.numeric; |
| this._length = this._resolveLength(); |
| this._slots = []; |
| this._pointerActive = false; |
| this._pointerIndex = 0; |
| this._setupInput(); |
| this._renderSlots(); |
| this._addEventListeners(); |
| this._render(); |
| } |
| static get Default() { |
| return Default$8; |
| } |
| static get DefaultType() { |
| return DefaultType$8; |
| } |
| static get NAME() { |
| return NAME$9; |
| } |
| getValue() { |
| return this._input.value; |
| } |
| setValue(value) { |
| this._input.value = this._sanitize(String(value)); |
| this._render(); |
| this._checkComplete(); |
| } |
| clear() { |
| this._input.value = ""; |
| this._render(); |
| this._input.focus(); |
| } |
| focus() { |
| this._input.focus(); |
| this._selectSlot(this._firstEmptyIndex()); |
| this._render(); |
| } |
| dispose() { |
| EventHandler.off(this._input, "input", this._onInput); |
| EventHandler.off(this._input, "beforeinput", this._onBeforeInput); |
| EventHandler.off(this._input, "focus", this._onFocus); |
| EventHandler.off(this._input, "pointerdown", this._onPointerDown); |
| EventHandler.off(document, "selectionchange", this._onSelectionChange); |
| for (const type of SYNC_EVENTS) EventHandler.off(this._input, type, this._onSync); |
| this._slotsContainer?.remove(); |
| this._element.classList.remove(CLASS_NAME_RENDERED); |
| super.dispose(); |
| } |
| _resolveLength() { |
| if (this._config.length) return this._config.length; |
| const maxLength = Number.parseInt(this._input.getAttribute("maxlength"), 10); |
| return Number.isNaN(maxLength) || maxLength < 1 ? 6 : maxLength; |
| } |
| _setupInput() { |
| const input = this._input; |
| if (input.type === "number" || input.type === "password") input.type = "text"; |
| input.classList.add(CLASS_NAME_INPUT); |
| input.setAttribute("maxlength", String(this._length)); |
| input.setAttribute("inputmode", this._type.inputmode); |
| input.setAttribute("pattern", this._type.pattern); |
| if (!input.getAttribute("autocomplete")) input.setAttribute("autocomplete", "one-time-code"); |
| if (input.value) input.value = this._sanitize(input.value); |
| } |
| _renderSlots() { |
| const container = document.createElement("div"); |
| container.className = CLASS_NAME_SLOTS; |
| container.setAttribute("aria-hidden", "true"); |
| const { groups } = this._config; |
| let groupIndex = 0; |
| let inGroup = 0; |
| for (let i = 0; i < this._length; i++) { |
| const slot = document.createElement("div"); |
| slot.className = CLASS_NAME_SLOT; |
| container.append(slot); |
| this._slots.push(slot); |
| if (Array.isArray(groups) && groups.length > 0) { |
| inGroup++; |
| if (inGroup === groups[groupIndex] && i < this._length - 1) { |
| const separator = document.createElement("div"); |
| separator.className = CLASS_NAME_SEPARATOR; |
| separator.textContent = this._config.separator; |
| container.append(separator); |
| groupIndex = Math.min(groupIndex + 1, groups.length - 1); |
| inGroup = 0; |
| } |
| } |
| } |
| this._slotsContainer = container; |
| this._element.append(container); |
| this._element.classList.add(CLASS_NAME_RENDERED); |
| } |
| _addEventListeners() { |
| this._onInput = () => this._handleInput(); |
| this._onBeforeInput = (event) => this._handleBeforeInput(event); |
| this._onPointerDown = (event) => this._handlePointerDown(event); |
| this._onFocus = () => { |
| if (this._pointerActive) { |
| this._pointerActive = false; |
| this._selectSlot(this._pointerIndex); |
| this._render(); |
| return; |
| } |
| this._selectSlot(this._firstEmptyIndex()); |
| this._render(); |
| }; |
| this._onSync = () => this._render(); |
| this._onSelectionChange = () => { |
| if (document.activeElement === this._input) this._render(); |
| }; |
| EventHandler.on(this._input, "input", this._onInput); |
| EventHandler.on(this._input, "beforeinput", this._onBeforeInput); |
| EventHandler.on(this._input, "focus", this._onFocus); |
| EventHandler.on(this._input, "pointerdown", this._onPointerDown); |
| EventHandler.on(document, "selectionchange", this._onSelectionChange); |
| for (const type of SYNC_EVENTS) EventHandler.on(this._input, type, this._onSync); |
| } |
| _handleInput() { |
| const sanitized = this._sanitize(this._input.value); |
| if (sanitized !== this._input.value) this._input.value = sanitized; |
| if (document.activeElement === this._input) this._selectSlot(this._firstEmptyIndex()); |
| this._afterValueChange(); |
| } |
| _handleBeforeInput(event) { |
| const { inputType, data } = event; |
| if (inputType === "insertText" && data && data.length === 1) { |
| event.preventDefault(); |
| const char = this._sanitize(data); |
| if (!char) return; |
| const index = Math.min(this._input.selectionStart ?? 0, this._length - 1); |
| const chars = [...this._input.value]; |
| chars[index] = char; |
| this._input.value = chars.join("").slice(0, this._length); |
| this._selectSlot(index + 1); |
| this._afterValueChange(); |
| return; |
| } |
| if (inputType === "deleteContentBackward") { |
| event.preventDefault(); |
| const start = this._input.selectionStart ?? 0; |
| const end = this._input.selectionEnd ?? start; |
| const chars = [...this._input.value]; |
| if (end > start) { |
| chars.splice(start, end - start); |
| this._input.value = chars.join(""); |
| this._selectSlot(start); |
| } else if (start > 0) { |
| chars.splice(start - 1, 1); |
| this._input.value = chars.join(""); |
| this._selectSlot(start - 1); |
| } |
| this._afterValueChange(); |
| } |
| } |
| _handlePointerDown(event) { |
| const index = this._slotIndexFromPoint(event.clientX); |
| if (index === null) return; |
| const target = Math.min(index, this._firstEmptyIndex()); |
| if (document.activeElement === this._input) { |
| event.preventDefault(); |
| this._selectSlot(target); |
| this._render(); |
| return; |
| } |
| this._pointerActive = true; |
| this._pointerIndex = target; |
| } |
| _slotIndexFromPoint(x) { |
| for (const [index, slot] of this._slots.entries()) if (x <= slot.getBoundingClientRect().right || index === this._slots.length - 1) return index; |
| return null; |
| } |
| _afterValueChange() { |
| this._render(); |
| EventHandler.trigger(this._element, EVENT_INPUT$1, { value: this._input.value }); |
| this._checkComplete(); |
| } |
| _firstEmptyIndex() { |
| return Math.min(this._input.value.length, this._length - 1); |
| } |
| _selectSlot(index) { |
| const clamped = Math.max(0, Math.min(index, this._length - 1)); |
| const end = clamped < this._input.value.length ? clamped + 1 : clamped; |
| this._input.setSelectionRange(clamped, end); |
| } |
| _sanitize(value) { |
| return value.replace(this._type.filter, "").slice(0, this._length); |
| } |
| _render() { |
| const { value } = this._input; |
| const isFocused = document.activeElement === this._input; |
| const caret = Math.min(this._input.selectionStart ?? value.length, this._length - 1); |
| for (const [index, slot] of this._slots.entries()) { |
| const char = value[index] ?? ""; |
| slot.textContent = char && this._config.mask ? MASK_CHARACTER : char; |
| slot.classList.toggle(CLASS_NAME_SLOT_FILLED, Boolean(char)); |
| slot.classList.toggle(CLASS_NAME_SLOT_ACTIVE, isFocused && index === caret); |
| } |
| } |
| _checkComplete() { |
| const { value } = this._input; |
| if (value.length === this._length) EventHandler.trigger(this._element, EVENT_COMPLETE, { value }); |
| } |
| }; |
| /** |
| * Data API implementation |
| */ |
| EventHandler.on(document, EVENT_DOMCONTENT_LOADED, () => { |
| for (const element of SelectorEngine.find(SELECTOR_DATA_OTP)) OtpInput.getOrCreateInstance(element); |
| }); |
| //#endregion |
| //#region js/src/chips.ts |
| /** |
| * -------------------------------------------------------------------------- |
| * Bootstrap chips.ts |
| * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) |
| * -------------------------------------------------------------------------- |
| */ |
| /** |
| * Constants |
| */ |
| const NAME$8 = "chips"; |
| const EVENT_KEY$5 = `.bs.chips`; |
| const DATA_API_KEY$2 = ".data-api"; |
| const EVENT_ADD = `add${EVENT_KEY$5}`; |
| const EVENT_REMOVE = `remove${EVENT_KEY$5}`; |
| const EVENT_CHANGE$1 = `change${EVENT_KEY$5}`; |
| const EVENT_SELECT = `select${EVENT_KEY$5}`; |
| const SELECTOR_DATA_CHIPS = "[data-bs-chips]"; |
| const SELECTOR_GHOST_INPUT = ".form-ghost"; |
| const SELECTOR_CHIP = ".chip"; |
| const SELECTOR_CHIP_DISMISS = ".chip-dismiss"; |
| const CLASS_NAME_CHIP = "chip"; |
| const CLASS_NAME_CHIP_DISMISS = "chip-dismiss"; |
| const CLASS_NAME_ACTIVE$2 = "active"; |
| const Default$7 = { |
| separator: ",", |
| allowDuplicates: false, |
| maxChips: null, |
| placeholder: "", |
| dismissible: true, |
| dismissIcon: "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"><line x1=\"4\" y1=\"4\" x2=\"12\" y2=\"12\"/><line x1=\"12\" y1=\"4\" x2=\"4\" y2=\"12\"/></svg>", |
| createOnBlur: true |
| }; |
| const DefaultType$7 = { |
| separator: "(string|null)", |
| allowDuplicates: "boolean", |
| maxChips: "(number|null)", |
| placeholder: "string", |
| dismissible: "boolean", |
| dismissIcon: "string", |
| createOnBlur: "boolean" |
| }; |
| /** |
| * Class definition |
| */ |
| var Chips = class extends BaseComponent { |
| constructor(element, config) { |
| super(element, config); |
| const ghostInput = SelectorEngine.findOne(SELECTOR_GHOST_INPUT, this._element); |
| this._chips = []; |
| this._selectedChips = /* @__PURE__ */ new Set(); |
| this._anchorChip = null; |
| if (ghostInput) this._input = ghostInput; |
| else this._createInput(); |
| this._initializeExistingChips(); |
| this._addEventListeners(); |
| } |
| static get Default() { |
| return Default$7; |
| } |
| static get DefaultType() { |
| return DefaultType$7; |
| } |
| static get NAME() { |
| return NAME$8; |
| } |
| add(value) { |
| const trimmedValue = String(value).trim(); |
| if (!trimmedValue) return null; |
| if (!this._config.allowDuplicates && this._chips.includes(trimmedValue)) return null; |
| if (this._config.maxChips !== null && this._chips.length >= this._config.maxChips) return null; |
| if (EventHandler.trigger(this._element, EVENT_ADD, { |
| value: trimmedValue, |
| relatedTarget: this._input |
| }).defaultPrevented) return null; |
| const chip = this._createChip(trimmedValue); |
| this._element.insertBefore(chip, this._input); |
| this._chips.push(trimmedValue); |
| EventHandler.trigger(this._element, EVENT_CHANGE$1, { values: this.getValues() }); |
| return chip; |
| } |
| remove(chipOrValue) { |
| let chip; |
| let value; |
| if (typeof chipOrValue === "string") { |
| value = chipOrValue; |
| chip = this._findChipByValue(value); |
| } else { |
| chip = chipOrValue; |
| value = this._getChipValue(chip); |
| } |
| if (!chip || !value) return false; |
| if (EventHandler.trigger(this._element, EVENT_REMOVE, { |
| value, |
| chip, |
| relatedTarget: this._input |
| }).defaultPrevented) return false; |
| this._selectedChips.delete(chip); |
| if (this._anchorChip === chip) this._anchorChip = null; |
| chip.remove(); |
| this._chips = this._getChipElements().map((chipElement) => this._getChipValue(chipElement)).filter(Boolean); |
| EventHandler.trigger(this._element, EVENT_CHANGE$1, { values: this.getValues() }); |
| return true; |
| } |
| removeSelected() { |
| const chipsToRemove = [...this._selectedChips]; |
| for (const chip of chipsToRemove) this.remove(chip); |
| this._input?.focus(); |
| } |
| getValues() { |
| return [...this._chips]; |
| } |
| getSelectedValues() { |
| return [...this._selectedChips].map((chip) => this._getChipValue(chip)); |
| } |
| clear() { |
| const chips = SelectorEngine.find(SELECTOR_CHIP, this._element); |
| for (const chip of chips) chip.remove(); |
| this._chips = []; |
| this._selectedChips.clear(); |
| this._anchorChip = null; |
| EventHandler.trigger(this._element, EVENT_CHANGE$1, { values: [] }); |
| } |
| clearSelection() { |
| for (const chip of this._selectedChips) chip.classList.remove(CLASS_NAME_ACTIVE$2); |
| this._selectedChips.clear(); |
| this._anchorChip = null; |
| EventHandler.trigger(this._element, EVENT_SELECT, { selected: [] }); |
| } |
| selectChip(chip, options = {}) { |
| const { addToSelection = false, rangeSelect = false } = options; |
| const chipElements = this._getChipElements(); |
| if (!chipElements.includes(chip)) return; |
| if (rangeSelect && this._anchorChip) { |
| const anchorIndex = chipElements.indexOf(this._anchorChip); |
| const chipIndex = chipElements.indexOf(chip); |
| const start = Math.min(anchorIndex, chipIndex); |
| const end = Math.max(anchorIndex, chipIndex); |
| if (!addToSelection) this.clearSelection(); |
| for (let i = start; i <= end; i++) { |
| this._selectedChips.add(chipElements[i]); |
| chipElements[i].classList.add(CLASS_NAME_ACTIVE$2); |
| } |
| } else if (addToSelection) if (this._selectedChips.has(chip)) { |
| this._selectedChips.delete(chip); |
| chip.classList.remove(CLASS_NAME_ACTIVE$2); |
| } else { |
| this._selectedChips.add(chip); |
| chip.classList.add(CLASS_NAME_ACTIVE$2); |
| this._anchorChip = chip; |
| } |
| else { |
| this.clearSelection(); |
| this._selectedChips.add(chip); |
| chip.classList.add(CLASS_NAME_ACTIVE$2); |
| this._anchorChip = chip; |
| } |
| EventHandler.trigger(this._element, EVENT_SELECT, { selected: this.getSelectedValues() }); |
| } |
| focus() { |
| this._input?.focus(); |
| } |
| _getChipElements() { |
| return SelectorEngine.find(SELECTOR_CHIP, this._element); |
| } |
| _createInput() { |
| const input = document.createElement("input"); |
| input.type = "text"; |
| input.className = "form-ghost"; |
| if (this._config.placeholder) input.placeholder = this._config.placeholder; |
| this._element.append(input); |
| this._input = input; |
| } |
| _initializeExistingChips() { |
| const existingChips = SelectorEngine.find(SELECTOR_CHIP, this._element); |
| for (const chip of existingChips) { |
| const value = this._getChipValue(chip); |
| if (value) { |
| this._chips.push(value); |
| this._setupChip(chip); |
| } |
| } |
| } |
| _setupChip(chip) { |
| chip.setAttribute("tabindex", "0"); |
| if (this._config.dismissible && !SelectorEngine.findOne(SELECTOR_CHIP_DISMISS, chip)) chip.append(this._createDismissButton()); |
| } |
| _createChip(value) { |
| const chip = document.createElement("span"); |
| chip.className = CLASS_NAME_CHIP; |
| chip.dataset.bsChipValue = value; |
| chip.append(document.createTextNode(value)); |
| this._setupChip(chip); |
| return chip; |
| } |
| _createDismissButton() { |
| const button = document.createElement("button"); |
| button.type = "button"; |
| button.className = CLASS_NAME_CHIP_DISMISS; |
| button.setAttribute("aria-label", "Remove"); |
| button.setAttribute("tabindex", "-1"); |
| button.innerHTML = sanitizeHtml(this._config.dismissIcon, DefaultIconAllowlist); |
| return button; |
| } |
| _findChipByValue(value) { |
| return this._getChipElements().find((chip) => this._getChipValue(chip) === value); |
| } |
| _getChipValue(chip) { |
| if (chip.dataset.bsChipValue) return chip.dataset.bsChipValue; |
| const clone = chip.cloneNode(true); |
| const dismiss = SelectorEngine.findOne(SELECTOR_CHIP_DISMISS, clone); |
| if (dismiss) dismiss.remove(); |
| return clone.textContent?.trim() || ""; |
| } |
| _addEventListeners() { |
| EventHandler.on(this._input, "keydown", (event) => this._handleInputKeydown(event)); |
| EventHandler.on(this._input, "input", (event) => this._handleInput(event)); |
| EventHandler.on(this._input, "paste", (event) => this._handlePaste(event)); |
| EventHandler.on(this._input, "focus", () => this.clearSelection()); |
| if (this._config.createOnBlur) EventHandler.on(this._input, "blur", (event) => { |
| if (!event.relatedTarget?.closest(SELECTOR_CHIP)) this._createChipFromInput(); |
| }); |
| EventHandler.on(this._element, "click", SELECTOR_CHIP, (event) => { |
| if (event.target.closest(SELECTOR_CHIP_DISMISS)) return; |
| const chip = event.target.closest(SELECTOR_CHIP); |
| if (chip) { |
| event.preventDefault(); |
| this.selectChip(chip, { |
| addToSelection: event.metaKey || event.ctrlKey, |
| rangeSelect: event.shiftKey |
| }); |
| chip.focus(); |
| } |
| }); |
| EventHandler.on(this._element, "click", SELECTOR_CHIP_DISMISS, (event) => { |
| event.stopPropagation(); |
| const chip = event.target.closest(SELECTOR_CHIP); |
| if (chip) { |
| this.remove(chip); |
| this._input?.focus(); |
| } |
| }); |
| EventHandler.on(this._element, "keydown", SELECTOR_CHIP, (event) => { |
| this._handleChipKeydown(event); |
| }); |
| EventHandler.on(this._element, "click", (event) => { |
| if (event.target === this._element) { |
| this.clearSelection(); |
| this._input?.focus(); |
| } |
| }); |
| } |
| _handleInputKeydown(event) { |
| const { key } = event; |
| switch (key) { |
| case "Enter": |
| event.preventDefault(); |
| this._createChipFromInput(); |
| break; |
| case "Backspace": |
| case "Delete": |
| if (this._input.value === "") { |
| event.preventDefault(); |
| const chips = this._getChipElements(); |
| if (chips.length > 0) { |
| const lastChip = chips.at(-1); |
| this.selectChip(lastChip); |
| lastChip.focus(); |
| } |
| } |
| break; |
| case "ArrowLeft": |
| if (this._input.selectionStart === 0 && this._input.selectionEnd === 0) { |
| event.preventDefault(); |
| const chips = this._getChipElements(); |
| if (chips.length > 0) { |
| const lastChip = chips.at(-1); |
| if (event.shiftKey) this.selectChip(lastChip, { addToSelection: true }); |
| else this.selectChip(lastChip); |
| lastChip.focus(); |
| } |
| } |
| break; |
| case "Escape": |
| this._input.value = ""; |
| this.clearSelection(); |
| this._input.blur(); |
| break; |
| } |
| } |
| _handleChipKeydown(event) { |
| const { key } = event; |
| const chip = event.target.closest(SELECTOR_CHIP); |
| if (!chip) return; |
| const chips = this._getChipElements(); |
| const currentIndex = chips.indexOf(chip); |
| switch (key) { |
| case "Backspace": |
| case "Delete": |
| event.preventDefault(); |
| this._handleChipDelete(currentIndex, chips); |
| break; |
| case "ArrowLeft": |
| event.preventDefault(); |
| this._navigateChip(chips, currentIndex, -1, event.shiftKey); |
| break; |
| case "ArrowRight": |
| event.preventDefault(); |
| this._navigateChip(chips, currentIndex, 1, event.shiftKey); |
| break; |
| case "Home": |
| event.preventDefault(); |
| this._navigateToEdge(chips, 0, event.shiftKey); |
| break; |
| case "End": |
| event.preventDefault(); |
| this.clearSelection(); |
| this._input?.focus(); |
| break; |
| case "a": |
| this._handleSelectAll(event, chips); |
| break; |
| case "Escape": |
| event.preventDefault(); |
| this.clearSelection(); |
| this._input?.focus(); |
| break; |
| } |
| } |
| _handleChipDelete(currentIndex, chips) { |
| if (this._selectedChips.size === 0) return; |
| const nextIndex = Math.min(currentIndex, chips.length - this._selectedChips.size - 1); |
| this.removeSelected(); |
| const remainingChips = this._getChipElements(); |
| if (remainingChips.length > 0) { |
| const focusIndex = Math.max(0, Math.min(nextIndex, remainingChips.length - 1)); |
| remainingChips[focusIndex].focus(); |
| this.selectChip(remainingChips[focusIndex]); |
| } else this._input?.focus(); |
| } |
| _navigateChip(chips, currentIndex, direction, shiftKey) { |
| const targetIndex = currentIndex + direction; |
| if (direction < 0 && targetIndex >= 0) { |
| const targetChip = chips[targetIndex]; |
| this.selectChip(targetChip, shiftKey ? { |
| addToSelection: true, |
| rangeSelect: true |
| } : {}); |
| targetChip.focus(); |
| } else if (direction > 0 && targetIndex < chips.length) { |
| const targetChip = chips[targetIndex]; |
| this.selectChip(targetChip, shiftKey ? { |
| addToSelection: true, |
| rangeSelect: true |
| } : {}); |
| targetChip.focus(); |
| } else if (direction > 0) { |
| this.clearSelection(); |
| this._input?.focus(); |
| } |
| } |
| _navigateToEdge(chips, targetIndex, shiftKey) { |
| if (chips.length === 0) return; |
| const targetChip = chips[targetIndex]; |
| this.selectChip(targetChip, shiftKey ? { rangeSelect: true } : {}); |
| targetChip.focus(); |
| } |
| _handleSelectAll(event, chips) { |
| if (!(event.metaKey || event.ctrlKey)) return; |
| event.preventDefault(); |
| for (const c of chips) { |
| this._selectedChips.add(c); |
| c.classList.add(CLASS_NAME_ACTIVE$2); |
| } |
| EventHandler.trigger(this._element, EVENT_SELECT, { selected: this.getSelectedValues() }); |
| } |
| _handleInput(event) { |
| const { value } = event.target; |
| const { separator } = this._config; |
| if (separator && value.includes(separator)) { |
| const parts = value.split(separator); |
| for (const part of parts.slice(0, -1)) this.add(part.trim()); |
| this._input.value = parts.at(-1); |
| } |
| } |
| _handlePaste(event) { |
| const { separator } = this._config; |
| if (!separator) return; |
| const pastedData = (event.clipboardData || window.clipboardData).getData("text"); |
| if (pastedData.includes(separator)) { |
| event.preventDefault(); |
| const parts = pastedData.split(separator); |
| for (const part of parts) this.add(part.trim()); |
| } |
| } |
| _createChipFromInput() { |
| const value = this._input.value.trim(); |
| if (value) { |
| this.add(value); |
| this._input.value = ""; |
| } |
| } |
| }; |
| /** |
| * Data API implementation |
| */ |
| EventHandler.on(document, `DOMContentLoaded${EVENT_KEY$5}${DATA_API_KEY$2}`, () => { |
| for (const element of SelectorEngine.find(SELECTOR_DATA_CHIPS)) Chips.getOrCreateInstance(element); |
| }); |
| //#endregion |
| //#region js/src/util/template-factory.ts |
| /** |
| * -------------------------------------------------------------------------- |
| * Bootstrap util/template-factory.ts |
| * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) |
| * -------------------------------------------------------------------------- |
| */ |
| /** |
| * Constants |
| */ |
| const NAME$7 = "TemplateFactory"; |
| const Default$6 = { |
| allowList: DefaultAllowlist, |
| content: {}, |
| extraClass: "", |
| html: false, |
| sanitize: true, |
| sanitizeFn: null, |
| template: "<div></div>" |
| }; |
| const DefaultType$6 = { |
| allowList: "object", |
| content: "object", |
| extraClass: "(string|function)", |
| html: "boolean", |
| sanitize: "boolean", |
| sanitizeFn: "(null|function)", |
| template: "string" |
| }; |
| const DefaultContentType = { |
| entry: "(string|element|function|null)", |
| selector: "(string|element)" |
| }; |
| /** |
| * Class definition |
| */ |
| var TemplateFactory = class extends Config { |
| constructor(config) { |
| super(); |
| this._config = this._getConfig(config); |
| } |
| static get Default() { |
| return Default$6; |
| } |
| static get DefaultType() { |
| return DefaultType$6; |
| } |
| static get NAME() { |
| return NAME$7; |
| } |
| getContent() { |
| return Object.values(this._config.content).map((config) => this._resolvePossibleFunction(config)).filter(Boolean); |
| } |
| hasContent() { |
| return this.getContent().length > 0; |
| } |
| changeContent(content) { |
| this._checkContent(content); |
| this._config.content = { |
| ...this._config.content, |
| ...content |
| }; |
| return this; |
| } |
| toHtml() { |
| const templateWrapper = document.createElement("div"); |
| templateWrapper.innerHTML = this._maybeSanitize(this._config.template); |
| for (const [selector, text] of Object.entries(this._config.content)) this._setContent(templateWrapper, text, selector); |
| const template = templateWrapper.children[0]; |
| const extraClass = this._resolvePossibleFunction(this._config.extraClass); |
| if (extraClass) template.classList.add(...extraClass.split(" ")); |
| return template; |
| } |
| _typeCheckConfig(config) { |
| super._typeCheckConfig(config); |
| this._checkContent(config.content); |
| } |
| _checkContent(arg) { |
| for (const [selector, content] of Object.entries(arg)) super._typeCheckConfig({ |
| selector, |
| entry: content |
| }, DefaultContentType); |
| } |
| _setContent(template, content, selector) { |
| const templateElement = SelectorEngine.findOne(selector, template); |
| if (!templateElement) return; |
| content = this._resolvePossibleFunction(content); |
| if (!content) { |
| templateElement.remove(); |
| return; |
| } |
| if (isElement(content)) { |
| this._putElementInTemplate(getElement(content), templateElement); |
| return; |
| } |
| if (this._config.html) { |
| templateElement.innerHTML = this._maybeSanitize(content); |
| return; |
| } |
| templateElement.textContent = content; |
| } |
| _maybeSanitize(arg) { |
| return this._config.sanitize ? sanitizeHtml(arg, this._config.allowList, this._config.sanitizeFn) : arg; |
| } |
| _resolvePossibleFunction(arg) { |
| return execute(arg, [void 0, this]); |
| } |
| _putElementInTemplate(element, templateElement) { |
| if (this._config.html) { |
| templateElement.innerHTML = ""; |
| templateElement.append(element); |
| return; |
| } |
| templateElement.textContent = element.textContent; |
| } |
| }; |
| //#endregion |
| //#region js/src/tooltip.ts |
| /** |
| * -------------------------------------------------------------------------- |
| * Bootstrap tooltip.ts |
| * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) |
| * -------------------------------------------------------------------------- |
| */ |
| /** |
| * Constants |
| */ |
| const NAME$6 = "tooltip"; |
| const DISALLOWED_ATTRIBUTES = /* @__PURE__ */ new Set([ |
| "sanitize", |
| "allowList", |
| "sanitizeFn" |
| ]); |
| const ESCAPE_KEY = "Escape"; |
| const CLASS_NAME_MODAL = "modal"; |
| const CLASS_NAME_SHOW$2 = "show"; |
| const SELECTOR_TOOLTIP_INNER = ".tooltip-inner"; |
| const SELECTOR_MODAL = `.${CLASS_NAME_MODAL}`; |
| const SELECTOR_DATA_TOGGLE$3 = "[data-bs-toggle=\"tooltip\"]"; |
| const EVENT_MODAL_HIDE = "hide.bs.modal"; |
| const TRIGGER_HOVER = "hover"; |
| const TRIGGER_FOCUS = "focus"; |
| const TRIGGER_CLICK = "click"; |
| const TRIGGER_MANUAL = "manual"; |
| const EVENT_HIDE$2 = "hide"; |
| const EVENT_HIDDEN$2 = "hidden"; |
| const EVENT_SHOW$2 = "show"; |
| const EVENT_SHOWN$2 = "shown"; |
| const EVENT_INSERTED = "inserted"; |
| const EVENT_CLICK$3 = "click"; |
| const EVENT_FOCUSIN$2 = "focusin"; |
| const EVENT_FOCUSOUT$1 = "focusout"; |
| const EVENT_MOUSEENTER$1 = "mouseenter"; |
| const EVENT_MOUSELEAVE = "mouseleave"; |
| const EVENT_KEYDOWN$1 = "keydown"; |
| const AttachmentMap = { |
| AUTO: "auto", |
| TOP: "top", |
| RIGHT: isRTL() ? "left" : "right", |
| BOTTOM: "bottom", |
| LEFT: isRTL() ? "right" : "left" |
| }; |
| const Default$5 = { |
| allowList: DefaultAllowlist, |
| animation: true, |
| boundary: "clippingParents", |
| container: false, |
| customClass: "", |
| delay: 0, |
| fallbackPlacements: [ |
| "top", |
| "right", |
| "bottom", |
| "left" |
| ], |
| html: false, |
| offset: [0, 6], |
| placement: "top", |
| floatingConfig: null, |
| sanitize: true, |
| sanitizeFn: null, |
| selector: false, |
| template: "<div class=\"tooltip\" role=\"tooltip\"><div class=\"tooltip-arrow\"></div><div class=\"tooltip-inner\"></div></div>", |
| title: "", |
| trigger: "hover focus" |
| }; |
| const DefaultType$5 = { |
| allowList: "object", |
| animation: "boolean", |
| boundary: "(string|element)", |
| container: "(string|element|boolean)", |
| customClass: "(string|function)", |
| delay: "(number|object)", |
| fallbackPlacements: "array", |
| html: "boolean", |
| offset: "(array|string|function)", |
| placement: "(string|function)", |
| floatingConfig: "(null|object|function)", |
| sanitize: "boolean", |
| sanitizeFn: "(null|function)", |
| selector: "(string|boolean)", |
| template: "string", |
| title: "(string|element|function)", |
| trigger: "string" |
| }; |
| /** |
| * Class definition |
| */ |
| var Tooltip = class extends BaseComponent { |
| constructor(element, config) { |
| if (typeof computePosition === "undefined") throw new TypeError("Bootstrap's tooltips require Floating UI (https://floating-ui.com)"); |
| super(element, config); |
| this._isEnabled = true; |
| this._timeout = 0; |
| this._resolveTimeout = null; |
| this._isHovered = null; |
| this._activeTrigger = {}; |
| this._floatingCleanup = null; |
| this._keydownHandler = null; |
| this._tipEventOut = null; |
| this._templateFactory = null; |
| this._newContent = null; |
| this._mediaQueryListeners = []; |
| this._responsivePlacements = null; |
| this.tip = null; |
| this._parseResponsivePlacements(); |
| this._setListeners(); |
| if (!this._config.selector) this._fixTitle(); |
| } |
| static get Default() { |
| return Default$5; |
| } |
| static get DefaultType() { |
| return DefaultType$5; |
| } |
| static get NAME() { |
| return NAME$6; |
| } |
| enable() { |
| this._isEnabled = true; |
| } |
| disable() { |
| this._isEnabled = false; |
| } |
| toggleEnabled() { |
| this._isEnabled = !this._isEnabled; |
| } |
| toggle() { |
| if (!this._isEnabled) return Promise.resolve(); |
| return this._isShown() ? this._leave() : this._enter(); |
| } |
| dispose() { |
| this._clearTimeout(); |
| this._removeEscapeListener(); |
| EventHandler.off(this._element.closest(SELECTOR_MODAL), EVENT_MODAL_HIDE, this._hideModalHandler); |
| if (this._element.getAttribute("data-bs-original-title")) this._element.setAttribute("title", this._element.getAttribute("data-bs-original-title")); |
| this._disposeFloating(); |
| this._disposeMediaQueryListeners(); |
| super.dispose(); |
| } |
| async show() { |
| if (this._element.style.display === "none") throw new Error("Please use show on visible elements"); |
| if (!(this._isWithContent() && this._isEnabled)) return; |
| const showEvent = EventHandler.trigger(this._element, this.constructor.eventName(EVENT_SHOW$2)); |
| const isInTheDom = (findShadowRoot(this._element) || this._element.ownerDocument.documentElement).contains(this._element); |
| if (showEvent.defaultPrevented || !isInTheDom) { |
| this._isHovered = false; |
| return; |
| } |
| this._disposeFloating(); |
| const tip = this._getTipElement(); |
| this._element.setAttribute("aria-describedby", tip.getAttribute("id")); |
| let { container } = this._config; |
| const closestDialog = this._element.closest("dialog[open]"); |
| if (closestDialog && container === document.body) container = closestDialog; |
| if (!this._element.ownerDocument.documentElement.contains(this.tip)) { |
| container.append(tip); |
| EventHandler.trigger(this._element, this.constructor.eventName(EVENT_INSERTED)); |
| this._setTipListeners(tip); |
| } |
| await this._createFloating(tip); |
| tip.classList.add(CLASS_NAME_SHOW$2); |
| this._setEscapeListener(); |
| if ("ontouchstart" in document.documentElement) for (const element of document.body.children) EventHandler.on(element, "mouseover", noop); |
| const complete = () => { |
| EventHandler.trigger(this._element, this.constructor.eventName(EVENT_SHOWN$2)); |
| if (this._isHovered === false) this._leave(); |
| this._isHovered = false; |
| }; |
| await this._queueCallback(complete, this.tip, this._isAnimated()); |
| } |
| async hide() { |
| if (!this._isShown()) return; |
| if (EventHandler.trigger(this._element, this.constructor.eventName(EVENT_HIDE$2)).defaultPrevented) return; |
| this._removeEscapeListener(); |
| this._getTipElement().classList.remove(CLASS_NAME_SHOW$2); |
| if ("ontouchstart" in document.documentElement) for (const element of document.body.children) EventHandler.off(element, "mouseover", noop); |
| this._activeTrigger[TRIGGER_CLICK] = false; |
| this._activeTrigger[TRIGGER_FOCUS] = false; |
| this._activeTrigger[TRIGGER_HOVER] = false; |
| this._isHovered = null; |
| const complete = () => { |
| if (this._isWithActiveTrigger()) return; |
| if (!this._isHovered) this._disposeFloating(); |
| this._element.removeAttribute("aria-describedby"); |
| EventHandler.trigger(this._element, this.constructor.eventName(EVENT_HIDDEN$2)); |
| }; |
| await this._queueCallback(complete, this.tip, this._isAnimated()); |
| } |
| update() { |
| if (this._floatingCleanup && this.tip) this._updateFloatingPosition(); |
| } |
| _isWithContent() { |
| return Boolean(this._getTitle()) || this._hasNewContent(); |
| } |
| _hasNewContent() { |
| return Boolean(this._newContent) && Object.values(this._newContent).some(Boolean); |
| } |
| _getTipElement() { |
| if (!this.tip) this.tip = this._createTipElement(this._newContent || this._getContentForTemplate()); |
| return this.tip; |
| } |
| _createTipElement(content) { |
| const tip = this._getTemplateFactory(content).toHtml(); |
| tip.classList.remove(CLASS_NAME_SHOW$2); |
| tip.classList.add(`bs-${this.constructor.NAME}-auto`); |
| const tipId = getUID(this.constructor.NAME).toString(); |
| tip.setAttribute("id", tipId); |
| if (!this._config.animation) tip.classList.add(this._getInstantClassName()); |
| return tip; |
| } |
| setContent(content) { |
| this._newContent = content; |
| if (this._isShown()) { |
| this._disposeFloating(); |
| this.show(); |
| } |
| } |
| _getTemplateFactory(content) { |
| if (this._templateFactory) this._templateFactory.changeContent(content); |
| else this._templateFactory = new TemplateFactory({ |
| ...this._config, |
| content, |
| extraClass: this._resolvePossibleFunction(this._config.customClass) |
| }); |
| return this._templateFactory; |
| } |
| _getContentForTemplate() { |
| return { [SELECTOR_TOOLTIP_INNER]: this._getTitle() }; |
| } |
| _getTitle() { |
| return this._resolvePossibleFunction(this._config.title) || this._element.getAttribute("data-bs-original-title"); |
| } |
| _initializeOnDelegatedTarget(event) { |
| return this.constructor.getOrCreateInstance(event.delegateTarget, this._getDelegateConfig()); |
| } |
| _getInstantClassName() { |
| return `${this.constructor.NAME}-instant`; |
| } |
| _isAnimated() { |
| return getTransitionDurationFromElement(this.tip) > 0; |
| } |
| _isShown() { |
| return this.tip && this.tip.classList.contains(CLASS_NAME_SHOW$2); |
| } |
| _getPlacement(tip) { |
| if (this._responsivePlacements) { |
| const placement = getResponsivePlacement(this._responsivePlacements, "top"); |
| return AttachmentMap[placement.toUpperCase()] || placement; |
| } |
| const placement = execute(this._config.placement, [ |
| this, |
| tip, |
| this._element |
| ]); |
| return AttachmentMap[placement.toUpperCase()] || placement; |
| } |
| _parseResponsivePlacements() { |
| if (typeof this._config.placement !== "string") { |
| this._responsivePlacements = null; |
| return; |
| } |
| this._responsivePlacements = parseResponsivePlacement(this._config.placement, "top"); |
| if (this._responsivePlacements) this._setupMediaQueryListeners(); |
| } |
| _setupMediaQueryListeners() { |
| this._disposeMediaQueryListeners(); |
| this._mediaQueryListeners = createBreakpointListeners(() => { |
| if (this._isShown()) this._updateFloatingPosition(); |
| }); |
| } |
| _disposeMediaQueryListeners() { |
| disposeBreakpointListeners(this._mediaQueryListeners); |
| this._mediaQueryListeners = []; |
| } |
| async _createFloating(tip) { |
| const placement = this._getPlacement(tip); |
| const arrowElement = tip.querySelector(`.${this.constructor.NAME}-arrow`); |
| await this._updateFloatingPosition(tip, placement, arrowElement); |
| this._floatingCleanup = autoUpdate(this._element, tip, () => this._updateFloatingPosition(tip, null, arrowElement)); |
| } |
| async _updateFloatingPosition(tip = this.tip, placement = null, arrowElement = null) { |
| if (!tip) return; |
| if (!placement) placement = this._getPlacement(tip); |
| if (!arrowElement) arrowElement = tip.querySelector(`.${this.constructor.NAME}-arrow`); |
| const middleware = this._getFloatingMiddleware(arrowElement); |
| const floatingConfig = this._getFloatingConfig(placement, middleware); |
| const { x, y, placement: finalPlacement, middlewareData } = await computePosition(this._element, tip, floatingConfig); |
| Object.assign(tip.style, { |
| position: "absolute", |
| left: `${x}px`, |
| top: `${y}px` |
| }); |
| if (arrowElement) arrowElement.style.position = "absolute"; |
| Manipulator.setDataAttribute(tip, "placement", finalPlacement); |
| if (arrowElement && middlewareData.arrow) { |
| const { x: arrowX, y: arrowY } = middlewareData.arrow; |
| const isVertical = finalPlacement.startsWith("top") || finalPlacement.startsWith("bottom"); |
| Object.assign(arrowElement.style, { |
| left: isVertical && arrowX !== void 0 ? `${arrowX}px` : "", |
| top: !isVertical && arrowY !== void 0 ? `${arrowY}px` : "", |
| right: "", |
| bottom: "" |
| }); |
| } |
| } |
| _getOffset() { |
| const { offset } = this._config; |
| if (typeof offset === "string") return offset.split(",").map((value) => Number.parseInt(value, 10)); |
| if (typeof offset === "function") return ({ placement, rects }) => { |
| return toFloatingOffset(offset({ |
| placement, |
| reference: rects.reference, |
| floating: rects.floating |
| }, this._element)); |
| }; |
| return offset; |
| } |
| _resolvePossibleFunction(arg) { |
| return execute(arg, [this._element, this._element]); |
| } |
| _getFloatingMiddleware(arrowElement) { |
| const offsetValue = this._getOffset(); |
| const middleware = [ |
| offset(typeof offsetValue === "function" ? offsetValue : toFloatingOffset(offsetValue)), |
| flip({ fallbackPlacements: this._config.fallbackPlacements }), |
| shift({ boundary: this._config.boundary === "clippingParents" ? "clippingAncestors" : this._config.boundary }) |
| ]; |
| if (arrowElement) middleware.push(arrow({ element: arrowElement })); |
| return middleware; |
| } |
| _getFloatingConfig(placement, middleware) { |
| const defaultConfig = { |
| placement, |
| middleware |
| }; |
| return { |
| ...defaultConfig, |
| ...execute(this._config.floatingConfig, [void 0, defaultConfig]) |
| }; |
| } |
| _setListeners() { |
| const triggers = this._config.trigger.split(" "); |
| for (const trigger of triggers) if (trigger === "click") EventHandler.on(this._element, this.constructor.eventName(EVENT_CLICK$3), this._config.selector, (event) => { |
| const context = this._initializeOnDelegatedTarget(event); |
| context._activeTrigger[TRIGGER_CLICK] = !(context._isShown() && context._activeTrigger[TRIGGER_CLICK]); |
| context.toggle(); |
| }); |
| else if (trigger !== TRIGGER_MANUAL) { |
| const [eventIn, eventOut] = this._getTriggerEvents(trigger); |
| EventHandler.on(this._element, eventIn, this._config.selector, (event) => { |
| const context = this._initializeOnDelegatedTarget(event); |
| context._activeTrigger[event.type === "focusin" ? TRIGGER_FOCUS : TRIGGER_HOVER] = true; |
| context._enter(); |
| }); |
| EventHandler.on(this._element, eventOut, this._config.selector, (event) => { |
| const context = this._initializeOnDelegatedTarget(event); |
| context._activeTrigger[event.type === "focusout" ? TRIGGER_FOCUS : TRIGGER_HOVER] = context._isInside(event.relatedTarget); |
| context._leave(); |
| }); |
| } |
| this._hideModalHandler = () => { |
| if (this._element) this.hide(); |
| }; |
| EventHandler.on(this._element.closest(SELECTOR_MODAL), EVENT_MODAL_HIDE, this._hideModalHandler); |
| } |
| _setTipListeners(tip) { |
| const trigger = this._getTrigger(); |
| if (trigger === TRIGGER_MANUAL || trigger.includes(TRIGGER_CLICK)) return; |
| this._tipEventOut = (event) => { |
| this._activeTrigger[event.type === "focusout" ? TRIGGER_FOCUS : TRIGGER_HOVER] = this._isInside(event.relatedTarget); |
| this._leave(); |
| }; |
| for (const name of trigger.split(" ")) if (name === TRIGGER_HOVER || name === TRIGGER_FOCUS) { |
| const [, eventOut] = this._getTriggerEvents(name); |
| EventHandler.on(tip, eventOut, this._tipEventOut); |
| } |
| } |
| _removeTipListeners(tip) { |
| if (!this._tipEventOut) return; |
| const trigger = this._getTrigger(); |
| for (const name of trigger.split(" ")) if (name === TRIGGER_HOVER || name === TRIGGER_FOCUS) { |
| const [, eventOut] = this._getTriggerEvents(name); |
| EventHandler.off(tip, eventOut, this._tipEventOut); |
| } |
| this._tipEventOut = null; |
| } |
| _isInside(element) { |
| return this._element.contains(element) || Boolean(this.tip?.contains(element)); |
| } |
| _getTrigger() { |
| return this._config._trigger; |
| } |
| _getTriggerEvents(trigger) { |
| return { |
| [TRIGGER_HOVER]: [this.constructor.eventName(EVENT_MOUSEENTER$1), this.constructor.eventName(EVENT_MOUSELEAVE)], |
| [TRIGGER_FOCUS]: [this.constructor.eventName(EVENT_FOCUSIN$2), this.constructor.eventName(EVENT_FOCUSOUT$1)] |
| }[trigger]; |
| } |
| _setEscapeListener() { |
| if (this._keydownHandler) return; |
| this._keydownHandler = (event) => { |
| if (event.key !== ESCAPE_KEY || !this._isShown() || !this.tip.isConnected) return; |
| event.preventDefault(); |
| event.stopPropagation(); |
| this.hide(); |
| }; |
| this._element.ownerDocument.addEventListener(EVENT_KEYDOWN$1, this._keydownHandler, true); |
| } |
| _removeEscapeListener() { |
| if (!this._keydownHandler) return; |
| this._element.ownerDocument.removeEventListener(EVENT_KEYDOWN$1, this._keydownHandler, true); |
| this._keydownHandler = null; |
| } |
| _fixTitle() { |
| const title = this._element.getAttribute("title"); |
| if (!title) return; |
| if (!this._element.getAttribute("aria-label") && !this._element.textContent.trim()) this._element.setAttribute("aria-label", title); |
| this._element.setAttribute("data-bs-original-title", title); |
| this._element.removeAttribute("title"); |
| } |
| _enter() { |
| if (this._isShown() || this._isHovered) { |
| this._isHovered = true; |
| return Promise.resolve(); |
| } |
| this._isHovered = true; |
| return this._setTimeout(() => this._isHovered ? this.show() : void 0, this._config.delay.show); |
| } |
| _leave() { |
| if (this._isWithActiveTrigger()) return Promise.resolve(); |
| this._isHovered = false; |
| return this._setTimeout(() => this._isHovered ? void 0 : this.hide(), this._config.delay.hide); |
| } |
| _setTimeout(handler, timeout) { |
| this._clearTimeout(); |
| return new Promise((resolve) => { |
| this._resolveTimeout = resolve; |
| this._timeout = setTimeout(() => { |
| this._resolveTimeout = null; |
| resolve(handler()); |
| }, timeout); |
| }); |
| } |
| _clearTimeout() { |
| clearTimeout(this._timeout); |
| if (this._resolveTimeout) { |
| this._resolveTimeout(); |
| this._resolveTimeout = null; |
| } |
| } |
| _isWithActiveTrigger() { |
| return Object.values(this._activeTrigger).includes(true); |
| } |
| _getConfig(config) { |
| const dataAttributes = Manipulator.getDataAttributes(this._element); |
| for (const dataAttribute of Object.keys(dataAttributes)) if (DISALLOWED_ATTRIBUTES.has(dataAttribute)) delete dataAttributes[dataAttribute]; |
| config = { |
| ...dataAttributes, |
| ...typeof config === "object" && config ? config : {} |
| }; |
| config = this._mergeConfigObj(config); |
| config = this._configAfterMerge(config); |
| this._typeCheckConfig(config); |
| return config; |
| } |
| _configAfterMerge(config) { |
| config.container = config.container === false ? document.body : getElement(config.container); |
| config._trigger = config._trigger || config.trigger; |
| if (typeof config.delay === "number") config.delay = { |
| show: config.delay, |
| hide: config.delay |
| }; |
| if (typeof config.title === "number" || typeof config.title === "boolean") config.title = config.title.toString(); |
| if (typeof config.content === "number" || typeof config.content === "boolean") config.content = config.content.toString(); |
| return config; |
| } |
| _getDelegateConfig() { |
| const config = {}; |
| for (const [key, value] of Object.entries(this._config)) if (this.constructor.Default[key] !== value) config[key] = value; |
| config.selector = false; |
| config.trigger = "manual"; |
| return config; |
| } |
| _disposeFloating() { |
| if (this._floatingCleanup) { |
| this._floatingCleanup(); |
| this._floatingCleanup = null; |
| } |
| if (this.tip) { |
| this._removeTipListeners(this.tip); |
| this.tip.remove(); |
| this.tip = null; |
| } |
| } |
| }; |
| /** |
| * Data API implementation - auto-initialize tooltips |
| */ |
| const initTooltip = (event) => { |
| const target = event.target.closest(SELECTOR_DATA_TOGGLE$3); |
| if (!target) return; |
| Tooltip.getOrCreateInstance(target); |
| }; |
| EventHandler.on(document, EVENT_FOCUSIN$2, SELECTOR_DATA_TOGGLE$3, initTooltip); |
| EventHandler.on(document, EVENT_MOUSEENTER$1, SELECTOR_DATA_TOGGLE$3, initTooltip); |
| //#endregion |
| //#region js/src/popover.ts |
| /** |
| * -------------------------------------------------------------------------- |
| * Bootstrap popover.ts |
| * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) |
| * -------------------------------------------------------------------------- |
| */ |
| /** |
| * Constants |
| */ |
| const NAME$5 = "popover"; |
| const SELECTOR_TITLE = ".popover-header"; |
| const SELECTOR_CONTENT = ".popover-body"; |
| const SELECTOR_DATA_TOGGLE$2 = "[data-bs-toggle=\"popover\"]"; |
| const EVENT_CLICK$2 = "click"; |
| const EVENT_FOCUSIN$1 = "focusin"; |
| const EVENT_MOUSEENTER = "mouseenter"; |
| const Default$4 = { |
| ...Tooltip.Default, |
| content: "", |
| offset: [0, 8], |
| placement: "right", |
| template: "<div class=\"popover\" role=\"tooltip\"><div class=\"popover-arrow\"></div><h3 class=\"popover-header\"></h3><div class=\"popover-body\"></div></div>", |
| trigger: "click" |
| }; |
| const DefaultType$4 = { |
| ...Tooltip.DefaultType, |
| content: "(null|string|element|function)" |
| }; |
| /** |
| * Class definition |
| */ |
| var Popover = class extends Tooltip { |
| constructor(element, config) { |
| super(element, config); |
| } |
| static get Default() { |
| return Default$4; |
| } |
| static get DefaultType() { |
| return DefaultType$4; |
| } |
| static get NAME() { |
| return NAME$5; |
| } |
| _isWithContent() { |
| return Boolean(this._getTitle() || this._getContent()) || this._hasNewContent(); |
| } |
| _getContentForTemplate() { |
| return { |
| [SELECTOR_TITLE]: this._getTitle(), |
| [SELECTOR_CONTENT]: this._getContent() |
| }; |
| } |
| _getContent() { |
| return this._resolvePossibleFunction(this._config.content); |
| } |
| }; |
| /** |
| * Data API implementation - auto-initialize popovers |
| */ |
| const initPopover = (event) => { |
| const target = event.target.closest(SELECTOR_DATA_TOGGLE$2); |
| if (!target) return; |
| if (event.type === "click") event.preventDefault(); |
| Popover.getOrCreateInstance(target); |
| }; |
| EventHandler.on(document, EVENT_CLICK$2, SELECTOR_DATA_TOGGLE$2, initPopover); |
| EventHandler.on(document, EVENT_FOCUSIN$1, SELECTOR_DATA_TOGGLE$2, initPopover); |
| EventHandler.on(document, EVENT_MOUSEENTER, SELECTOR_DATA_TOGGLE$2, initPopover); |
| //#endregion |
| //#region js/src/range.ts |
| /** |
| * -------------------------------------------------------------------------- |
| * Bootstrap range.ts |
| * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) |
| * -------------------------------------------------------------------------- |
| */ |
| /** |
| * Constants |
| */ |
| const NAME$4 = "range"; |
| const EVENT_KEY$4 = `.bs.range`; |
| const DATA_API_KEY$1 = ".data-api"; |
| const EVENT_CHANGED = `changed${EVENT_KEY$4}`; |
| const EVENT_DOM_CONTENT_LOADED = `DOMContentLoaded${EVENT_KEY$4}${DATA_API_KEY$1}`; |
| const EVENT_INPUT = "input"; |
| const EVENT_CHANGE = "change"; |
| const SELECTOR_RANGE = ".form-range"; |
| const SELECTOR_INPUT = ".form-range-input"; |
| const CLASS_NAME_BUBBLE = "form-range-bubble"; |
| const CLASS_NAME_TICKS = "form-range-ticks"; |
| const CLASS_NAME_TICK = "form-range-tick"; |
| const CLASS_NAME_TICK_LABEL = "form-range-tick-label"; |
| const PROPERTY_FILL = "--bs-range-fill"; |
| const Default$3 = { |
| bubble: false, |
| formatter: null |
| }; |
| const DefaultType$3 = { |
| bubble: "(boolean|null)", |
| formatter: "(function|null)" |
| }; |
| /** |
| * Class definition |
| */ |
| var Range = class extends BaseComponent { |
| constructor(element, config) { |
| super(element, config); |
| if (!this._element) return; |
| this._input = SelectorEngine.findOne(SELECTOR_INPUT, this._element); |
| if (!this._input) return; |
| this._bubble = null; |
| this._bubbleText = null; |
| this._ticks = null; |
| this._updateHandler = () => this._update(); |
| if (this._config.bubble) this._createBubble(); |
| this._createTicks(); |
| this._addEventListeners(); |
| this._update(); |
| } |
| static get Default() { |
| return Default$3; |
| } |
| static get DefaultType() { |
| return DefaultType$3; |
| } |
| static get NAME() { |
| return NAME$4; |
| } |
| update() { |
| this._update(); |
| } |
| dispose() { |
| EventHandler.off(this._input, EVENT_INPUT, this._updateHandler); |
| EventHandler.off(this._input, EVENT_CHANGE, this._updateHandler); |
| this._bubble?.remove(); |
| this._ticks?.remove(); |
| super.dispose(); |
| } |
| _configAfterMerge(config) { |
| if (config.bubble === null) config.bubble = true; |
| return config; |
| } |
| _addEventListeners() { |
| EventHandler.on(this._input, EVENT_INPUT, this._updateHandler); |
| EventHandler.on(this._input, EVENT_CHANGE, this._updateHandler); |
| } |
| _min() { |
| return this._input.min === "" ? 0 : Number.parseFloat(this._input.min); |
| } |
| _max() { |
| return this._input.max === "" ? 100 : Number.parseFloat(this._input.max); |
| } |
| _value() { |
| return Number.parseFloat(this._input.value); |
| } |
| _ratio() { |
| const span = this._max() - this._min(); |
| return span > 0 ? (this._value() - this._min()) / span : 0; |
| } |
| _update() { |
| this._element.style.setProperty(PROPERTY_FILL, `${this._ratio()}`); |
| if (this._bubbleText) this._bubbleText.textContent = this._format(this._value()); |
| EventHandler.trigger(this._input, EVENT_CHANGED, { value: this._value() }); |
| } |
| _format(value) { |
| return typeof this._config.formatter === "function" ? this._config.formatter(value) : String(value); |
| } |
| _createBubble() { |
| this._bubble = document.createElement("output"); |
| this._bubble.className = `${CLASS_NAME_BUBBLE} tooltip bs-tooltip-top show`; |
| this._bubble.setAttribute("aria-hidden", "true"); |
| const arrow = document.createElement("div"); |
| arrow.className = "tooltip-arrow"; |
| this._bubbleText = document.createElement("div"); |
| this._bubbleText.className = "tooltip-inner"; |
| this._bubble.append(arrow, this._bubbleText); |
| this._input.insertAdjacentElement("afterend", this._bubble); |
| } |
| _createTicks() { |
| const listId = this._input.getAttribute("list"); |
| const datalist = listId ? document.getElementById(listId) : null; |
| if (!datalist) return; |
| const min = this._min(); |
| const span = this._max() - min || 1; |
| const points = []; |
| for (const option of SelectorEngine.find("option", datalist)) { |
| const value = Number.parseFloat(option.value); |
| if (!Number.isNaN(value)) { |
| const ratio = Math.min(Math.max((value - min) / span, 0), 1); |
| points.push({ |
| ratio, |
| label: option.label |
| }); |
| } |
| } |
| if (points.length === 0) return; |
| points.sort((a, b) => a.ratio - b.ratio); |
| this._ticks = document.createElement("div"); |
| this._ticks.className = CLASS_NAME_TICKS; |
| this._ticks.setAttribute("aria-hidden", "true"); |
| const stops = [ |
| 0, |
| ...points.map((point) => point.ratio), |
| 1 |
| ]; |
| this._ticks.style.gridTemplateColumns = stops.slice(1).map((stop, index) => `${stop - stops[index]}fr`).join(" "); |
| for (const [index, point] of points.entries()) { |
| const tick = document.createElement("span"); |
| tick.className = CLASS_NAME_TICK; |
| tick.style.gridColumnStart = `${index + 2}`; |
| if (point.label) { |
| const label = document.createElement("span"); |
| label.className = CLASS_NAME_TICK_LABEL; |
| label.textContent = point.label; |
| tick.append(label); |
| } |
| this._ticks.append(tick); |
| } |
| this._element.append(this._ticks); |
| } |
| }; |
| /** |
| * Data API implementation |
| */ |
| EventHandler.on(document, EVENT_DOM_CONTENT_LOADED, () => { |
| for (const element of SelectorEngine.find(SELECTOR_RANGE)) Range.getOrCreateInstance(element); |
| }); |
| //#endregion |
| //#region js/src/scrollspy.ts |
| /** |
| * -------------------------------------------------------------------------- |
| * Bootstrap scrollspy.ts |
| * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) |
| * -------------------------------------------------------------------------- |
| */ |
| /** |
| * Constants |
| */ |
| const NAME$3 = "scrollspy"; |
| const EVENT_KEY$3 = `.bs.scrollspy`; |
| const DATA_API_KEY = ".data-api"; |
| const EVENT_ACTIVATE = `activate${EVENT_KEY$3}`; |
| const EVENT_CLICK$1 = `click${EVENT_KEY$3}`; |
| const EVENT_SCROLL = `scroll${EVENT_KEY$3}`; |
| const EVENT_SCROLLEND = `scrollend${EVENT_KEY$3}`; |
| const EVENT_RESIZE = `resize${EVENT_KEY$3}`; |
| const EVENT_LOAD_DATA_API$1 = `load${EVENT_KEY$3}${DATA_API_KEY}`; |
| const CLASS_NAME_MENU_ITEM = "menu-item"; |
| const CLASS_NAME_ACTIVE$1 = "active"; |
| const SELECTOR_DATA_SPY = "[data-bs-spy=\"scroll\"]"; |
| const SELECTOR_TARGET_LINKS = "[href]"; |
| const SELECTOR_NAV_LIST_GROUP = ".nav, .list-group"; |
| const SELECTOR_NAV_LINKS = ".nav-link"; |
| const SELECTOR_LINK_ITEMS = `${SELECTOR_NAV_LINKS}, .nav-item > ${SELECTOR_NAV_LINKS}, .list-group-item`; |
| const SELECTOR_MENU_TOGGLE$1 = "[data-bs-toggle=\"menu\"]"; |
| const SCROLL_IDLE_TIMEOUT = 100; |
| const RESIZE_DEBOUNCE = 100; |
| const Default$2 = { |
| rootMargin: null, |
| smoothScroll: false, |
| target: null, |
| threshold: [0], |
| topMargin: "12%" |
| }; |
| const DefaultType$2 = { |
| rootMargin: "(string|null)", |
| smoothScroll: "boolean", |
| target: "element", |
| threshold: "array", |
| topMargin: "string" |
| }; |
| /** |
| * Class definition |
| */ |
| var ScrollSpy = class extends BaseComponent { |
| constructor(element, config) { |
| super(element, config); |
| this._sections = []; |
| this._linkBySection = /* @__PURE__ */ new Map(); |
| this._sectionByLink = /* @__PURE__ */ new Map(); |
| this._intersecting = /* @__PURE__ */ new Set(); |
| this._activeTarget = null; |
| this._lastActive = null; |
| this._atBottom = false; |
| this._rootElement = getComputedStyle(this._element).overflowY === "visible" ? null : this._element; |
| this._observer = null; |
| this._sentinel = null; |
| this._sentinelObserver = null; |
| this._pendingNavigation = null; |
| this._settleTimeout = null; |
| this._settleHandler = null; |
| this._scrollIdleHandler = null; |
| this._resizeHandler = null; |
| this._resizeTimeout = null; |
| this.refresh(); |
| } |
| static get Default() { |
| return Default$2; |
| } |
| static get DefaultType() { |
| return DefaultType$2; |
| } |
| static get NAME() { |
| return NAME$3; |
| } |
| refresh() { |
| this._initializeTargetsAndObservables(); |
| this._maybeEnableSmoothScroll(); |
| this._observer?.disconnect(); |
| this._intersecting.clear(); |
| this._observer = this._getNewObserver(); |
| for (const section of this._sections) this._observer.observe(section); |
| this._setUpSentinel(); |
| this._maybeAddResizeListener(); |
| } |
| dispose() { |
| this._observer?.disconnect(); |
| this._teardownSentinel(); |
| this._disarmSettle(); |
| this._removeResizeListener(); |
| EventHandler.off(this._config.target, EVENT_CLICK$1); |
| super.dispose(); |
| } |
| _configAfterMerge(config) { |
| config.target = getElement(config.target) || document.body; |
| if (typeof config.threshold === "string") config.threshold = config.threshold.split(",").map((value) => Number.parseFloat(value)); |
| return config; |
| } |
| _getNewObserver() { |
| const options = { |
| root: this._rootElement, |
| threshold: this._config.threshold, |
| rootMargin: this._config.rootMargin ?? this._getDerivedRootMargin() |
| }; |
| return new IntersectionObserver((entries) => this._onIntersect(entries), options); |
| } |
| _onIntersect(entries) { |
| for (const entry of entries) if (entry.isIntersecting) this._intersecting.add(entry.target); |
| else this._intersecting.delete(entry.target); |
| this._computeActive(); |
| } |
| _computeActive() { |
| if (!this._element?.isConnected || this._sections.length === 0) return; |
| let active = null; |
| if (this._atBottom) active = this._sections.at(-1); |
| else { |
| for (const section of this._sections) if (this._intersecting.has(section)) active = section; |
| active ||= this._lastActive ?? this._sections.at(0); |
| } |
| if (!active) return; |
| this._lastActive = active; |
| const link = this._linkBySection.get(active); |
| if (link) this._process(link); |
| } |
| _parseTopMargin() { |
| const value = String(this._config.topMargin); |
| return { |
| value: Number.parseFloat(value) || 0, |
| unit: value.endsWith("%") ? "%" : "px" |
| }; |
| } |
| _getDerivedRootMargin() { |
| const { value, unit } = this._parseTopMargin(); |
| let percent = value; |
| if (unit === "px") { |
| const rootHeight = this._rootElement ? this._rootElement.clientHeight : document.documentElement.clientHeight || window.innerHeight; |
| percent = rootHeight ? value / rootHeight * 100 : 12; |
| } |
| return `0px 0px -${Math.min(Math.max(100 - percent, 0), 100)}% 0px`; |
| } |
| _usesPixelMargin() { |
| return !this._config.rootMargin && this._parseTopMargin().unit === "px"; |
| } |
| _setUpSentinel() { |
| this._teardownSentinel(); |
| if (this._sections.length === 0) return; |
| const sentinel = document.createElement("div"); |
| sentinel.setAttribute("aria-hidden", "true"); |
| sentinel.style.cssText = "position:relative;width:0;height:0;margin:0;padding:0;border:0;visibility:hidden;"; |
| this._element.append(sentinel); |
| this._sentinel = sentinel; |
| this._sentinelObserver = new IntersectionObserver((entries) => this._onSentinel(entries), { |
| root: this._rootElement, |
| threshold: [0] |
| }); |
| this._sentinelObserver.observe(sentinel); |
| } |
| _onSentinel(entries) { |
| const entry = entries.at(-1); |
| this._atBottom = Boolean(entry?.isIntersecting) && this._isOverflowing(); |
| this._computeActive(); |
| } |
| _isOverflowing() { |
| const scroller = this._rootElement || document.scrollingElement || document.documentElement; |
| return scroller.scrollHeight > scroller.clientHeight; |
| } |
| _teardownSentinel() { |
| this._sentinelObserver?.disconnect(); |
| this._sentinelObserver = null; |
| this._sentinel?.remove(); |
| this._sentinel = null; |
| this._atBottom = false; |
| } |
| _maybeAddResizeListener() { |
| this._removeResizeListener(); |
| if (!this._usesPixelMargin()) return; |
| this._resizeHandler = () => { |
| clearTimeout(this._resizeTimeout); |
| this._resizeTimeout = setTimeout(() => this._rebuildObserver(), RESIZE_DEBOUNCE); |
| }; |
| EventHandler.on(window, EVENT_RESIZE, this._resizeHandler); |
| } |
| _removeResizeListener() { |
| clearTimeout(this._resizeTimeout); |
| this._resizeTimeout = null; |
| if (this._resizeHandler) { |
| EventHandler.off(window, EVENT_RESIZE, this._resizeHandler); |
| this._resizeHandler = null; |
| } |
| } |
| _rebuildObserver() { |
| if (!this._observer) return; |
| this._observer.disconnect(); |
| this._intersecting.clear(); |
| this._observer = this._getNewObserver(); |
| for (const section of this._sections) this._observer.observe(section); |
| } |
| _maybeEnableSmoothScroll() { |
| if (!this._config.smoothScroll) return; |
| EventHandler.off(this._config.target, EVENT_CLICK$1); |
| EventHandler.on(this._config.target, EVENT_CLICK$1, SELECTOR_TARGET_LINKS, (event) => { |
| const link = event.target.closest(SELECTOR_TARGET_LINKS); |
| const section = link && this._sectionByLink.get(link); |
| if (!section || !this._element) return; |
| event.preventDefault(); |
| const root = this._rootElement || window; |
| const height = section.offsetTop - this._element.offsetTop; |
| const currentTop = this._rootElement ? this._rootElement.scrollTop : window.scrollY ?? window.pageYOffset; |
| if (matchMedia("(prefers-reduced-motion: reduce)").matches || Math.abs(currentTop - height) <= 2) { |
| if (root.scrollTo) root.scrollTo({ |
| top: height, |
| behavior: "auto" |
| }); |
| else root.scrollTop = height; |
| this._settleNavigation(link.hash, section); |
| return; |
| } |
| this._pendingNavigation = { |
| hash: link.hash, |
| section |
| }; |
| this._armSettle(); |
| if (root.scrollTo) root.scrollTo({ |
| top: height, |
| behavior: "smooth" |
| }); |
| else root.scrollTop = height; |
| }); |
| } |
| _armSettle() { |
| this._disarmSettle(); |
| const target = this._getSettleTarget(); |
| this._settleHandler = () => this._onSettle(); |
| this._scrollIdleHandler = () => { |
| clearTimeout(this._settleTimeout); |
| this._settleTimeout = setTimeout(() => this._onSettle(), SCROLL_IDLE_TIMEOUT); |
| }; |
| EventHandler.on(target, EVENT_SCROLLEND, this._settleHandler); |
| EventHandler.on(target, EVENT_SCROLL, this._scrollIdleHandler); |
| } |
| _disarmSettle() { |
| clearTimeout(this._settleTimeout); |
| this._settleTimeout = null; |
| const target = this._getSettleTarget(); |
| if (this._settleHandler) { |
| EventHandler.off(target, EVENT_SCROLLEND, this._settleHandler); |
| this._settleHandler = null; |
| } |
| if (this._scrollIdleHandler) { |
| EventHandler.off(target, EVENT_SCROLL, this._scrollIdleHandler); |
| this._scrollIdleHandler = null; |
| } |
| } |
| _getSettleTarget() { |
| return this._rootElement || document; |
| } |
| _onSettle() { |
| this._disarmSettle(); |
| if (!this._pendingNavigation) return; |
| const { hash, section } = this._pendingNavigation; |
| this._settleNavigation(hash, section); |
| } |
| _settleNavigation(hash, section) { |
| this._pendingNavigation = null; |
| if (window.history?.replaceState) window.history.replaceState(null, "", hash); |
| if (!section.hasAttribute("tabindex")) section.setAttribute("tabindex", "-1"); |
| section.focus({ preventScroll: true }); |
| } |
| _initializeTargetsAndObservables() { |
| this._sections = []; |
| this._linkBySection = /* @__PURE__ */ new Map(); |
| this._sectionByLink = /* @__PURE__ */ new Map(); |
| const targetLinks = SelectorEngine.find(SELECTOR_TARGET_LINKS, this._config.target); |
| const seen = /* @__PURE__ */ new Set(); |
| for (const anchor of targetLinks) { |
| if (!anchor.hash || isDisabled(anchor)) continue; |
| const id = decodeFragment(anchor.hash.slice(1)); |
| if (!id) continue; |
| const section = document.getElementById(id); |
| if (!section || !this._element.contains(section) || !isVisible(section)) continue; |
| this._sectionByLink.set(anchor, section); |
| this._linkBySection.set(section, anchor); |
| if (!seen.has(section)) { |
| seen.add(section); |
| this._sections.push(section); |
| } |
| } |
| this._sections.sort((a, b) => a.getBoundingClientRect().top - b.getBoundingClientRect().top); |
| } |
| _process(target) { |
| if (this._activeTarget === target) return; |
| this._clearActiveClass(this._config.target); |
| this._activeTarget = target; |
| target.classList.add(CLASS_NAME_ACTIVE$1); |
| this._activateParents(target); |
| EventHandler.trigger(this._element, EVENT_ACTIVATE, { relatedTarget: target }); |
| } |
| _activateParents(target) { |
| if (target.classList.contains(CLASS_NAME_MENU_ITEM)) { |
| const menuToggle = target.closest(".menu")?.previousElementSibling; |
| if (menuToggle?.matches(SELECTOR_MENU_TOGGLE$1)) menuToggle.classList.add(CLASS_NAME_ACTIVE$1); |
| return; |
| } |
| for (const listGroup of SelectorEngine.parents(target, SELECTOR_NAV_LIST_GROUP)) for (const item of SelectorEngine.prev(listGroup, SELECTOR_LINK_ITEMS)) item.classList.add(CLASS_NAME_ACTIVE$1); |
| } |
| _clearActiveClass(parent) { |
| parent.classList.remove(CLASS_NAME_ACTIVE$1); |
| const activeNodes = SelectorEngine.find(`${SELECTOR_TARGET_LINKS}.${CLASS_NAME_ACTIVE$1}`, parent); |
| for (const node of activeNodes) node.classList.remove(CLASS_NAME_ACTIVE$1); |
| } |
| }; |
| function decodeFragment(hash) { |
| try { |
| return decodeURIComponent(hash); |
| } catch { |
| return hash; |
| } |
| } |
| /** |
| * Data API implementation |
| */ |
| EventHandler.on(window, EVENT_LOAD_DATA_API$1, () => { |
| for (const spy of SelectorEngine.find(SELECTOR_DATA_SPY)) ScrollSpy.getOrCreateInstance(spy); |
| }); |
| //#endregion |
| //#region js/src/tab.ts |
| /** |
| * -------------------------------------------------------------------------- |
| * Bootstrap tab.ts |
| * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) |
| * -------------------------------------------------------------------------- |
| */ |
| /** |
| * Constants |
| */ |
| const NAME$2 = "tab"; |
| const EVENT_KEY$2 = `.bs.tab`; |
| const EVENT_HIDE$1 = `hide${EVENT_KEY$2}`; |
| const EVENT_HIDDEN$1 = `hidden${EVENT_KEY$2}`; |
| const EVENT_SHOW$1 = `show${EVENT_KEY$2}`; |
| const EVENT_SHOWN$1 = `shown${EVENT_KEY$2}`; |
| const EVENT_CLICK_DATA_API = `click${EVENT_KEY$2}`; |
| const EVENT_KEYDOWN = `keydown${EVENT_KEY$2}`; |
| const EVENT_LOAD_DATA_API = `load${EVENT_KEY$2}`; |
| const ARROW_LEFT_KEY = "ArrowLeft"; |
| const ARROW_RIGHT_KEY = "ArrowRight"; |
| const ARROW_UP_KEY = "ArrowUp"; |
| const ARROW_DOWN_KEY = "ArrowDown"; |
| const HOME_KEY = "Home"; |
| const END_KEY = "End"; |
| const CLASS_NAME_ACTIVE = "active"; |
| const CLASS_NAME_SHOW$1 = "show"; |
| const SELECTOR_MENU_TOGGLE = "[data-bs-toggle=\"menu\"]"; |
| const SELECTOR_MENU = ".menu"; |
| const NOT_SELECTOR_MENU_TOGGLE = `:not(${SELECTOR_MENU_TOGGLE})`; |
| const SELECTOR_TAB_PANEL = ".list-group, .nav, [role=\"tablist\"]"; |
| const SELECTOR_OUTER = ".nav-item, .list-group-item"; |
| const SELECTOR_INNER = `.nav-link${NOT_SELECTOR_MENU_TOGGLE}, .list-group-item${NOT_SELECTOR_MENU_TOGGLE}, [role="tab"]${NOT_SELECTOR_MENU_TOGGLE}`; |
| const SELECTOR_DATA_TOGGLE$1 = "[data-bs-toggle=\"tab\"]"; |
| const SELECTOR_INNER_ELEM = `${SELECTOR_INNER}, ${SELECTOR_DATA_TOGGLE$1}`; |
| const SELECTOR_DATA_TOGGLE_ACTIVE = `.${CLASS_NAME_ACTIVE}[data-bs-toggle="tab"]`; |
| /** |
| * Class definition |
| */ |
| var Tab = class Tab extends BaseComponent { |
| constructor(element) { |
| super(element); |
| this._parent = this._element.closest(SELECTOR_TAB_PANEL); |
| if (!this._parent) throw new TypeError(`${this._element.outerHTML} has no valid parent ${SELECTOR_TAB_PANEL}`); |
| this._setInitialAttributes(this._parent, this._getChildren()); |
| EventHandler.on(this._element, EVENT_KEYDOWN, (event) => this._keydown(event)); |
| } |
| static get NAME() { |
| return NAME$2; |
| } |
| async show() { |
| const innerElem = this._element; |
| if (this._elemIsActive(innerElem)) return; |
| const active = this._getActiveElem(); |
| const hideEvent = active ? EventHandler.trigger(active, EVENT_HIDE$1, { relatedTarget: innerElem }) : null; |
| if (EventHandler.trigger(innerElem, EVENT_SHOW$1, { relatedTarget: active }).defaultPrevented || hideEvent && hideEvent.defaultPrevented) return; |
| this._deactivate(active, innerElem); |
| await this._activate(innerElem, active); |
| } |
| async _activate(element, relatedElem) { |
| if (!element) return; |
| element.classList.add(CLASS_NAME_ACTIVE); |
| if (element.getAttribute("role") !== "tab") { |
| element.classList.add(CLASS_NAME_SHOW$1); |
| return; |
| } |
| const pane = SelectorEngine.getElementFromSelector(element); |
| this._activate(pane); |
| const complete = () => { |
| element.removeAttribute("tabindex"); |
| setAriaAttribute(element, "aria-selected", true); |
| this._toggleMenu(element, true); |
| EventHandler.trigger(element, EVENT_SHOWN$1, { relatedTarget: relatedElem }); |
| }; |
| await this._queueCallback(complete, pane ?? element, getTransitionDurationFromElement(pane) > 0); |
| } |
| async _deactivate(element, relatedElem) { |
| if (!element) return; |
| element.classList.remove(CLASS_NAME_ACTIVE); |
| element.blur(); |
| if (element.getAttribute("role") !== "tab") { |
| element.classList.remove(CLASS_NAME_SHOW$1); |
| return; |
| } |
| this._deactivate(SelectorEngine.getElementFromSelector(element)); |
| const complete = () => { |
| setAriaAttribute(element, "aria-selected", false); |
| element.setAttribute("tabindex", "-1"); |
| this._toggleMenu(element, false); |
| EventHandler.trigger(element, EVENT_HIDDEN$1, { relatedTarget: relatedElem }); |
| }; |
| await this._queueCallback(complete, element, false); |
| } |
| _keydown(event) { |
| if (![ |
| ARROW_LEFT_KEY, |
| ARROW_RIGHT_KEY, |
| ARROW_UP_KEY, |
| ARROW_DOWN_KEY, |
| HOME_KEY, |
| END_KEY |
| ].includes(event.key)) return; |
| if (event.altKey || event.ctrlKey || event.metaKey) return; |
| event.stopPropagation(); |
| event.preventDefault(); |
| const children = this._getChildren().filter((element) => !isDisabled(element)); |
| let nextActiveElement; |
| if ([HOME_KEY, END_KEY].includes(event.key)) nextActiveElement = event.key === HOME_KEY ? children[0] : children.at(-1); |
| else { |
| const isNext = [ARROW_RIGHT_KEY, ARROW_DOWN_KEY].includes(event.key); |
| nextActiveElement = getNextActiveElement(children, event.target, isNext, true); |
| } |
| if (nextActiveElement) { |
| nextActiveElement.focus({ preventScroll: true }); |
| Tab.getOrCreateInstance(nextActiveElement).show(); |
| } |
| } |
| _getChildren() { |
| return SelectorEngine.find(SELECTOR_INNER_ELEM, this._parent); |
| } |
| _getActiveElem() { |
| return this._getChildren().find((child) => this._elemIsActive(child)) || null; |
| } |
| _setInitialAttributes(parent, children) { |
| this._setAttributeIfNotExists(parent, "role", "tablist"); |
| for (const child of children) this._setInitialAttributesOnChild(child); |
| } |
| _setInitialAttributesOnChild(child) { |
| child = this._getInnerElement(child); |
| const isActive = this._elemIsActive(child); |
| const outerElem = this._getOuterElement(child); |
| setAriaAttribute(child, "aria-selected", isActive); |
| if (outerElem !== child) this._setAttributeIfNotExists(outerElem, "role", "presentation"); |
| if (!isActive) child.setAttribute("tabindex", "-1"); |
| this._setAttributeIfNotExists(child, "role", "tab"); |
| this._setInitialAttributesOnTargetPanel(child); |
| } |
| _setInitialAttributesOnTargetPanel(child) { |
| const target = SelectorEngine.getElementFromSelector(child); |
| if (!target) return; |
| this._setAttributeIfNotExists(target, "role", "tabpanel"); |
| if (child.id) this._setAttributeIfNotExists(target, "aria-labelledby", `${child.id}`); |
| } |
| _toggleMenu(element, open) { |
| const outerElem = this._getOuterElement(element); |
| const menuToggle = SelectorEngine.findOne(SELECTOR_MENU_TOGGLE, outerElem); |
| if (!menuToggle) return; |
| const menu = SelectorEngine.findOne(SELECTOR_MENU, outerElem); |
| menuToggle.classList.toggle(CLASS_NAME_ACTIVE, open); |
| if (menu) menu.classList.toggle(CLASS_NAME_SHOW$1, open); |
| setAriaAttribute(menuToggle, "aria-expanded", open); |
| } |
| _setAttributeIfNotExists(element, attribute, value) { |
| if (!element.hasAttribute(attribute)) element.setAttribute(attribute, value); |
| } |
| _elemIsActive(elem) { |
| return elem.classList.contains(CLASS_NAME_ACTIVE); |
| } |
| _getInnerElement(elem) { |
| return elem.matches(SELECTOR_INNER_ELEM) ? elem : SelectorEngine.findOne(SELECTOR_INNER_ELEM, elem); |
| } |
| _getOuterElement(elem) { |
| return elem.closest(SELECTOR_OUTER) || elem; |
| } |
| }; |
| /** |
| * Data API implementation |
| */ |
| EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE$1, function(event) { |
| if (["A", "AREA"].includes(this.tagName)) event.preventDefault(); |
| if (isDisabled(this)) return; |
| Tab.getOrCreateInstance(this).show(); |
| }); |
| /** |
| * Initialize on focus |
| */ |
| EventHandler.on(window, EVENT_LOAD_DATA_API, () => { |
| for (const element of SelectorEngine.find(SELECTOR_DATA_TOGGLE_ACTIVE)) Tab.getOrCreateInstance(element); |
| }); |
| //#endregion |
| //#region js/src/toast.ts |
| /** |
| * -------------------------------------------------------------------------- |
| * Bootstrap toast.ts |
| * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) |
| * -------------------------------------------------------------------------- |
| */ |
| /** |
| * Constants |
| */ |
| const NAME$1 = "toast"; |
| const EVENT_KEY$1 = `.bs.toast`; |
| const EVENT_MOUSEOVER = `mouseover${EVENT_KEY$1}`; |
| const EVENT_MOUSEOUT = `mouseout${EVENT_KEY$1}`; |
| const EVENT_FOCUSIN = `focusin${EVENT_KEY$1}`; |
| const EVENT_FOCUSOUT = `focusout${EVENT_KEY$1}`; |
| const EVENT_HIDE = `hide${EVENT_KEY$1}`; |
| const EVENT_HIDDEN = `hidden${EVENT_KEY$1}`; |
| const EVENT_SHOW = `show${EVENT_KEY$1}`; |
| const EVENT_SHOWN = `shown${EVENT_KEY$1}`; |
| const CLASS_NAME_INSTANT = "toast-instant"; |
| const CLASS_NAME_SHOW = "show"; |
| const DefaultType$1 = { |
| autohide: "boolean", |
| delay: "number" |
| }; |
| const Default$1 = { |
| autohide: true, |
| delay: 5e3 |
| }; |
| /** |
| * Class definition |
| */ |
| var Toast = class extends BaseComponent { |
| constructor(element, config) { |
| super(element, config); |
| this._timeout = null; |
| this._hasMouseInteraction = false; |
| this._hasKeyboardInteraction = false; |
| this._setListeners(); |
| } |
| static get Default() { |
| return Default$1; |
| } |
| static get DefaultType() { |
| return DefaultType$1; |
| } |
| static get NAME() { |
| return NAME$1; |
| } |
| async show() { |
| if (EventHandler.trigger(this._element, EVENT_SHOW).defaultPrevented) return; |
| this._clearTimeout(); |
| const complete = () => { |
| EventHandler.trigger(this._element, EVENT_SHOWN); |
| this._maybeScheduleHide(); |
| }; |
| this._element.classList.add(CLASS_NAME_SHOW); |
| await this._queueCallback(complete, this._element, this._isAnimated()); |
| } |
| async hide() { |
| if (!this.isShown()) return; |
| if (EventHandler.trigger(this._element, EVENT_HIDE).defaultPrevented) return; |
| const complete = () => { |
| EventHandler.trigger(this._element, EVENT_HIDDEN); |
| }; |
| this._element.classList.remove(CLASS_NAME_SHOW); |
| await this._queueCallback(complete, this._element, this._isAnimated()); |
| } |
| dispose() { |
| this._clearTimeout(); |
| if (this.isShown()) this._element.classList.remove(CLASS_NAME_SHOW); |
| super.dispose(); |
| } |
| isShown() { |
| return this._element.classList.contains(CLASS_NAME_SHOW); |
| } |
| _isAnimated() { |
| return !this._element.classList.contains(CLASS_NAME_INSTANT); |
| } |
| _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._element === nextElement || this._element.contains(nextElement)) return; |
| this._maybeScheduleHide(); |
| } |
| _setListeners() { |
| EventHandler.on(this._element, EVENT_MOUSEOVER, (event) => this._onInteraction(event, true)); |
| EventHandler.on(this._element, EVENT_MOUSEOUT, (event) => this._onInteraction(event, false)); |
| EventHandler.on(this._element, EVENT_FOCUSIN, (event) => this._onInteraction(event, true)); |
| EventHandler.on(this._element, EVENT_FOCUSOUT, (event) => this._onInteraction(event, false)); |
| } |
| _clearTimeout() { |
| clearTimeout(this._timeout); |
| this._timeout = null; |
| } |
| }; |
| /** |
| * Data API implementation |
| */ |
| enableDismissTrigger(Toast); |
| //#endregion |
| //#region js/src/toggler.ts |
| /** |
| * -------------------------------------------------------------------------- |
| * Bootstrap toggler.ts |
| * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) |
| * -------------------------------------------------------------------------- |
| */ |
| /** |
| * Constants |
| */ |
| const NAME = "toggler"; |
| const EVENT_KEY = `.bs.toggler`; |
| const EVENT_TOGGLE = `toggle${EVENT_KEY}`; |
| const EVENT_TOGGLED = `toggled${EVENT_KEY}`; |
| const EVENT_CLICK = "click"; |
| const SELECTOR_DATA_TOGGLE = "[data-bs-toggle=\"toggler\"]"; |
| const DefaultType = { |
| attribute: "string", |
| value: "(string|number|boolean|null)" |
| }; |
| const Default = { |
| attribute: "class", |
| value: null |
| }; |
| /** |
| * Class definition |
| */ |
| var Toggler = class extends BaseComponent { |
| static get Default() { |
| return Default; |
| } |
| static get DefaultType() { |
| return DefaultType; |
| } |
| static get NAME() { |
| return NAME; |
| } |
| toggle() { |
| if (EventHandler.trigger(this._element, EVENT_TOGGLE).defaultPrevented) return; |
| this._execute(); |
| EventHandler.trigger(this._element, EVENT_TOGGLED); |
| } |
| _execute() { |
| const { attribute, value } = this._config; |
| if (attribute === "id") return; |
| if (value === null || value === void 0) return; |
| if (attribute === "class") { |
| this._element.classList.toggle(value); |
| return; |
| } |
| if (this._element.getAttribute(attribute) === String(value)) { |
| this._element.removeAttribute(attribute); |
| return; |
| } |
| this._element.setAttribute(attribute, value); |
| } |
| }; |
| /** |
| * Data API implementation |
| */ |
| eventActionOnPlugin(Toggler, EVENT_CLICK, SELECTOR_DATA_TOGGLE, "toggle"); |
| //#endregion |
| export { Alert, Button, Carousel, Chips, Collapse, Combobox, Datepicker, Dialog, Drawer, Menu, NavOverflow, OtpInput, Popover, Range, ScrollSpy, Strength, Tab, Toast, Toggler, Tooltip }; |
| |
| //# sourceMappingURL=bootstrap.js.map |