blob: 6ee61e40d2fffb0d6c58eb3df78a09087bc83e0b [file] [edit]
/*!
* Bootstrap range.js 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 BaseComponent from "./base-component.js";
import EventHandler from "./dom/event-handler.js";
import SelectorEngine from "./dom/selector-engine.js";
//#region js/src/range.ts
/**
* --------------------------------------------------------------------------
* Bootstrap range.ts
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
/**
* Constants
*/
const NAME = "range";
const EVENT_KEY = `.bs.range`;
const DATA_API_KEY = ".data-api";
const EVENT_CHANGED = `changed${EVENT_KEY}`;
const EVENT_DOM_CONTENT_LOADED = `DOMContentLoaded${EVENT_KEY}${DATA_API_KEY}`;
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 = {
bubble: false,
formatter: null
};
const DefaultType = {
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;
}
static get DefaultType() {
return DefaultType;
}
static get NAME() {
return NAME;
}
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
export { Range as default };
//# sourceMappingURL=range.js.map