b2in/public/flux/flux.js
2026-01-23 17:33:10 +01:00

13171 lines
481 KiB
JavaScript

(() => {
// node_modules/@oddbird/popover-polyfill/dist/popover.js
var ToggleEvent = class extends Event {
oldState;
newState;
constructor(type, { oldState = "", newState = "", ...init } = {}) {
super(type, init);
this.oldState = String(oldState || "");
this.newState = String(newState || "");
}
};
var popoverToggleTaskQueue = /* @__PURE__ */ new WeakMap();
function queuePopoverToggleEventTask(element2, oldState, newState) {
popoverToggleTaskQueue.set(
element2,
setTimeout(() => {
if (!popoverToggleTaskQueue.has(element2)) return;
element2.dispatchEvent(
new ToggleEvent("toggle", {
cancelable: false,
oldState,
newState
})
);
}, 0)
);
}
var ShadowRoot2 = globalThis.ShadowRoot || function() {
};
var HTMLDialogElement = globalThis.HTMLDialogElement || function() {
};
var topLayerElements = /* @__PURE__ */ new WeakMap();
var autoPopoverList = /* @__PURE__ */ new WeakMap();
var visibilityState = /* @__PURE__ */ new WeakMap();
function getPopoverVisibilityState(popover) {
return visibilityState.get(popover) || "hidden";
}
var popoverInvoker = /* @__PURE__ */ new WeakMap();
function popoverTargetAttributeActivationBehavior(element2) {
const popover = element2.popoverTargetElement;
if (!(popover instanceof HTMLElement)) {
return;
}
const visibility = getPopoverVisibilityState(popover);
if (element2.popoverTargetAction === "show" && visibility === "showing") {
return;
}
if (element2.popoverTargetAction === "hide" && visibility === "hidden") return;
if (visibility === "showing") {
hidePopover(popover, true, true);
} else if (checkPopoverValidity(popover, false)) {
popoverInvoker.set(popover, element2);
showPopover(popover);
}
}
function checkPopoverValidity(element2, expectedToBeShowing) {
if (element2.popover !== "auto" && element2.popover !== "manual") {
return false;
}
if (!element2.isConnected) return false;
if (expectedToBeShowing && getPopoverVisibilityState(element2) !== "showing") {
return false;
}
if (!expectedToBeShowing && getPopoverVisibilityState(element2) !== "hidden") {
return false;
}
if (element2 instanceof HTMLDialogElement && element2.hasAttribute("open")) {
return false;
}
if (document.fullscreenElement === element2) return false;
return true;
}
function getStackPosition(popover) {
if (!popover) return 0;
return Array.from(autoPopoverList.get(popover.ownerDocument) || []).indexOf(
popover
) + 1;
}
function topMostClickedPopover(target) {
const clickedPopover = nearestInclusiveOpenPopover(target);
const invokerPopover = nearestInclusiveTargetPopoverForInvoker(target);
if (getStackPosition(clickedPopover) > getStackPosition(invokerPopover)) {
return clickedPopover;
}
return invokerPopover;
}
function topMostAutoPopover(document2) {
const documentPopovers = autoPopoverList.get(document2);
for (const popover of documentPopovers || []) {
if (!popover.isConnected) {
documentPopovers.delete(popover);
} else {
return popover;
}
}
return null;
}
function getRootNode(node) {
if (typeof node.getRootNode === "function") {
return node.getRootNode();
}
if (node.parentNode) return getRootNode(node.parentNode);
return node;
}
function nearestInclusiveOpenPopover(node) {
while (node) {
if (node instanceof HTMLElement && node.popover === "auto" && visibilityState.get(node) === "showing") {
return node;
}
node = node instanceof Element && node.assignedSlot || node.parentElement || getRootNode(node);
if (node instanceof ShadowRoot2) node = node.host;
if (node instanceof Document) return;
}
}
function nearestInclusiveTargetPopoverForInvoker(node) {
while (node) {
const nodePopover = node.popoverTargetElement;
if (nodePopover instanceof HTMLElement) return nodePopover;
node = node.parentElement || getRootNode(node);
if (node instanceof ShadowRoot2) node = node.host;
if (node instanceof Document) return;
}
}
function topMostPopoverAncestor(newPopover) {
const popoverPositions = /* @__PURE__ */ new Map();
let i = 0;
for (const popover of autoPopoverList.get(newPopover.ownerDocument) || []) {
popoverPositions.set(popover, i);
i += 1;
}
popoverPositions.set(newPopover, i);
i += 1;
let topMostPopoverAncestor22 = null;
function checkAncestor(candidate) {
const candidateAncestor = nearestInclusiveOpenPopover(candidate);
if (candidateAncestor === null) return null;
const candidatePosition = popoverPositions.get(candidateAncestor);
if (topMostPopoverAncestor22 === null || popoverPositions.get(topMostPopoverAncestor22) < candidatePosition) {
topMostPopoverAncestor22 = candidateAncestor;
}
}
checkAncestor(newPopover.parentElement || getRootNode(newPopover));
return topMostPopoverAncestor22;
}
function isFocusable(focusTarget) {
if (focusTarget.hidden || focusTarget instanceof ShadowRoot2) return false;
if (focusTarget instanceof HTMLButtonElement || focusTarget instanceof HTMLInputElement || focusTarget instanceof HTMLSelectElement || focusTarget instanceof HTMLTextAreaElement || focusTarget instanceof HTMLOptGroupElement || focusTarget instanceof HTMLOptionElement || focusTarget instanceof HTMLFieldSetElement) {
if (focusTarget.disabled) return false;
}
if (focusTarget instanceof HTMLInputElement && focusTarget.type === "hidden") {
return false;
}
if (focusTarget instanceof HTMLAnchorElement && focusTarget.href === "") {
return false;
}
return typeof focusTarget.tabIndex === "number" && focusTarget.tabIndex !== -1;
}
function focusDelegate(focusTarget) {
if (focusTarget.shadowRoot && focusTarget.shadowRoot.delegatesFocus !== true) {
return null;
}
let whereToLook = focusTarget;
if (whereToLook.shadowRoot) {
whereToLook = whereToLook.shadowRoot;
}
let autoFocusDelegate = whereToLook.querySelector("[autofocus]");
if (autoFocusDelegate) {
return autoFocusDelegate;
} else {
const slots = whereToLook.querySelectorAll("slot");
for (const slot of slots) {
const assignedElements = slot.assignedElements({ flatten: true });
for (const el of assignedElements) {
if (el.hasAttribute("autofocus")) {
return el;
} else {
autoFocusDelegate = el.querySelector("[autofocus]");
if (autoFocusDelegate) {
return autoFocusDelegate;
}
}
}
}
}
const walker2 = focusTarget.ownerDocument.createTreeWalker(
whereToLook,
NodeFilter.SHOW_ELEMENT
);
let descendant = walker2.currentNode;
while (descendant) {
if (isFocusable(descendant)) {
return descendant;
}
descendant = walker2.nextNode();
}
}
function popoverFocusingSteps(subject) {
focusDelegate(subject)?.focus();
}
var previouslyFocusedElements = /* @__PURE__ */ new WeakMap();
function showPopover(element2) {
if (!checkPopoverValidity(element2, false)) {
return;
}
const document2 = element2.ownerDocument;
if (!element2.dispatchEvent(
new ToggleEvent("beforetoggle", {
cancelable: true,
oldState: "closed",
newState: "open"
})
)) {
return;
}
if (!checkPopoverValidity(element2, false)) {
return;
}
let shouldRestoreFocus = false;
if (element2.popover === "auto") {
const originalType = element2.getAttribute("popover");
const ancestor = topMostPopoverAncestor(element2) || document2;
hideAllPopoversUntil(ancestor, false, true);
if (originalType !== element2.getAttribute("popover") || !checkPopoverValidity(element2, false)) {
return;
}
}
if (!topMostAutoPopover(document2)) {
shouldRestoreFocus = true;
}
previouslyFocusedElements.delete(element2);
const originallyFocusedElement = document2.activeElement;
element2.classList.add(":popover-open");
visibilityState.set(element2, "showing");
if (!topLayerElements.has(document2)) {
topLayerElements.set(document2, /* @__PURE__ */ new Set());
}
topLayerElements.get(document2).add(element2);
popoverFocusingSteps(element2);
if (element2.popover === "auto") {
if (!autoPopoverList.has(document2)) {
autoPopoverList.set(document2, /* @__PURE__ */ new Set());
}
autoPopoverList.get(document2).add(element2);
setInvokerAriaExpanded(popoverInvoker.get(element2), true);
}
if (shouldRestoreFocus && originallyFocusedElement && element2.popover === "auto") {
previouslyFocusedElements.set(element2, originallyFocusedElement);
}
queuePopoverToggleEventTask(element2, "closed", "open");
}
function hidePopover(element2, focusPreviousElement = false, fireEvents = false) {
if (!checkPopoverValidity(element2, true)) {
return;
}
const document2 = element2.ownerDocument;
if (element2.popover === "auto") {
hideAllPopoversUntil(element2, focusPreviousElement, fireEvents);
if (!checkPopoverValidity(element2, true)) {
return;
}
}
setInvokerAriaExpanded(popoverInvoker.get(element2), false);
popoverInvoker.delete(element2);
if (fireEvents) {
element2.dispatchEvent(
new ToggleEvent("beforetoggle", {
oldState: "open",
newState: "closed"
})
);
if (!checkPopoverValidity(element2, true)) {
return;
}
}
topLayerElements.get(document2)?.delete(element2);
autoPopoverList.get(document2)?.delete(element2);
element2.classList.remove(":popover-open");
visibilityState.set(element2, "hidden");
if (fireEvents) {
queuePopoverToggleEventTask(element2, "open", "closed");
}
const previouslyFocusedElement = previouslyFocusedElements.get(element2);
if (previouslyFocusedElement) {
previouslyFocusedElements.delete(element2);
if (focusPreviousElement) {
previouslyFocusedElement.focus();
}
}
}
function closeAllOpenPopovers(document2, focusPreviousElement = false, fireEvents = false) {
let popover = topMostAutoPopover(document2);
while (popover) {
hidePopover(popover, focusPreviousElement, fireEvents);
popover = topMostAutoPopover(document2);
}
}
function hideAllPopoversUntil(endpoint, focusPreviousElement, fireEvents) {
const document2 = endpoint.ownerDocument || endpoint;
if (endpoint instanceof Document) {
return closeAllOpenPopovers(document2, focusPreviousElement, fireEvents);
}
let lastToHide = null;
let foundEndpoint = false;
for (const popover of autoPopoverList.get(document2) || []) {
if (popover === endpoint) {
foundEndpoint = true;
} else if (foundEndpoint) {
lastToHide = popover;
break;
}
}
if (!foundEndpoint) {
return closeAllOpenPopovers(document2, focusPreviousElement, fireEvents);
}
while (lastToHide && getPopoverVisibilityState(lastToHide) === "showing" && autoPopoverList.get(document2)?.size) {
hidePopover(lastToHide, focusPreviousElement, fireEvents);
}
}
var popoverPointerDownTargets = /* @__PURE__ */ new WeakMap();
function lightDismissOpenPopovers(event) {
if (!event.isTrusted) return;
const target = event.composedPath()[0];
if (!target) return;
const document2 = target.ownerDocument;
const topMostPopover = topMostAutoPopover(document2);
if (!topMostPopover) return;
const ancestor = topMostClickedPopover(target);
if (ancestor && event.type === "pointerdown") {
popoverPointerDownTargets.set(document2, ancestor);
} else if (event.type === "pointerup") {
const sameTarget = popoverPointerDownTargets.get(document2) === ancestor;
popoverPointerDownTargets.delete(document2);
if (sameTarget) {
hideAllPopoversUntil(ancestor || document2, false, true);
}
}
}
var initialAriaExpandedValue = /* @__PURE__ */ new WeakMap();
function setInvokerAriaExpanded(el, force = false) {
if (!el) return;
if (!initialAriaExpandedValue.has(el)) {
initialAriaExpandedValue.set(el, el.getAttribute("aria-expanded"));
}
const popover = el.popoverTargetElement;
if (popover instanceof HTMLElement && popover.popover === "auto") {
el.setAttribute("aria-expanded", String(force));
} else {
const initialValue = initialAriaExpandedValue.get(el);
if (!initialValue) {
el.removeAttribute("aria-expanded");
} else {
el.setAttribute("aria-expanded", initialValue);
}
}
}
var ShadowRoot22 = globalThis.ShadowRoot || function() {
};
function isSupported() {
return typeof HTMLElement !== "undefined" && typeof HTMLElement.prototype === "object" && "popover" in HTMLElement.prototype;
}
function patchSelectorFn(object, name, mapper) {
const original = object[name];
Object.defineProperty(object, name, {
value(selector) {
return original.call(this, mapper(selector));
}
});
}
var nonEscapedPopoverSelector = /(^|[^\\]):popover-open\b/g;
function hasLayerSupport() {
return typeof globalThis.CSSLayerBlockRule === "function";
}
function getStyles() {
const useLayer = hasLayerSupport();
return `
${useLayer ? "@layer popover-polyfill {" : ""}
:where([popover]) {
position: fixed;
z-index: 2147483647;
inset: 0;
padding: 0.25em;
width: fit-content;
height: fit-content;
border-width: initial;
border-color: initial;
border-image: initial;
border-style: solid;
background-color: canvas;
color: canvastext;
overflow: auto;
margin: auto;
}
:where([popover]:not(.\\:popover-open)) {
display: none;
}
:where(dialog[popover].\\:popover-open) {
display: block;
}
:where(dialog[popover][open]) {
display: revert;
}
:where([anchor].\\:popover-open) {
inset: auto;
}
:where([anchor]:popover-open) {
inset: auto;
}
@supports not (background-color: canvas) {
:where([popover]) {
background-color: white;
color: black;
}
}
@supports (width: -moz-fit-content) {
:where([popover]) {
width: -moz-fit-content;
height: -moz-fit-content;
}
}
@supports not (inset: 0) {
:where([popover]) {
top: 0;
left: 0;
right: 0;
bottom: 0;
}
}
${useLayer ? "}" : ""}
`;
}
var popoverStyleSheet = null;
function injectStyles(root) {
const styles = getStyles();
if (popoverStyleSheet === null) {
try {
popoverStyleSheet = new CSSStyleSheet();
popoverStyleSheet.replaceSync(styles);
} catch {
popoverStyleSheet = false;
}
}
if (popoverStyleSheet === false) {
const sheet = document.createElement("style");
sheet.textContent = styles;
if (root instanceof Document) {
root.head.prepend(sheet);
} else {
root.prepend(sheet);
}
} else {
root.adoptedStyleSheets = [popoverStyleSheet, ...root.adoptedStyleSheets];
}
}
function apply() {
if (typeof window === "undefined") return;
window.ToggleEvent = window.ToggleEvent || ToggleEvent;
function rewriteSelector(selector) {
if (selector?.includes(":popover-open")) {
selector = selector.replace(
nonEscapedPopoverSelector,
"$1.\\:popover-open"
);
}
return selector;
}
patchSelectorFn(Document.prototype, "querySelector", rewriteSelector);
patchSelectorFn(Document.prototype, "querySelectorAll", rewriteSelector);
patchSelectorFn(Element.prototype, "querySelector", rewriteSelector);
patchSelectorFn(Element.prototype, "querySelectorAll", rewriteSelector);
patchSelectorFn(Element.prototype, "matches", rewriteSelector);
patchSelectorFn(Element.prototype, "closest", rewriteSelector);
patchSelectorFn(
DocumentFragment.prototype,
"querySelectorAll",
rewriteSelector
);
Object.defineProperties(HTMLElement.prototype, {
popover: {
enumerable: true,
configurable: true,
get() {
if (!this.hasAttribute("popover")) return null;
const value3 = (this.getAttribute("popover") || "").toLowerCase();
if (value3 === "" || value3 == "auto") return "auto";
return "manual";
},
set(value3) {
if (value3 === null) {
this.removeAttribute("popover");
} else {
this.setAttribute("popover", value3);
}
}
},
showPopover: {
enumerable: true,
configurable: true,
value() {
showPopover(this);
}
},
hidePopover: {
enumerable: true,
configurable: true,
value() {
hidePopover(this, true, true);
}
},
togglePopover: {
enumerable: true,
configurable: true,
value(force) {
if (visibilityState.get(this) === "showing" && force === void 0 || force === false) {
hidePopover(this, true, true);
} else if (force === void 0 || force === true) {
showPopover(this);
}
}
}
});
const originalAttachShadow = Element.prototype.attachShadow;
if (originalAttachShadow) {
Object.defineProperties(Element.prototype, {
attachShadow: {
enumerable: true,
configurable: true,
writable: true,
value(options) {
const shadowRoot = originalAttachShadow.call(this, options);
injectStyles(shadowRoot);
return shadowRoot;
}
}
});
}
const originalAttachInternals = HTMLElement.prototype.attachInternals;
if (originalAttachInternals) {
Object.defineProperties(HTMLElement.prototype, {
attachInternals: {
enumerable: true,
configurable: true,
writable: true,
value() {
const internals = originalAttachInternals.call(this);
if (internals.shadowRoot) {
injectStyles(internals.shadowRoot);
}
return internals;
}
}
});
}
const popoverTargetAssociatedElements = /* @__PURE__ */ new WeakMap();
function applyPopoverInvokerElementMixin(ElementClass) {
Object.defineProperties(ElementClass.prototype, {
popoverTargetElement: {
enumerable: true,
configurable: true,
set(targetElement) {
if (targetElement === null) {
this.removeAttribute("popovertarget");
popoverTargetAssociatedElements.delete(this);
} else if (!(targetElement instanceof Element)) {
throw new TypeError(
`popoverTargetElement must be an element or null`
);
} else {
this.setAttribute("popovertarget", "");
popoverTargetAssociatedElements.set(this, targetElement);
}
},
get() {
if (this.localName !== "button" && this.localName !== "input") {
return null;
}
if (this.localName === "input" && this.type !== "reset" && this.type !== "image" && this.type !== "button") {
return null;
}
if (this.disabled) {
return null;
}
if (this.form && this.type === "submit") {
return null;
}
const targetElement = popoverTargetAssociatedElements.get(this);
if (targetElement && targetElement.isConnected) {
return targetElement;
} else if (targetElement && !targetElement.isConnected) {
popoverTargetAssociatedElements.delete(this);
return null;
}
const root = getRootNode(this);
const idref = this.getAttribute("popovertarget");
if ((root instanceof Document || root instanceof ShadowRoot22) && idref) {
return root.getElementById(idref) || null;
}
return null;
}
},
popoverTargetAction: {
enumerable: true,
configurable: true,
get() {
const value3 = (this.getAttribute("popovertargetaction") || "").toLowerCase();
if (value3 === "show" || value3 === "hide") return value3;
return "toggle";
},
set(value3) {
this.setAttribute("popovertargetaction", value3);
}
}
});
}
applyPopoverInvokerElementMixin(HTMLButtonElement);
applyPopoverInvokerElementMixin(HTMLInputElement);
const handleInvokerActivation = (event) => {
const composedPath = event.composedPath();
const target = composedPath[0];
if (!(target instanceof Element) || target?.shadowRoot) {
return;
}
const root = getRootNode(target);
if (!(root instanceof ShadowRoot22 || root instanceof Document)) {
return;
}
const invoker = composedPath.find(
(el) => el.matches?.("[popovertargetaction],[popovertarget]")
);
if (invoker) {
popoverTargetAttributeActivationBehavior(invoker);
event.preventDefault();
return;
}
};
const onKeydown = (event) => {
const key = event.key;
const target = event.target;
if (!event.defaultPrevented && target && (key === "Escape" || key === "Esc")) {
hideAllPopoversUntil(target.ownerDocument, true, true);
}
};
const addEventListeners = (root) => {
root.addEventListener("click", handleInvokerActivation);
root.addEventListener("keydown", onKeydown);
root.addEventListener("pointerdown", lightDismissOpenPopovers);
root.addEventListener("pointerup", lightDismissOpenPopovers);
};
addEventListeners(document);
injectStyles(document);
}
if (!isSupported()) apply();
// node_modules/@oddbird/popover-polyfill/dist/popover-fn.js
var ToggleEvent2 = class extends Event {
oldState;
newState;
constructor(type, { oldState = "", newState = "", ...init } = {}) {
super(type, init);
this.oldState = String(oldState || "");
this.newState = String(newState || "");
}
};
var popoverToggleTaskQueue2 = /* @__PURE__ */ new WeakMap();
function queuePopoverToggleEventTask2(element2, oldState, newState) {
popoverToggleTaskQueue2.set(
element2,
setTimeout(() => {
if (!popoverToggleTaskQueue2.has(element2)) return;
element2.dispatchEvent(
new ToggleEvent2("toggle", {
cancelable: false,
oldState,
newState
})
);
}, 0)
);
}
var ShadowRoot3 = globalThis.ShadowRoot || function() {
};
var HTMLDialogElement2 = globalThis.HTMLDialogElement || function() {
};
var topLayerElements2 = /* @__PURE__ */ new WeakMap();
var autoPopoverList2 = /* @__PURE__ */ new WeakMap();
var visibilityState2 = /* @__PURE__ */ new WeakMap();
function getPopoverVisibilityState2(popover) {
return visibilityState2.get(popover) || "hidden";
}
var popoverInvoker2 = /* @__PURE__ */ new WeakMap();
function popoverTargetAttributeActivationBehavior2(element2) {
const popover = element2.popoverTargetElement;
if (!(popover instanceof HTMLElement)) {
return;
}
const visibility = getPopoverVisibilityState2(popover);
if (element2.popoverTargetAction === "show" && visibility === "showing") {
return;
}
if (element2.popoverTargetAction === "hide" && visibility === "hidden") return;
if (visibility === "showing") {
hidePopover2(popover, true, true);
} else if (checkPopoverValidity2(popover, false)) {
popoverInvoker2.set(popover, element2);
showPopover2(popover);
}
}
function checkPopoverValidity2(element2, expectedToBeShowing) {
if (element2.popover !== "auto" && element2.popover !== "manual") {
return false;
}
if (!element2.isConnected) return false;
if (expectedToBeShowing && getPopoverVisibilityState2(element2) !== "showing") {
return false;
}
if (!expectedToBeShowing && getPopoverVisibilityState2(element2) !== "hidden") {
return false;
}
if (element2 instanceof HTMLDialogElement2 && element2.hasAttribute("open")) {
return false;
}
if (document.fullscreenElement === element2) return false;
return true;
}
function getStackPosition2(popover) {
if (!popover) return 0;
return Array.from(autoPopoverList2.get(popover.ownerDocument) || []).indexOf(
popover
) + 1;
}
function topMostClickedPopover2(target) {
const clickedPopover = nearestInclusiveOpenPopover2(target);
const invokerPopover = nearestInclusiveTargetPopoverForInvoker2(target);
if (getStackPosition2(clickedPopover) > getStackPosition2(invokerPopover)) {
return clickedPopover;
}
return invokerPopover;
}
function topMostAutoPopover2(document2) {
const documentPopovers = autoPopoverList2.get(document2);
for (const popover of documentPopovers || []) {
if (!popover.isConnected) {
documentPopovers.delete(popover);
} else {
return popover;
}
}
return null;
}
function getRootNode2(node) {
if (typeof node.getRootNode === "function") {
return node.getRootNode();
}
if (node.parentNode) return getRootNode2(node.parentNode);
return node;
}
function nearestInclusiveOpenPopover2(node) {
while (node) {
if (node instanceof HTMLElement && node.popover === "auto" && visibilityState2.get(node) === "showing") {
return node;
}
node = node instanceof Element && node.assignedSlot || node.parentElement || getRootNode2(node);
if (node instanceof ShadowRoot3) node = node.host;
if (node instanceof Document) return;
}
}
function nearestInclusiveTargetPopoverForInvoker2(node) {
while (node) {
const nodePopover = node.popoverTargetElement;
if (nodePopover instanceof HTMLElement) return nodePopover;
node = node.parentElement || getRootNode2(node);
if (node instanceof ShadowRoot3) node = node.host;
if (node instanceof Document) return;
}
}
function topMostPopoverAncestor2(newPopover) {
const popoverPositions = /* @__PURE__ */ new Map();
let i = 0;
for (const popover of autoPopoverList2.get(newPopover.ownerDocument) || []) {
popoverPositions.set(popover, i);
i += 1;
}
popoverPositions.set(newPopover, i);
i += 1;
let topMostPopoverAncestor22 = null;
function checkAncestor(candidate) {
const candidateAncestor = nearestInclusiveOpenPopover2(candidate);
if (candidateAncestor === null) return null;
const candidatePosition = popoverPositions.get(candidateAncestor);
if (topMostPopoverAncestor22 === null || popoverPositions.get(topMostPopoverAncestor22) < candidatePosition) {
topMostPopoverAncestor22 = candidateAncestor;
}
}
checkAncestor(newPopover.parentElement || getRootNode2(newPopover));
return topMostPopoverAncestor22;
}
function isFocusable2(focusTarget) {
if (focusTarget.hidden || focusTarget instanceof ShadowRoot3) return false;
if (focusTarget instanceof HTMLButtonElement || focusTarget instanceof HTMLInputElement || focusTarget instanceof HTMLSelectElement || focusTarget instanceof HTMLTextAreaElement || focusTarget instanceof HTMLOptGroupElement || focusTarget instanceof HTMLOptionElement || focusTarget instanceof HTMLFieldSetElement) {
if (focusTarget.disabled) return false;
}
if (focusTarget instanceof HTMLInputElement && focusTarget.type === "hidden") {
return false;
}
if (focusTarget instanceof HTMLAnchorElement && focusTarget.href === "") {
return false;
}
return typeof focusTarget.tabIndex === "number" && focusTarget.tabIndex !== -1;
}
function focusDelegate2(focusTarget) {
if (focusTarget.shadowRoot && focusTarget.shadowRoot.delegatesFocus !== true) {
return null;
}
let whereToLook = focusTarget;
if (whereToLook.shadowRoot) {
whereToLook = whereToLook.shadowRoot;
}
let autoFocusDelegate = whereToLook.querySelector("[autofocus]");
if (autoFocusDelegate) {
return autoFocusDelegate;
} else {
const slots = whereToLook.querySelectorAll("slot");
for (const slot of slots) {
const assignedElements = slot.assignedElements({ flatten: true });
for (const el of assignedElements) {
if (el.hasAttribute("autofocus")) {
return el;
} else {
autoFocusDelegate = el.querySelector("[autofocus]");
if (autoFocusDelegate) {
return autoFocusDelegate;
}
}
}
}
}
const walker2 = focusTarget.ownerDocument.createTreeWalker(
whereToLook,
NodeFilter.SHOW_ELEMENT
);
let descendant = walker2.currentNode;
while (descendant) {
if (isFocusable2(descendant)) {
return descendant;
}
descendant = walker2.nextNode();
}
}
function popoverFocusingSteps2(subject) {
focusDelegate2(subject)?.focus();
}
var previouslyFocusedElements2 = /* @__PURE__ */ new WeakMap();
function showPopover2(element2) {
if (!checkPopoverValidity2(element2, false)) {
return;
}
const document2 = element2.ownerDocument;
if (!element2.dispatchEvent(
new ToggleEvent2("beforetoggle", {
cancelable: true,
oldState: "closed",
newState: "open"
})
)) {
return;
}
if (!checkPopoverValidity2(element2, false)) {
return;
}
let shouldRestoreFocus = false;
if (element2.popover === "auto") {
const originalType = element2.getAttribute("popover");
const ancestor = topMostPopoverAncestor2(element2) || document2;
hideAllPopoversUntil2(ancestor, false, true);
if (originalType !== element2.getAttribute("popover") || !checkPopoverValidity2(element2, false)) {
return;
}
}
if (!topMostAutoPopover2(document2)) {
shouldRestoreFocus = true;
}
previouslyFocusedElements2.delete(element2);
const originallyFocusedElement = document2.activeElement;
element2.classList.add(":popover-open");
visibilityState2.set(element2, "showing");
if (!topLayerElements2.has(document2)) {
topLayerElements2.set(document2, /* @__PURE__ */ new Set());
}
topLayerElements2.get(document2).add(element2);
popoverFocusingSteps2(element2);
if (element2.popover === "auto") {
if (!autoPopoverList2.has(document2)) {
autoPopoverList2.set(document2, /* @__PURE__ */ new Set());
}
autoPopoverList2.get(document2).add(element2);
setInvokerAriaExpanded2(popoverInvoker2.get(element2), true);
}
if (shouldRestoreFocus && originallyFocusedElement && element2.popover === "auto") {
previouslyFocusedElements2.set(element2, originallyFocusedElement);
}
queuePopoverToggleEventTask2(element2, "closed", "open");
}
function hidePopover2(element2, focusPreviousElement = false, fireEvents = false) {
if (!checkPopoverValidity2(element2, true)) {
return;
}
const document2 = element2.ownerDocument;
if (element2.popover === "auto") {
hideAllPopoversUntil2(element2, focusPreviousElement, fireEvents);
if (!checkPopoverValidity2(element2, true)) {
return;
}
}
setInvokerAriaExpanded2(popoverInvoker2.get(element2), false);
popoverInvoker2.delete(element2);
if (fireEvents) {
element2.dispatchEvent(
new ToggleEvent2("beforetoggle", {
oldState: "open",
newState: "closed"
})
);
if (!checkPopoverValidity2(element2, true)) {
return;
}
}
topLayerElements2.get(document2)?.delete(element2);
autoPopoverList2.get(document2)?.delete(element2);
element2.classList.remove(":popover-open");
visibilityState2.set(element2, "hidden");
if (fireEvents) {
queuePopoverToggleEventTask2(element2, "open", "closed");
}
const previouslyFocusedElement = previouslyFocusedElements2.get(element2);
if (previouslyFocusedElement) {
previouslyFocusedElements2.delete(element2);
if (focusPreviousElement) {
previouslyFocusedElement.focus();
}
}
}
function closeAllOpenPopovers2(document2, focusPreviousElement = false, fireEvents = false) {
let popover = topMostAutoPopover2(document2);
while (popover) {
hidePopover2(popover, focusPreviousElement, fireEvents);
popover = topMostAutoPopover2(document2);
}
}
function hideAllPopoversUntil2(endpoint, focusPreviousElement, fireEvents) {
const document2 = endpoint.ownerDocument || endpoint;
if (endpoint instanceof Document) {
return closeAllOpenPopovers2(document2, focusPreviousElement, fireEvents);
}
let lastToHide = null;
let foundEndpoint = false;
for (const popover of autoPopoverList2.get(document2) || []) {
if (popover === endpoint) {
foundEndpoint = true;
} else if (foundEndpoint) {
lastToHide = popover;
break;
}
}
if (!foundEndpoint) {
return closeAllOpenPopovers2(document2, focusPreviousElement, fireEvents);
}
while (lastToHide && getPopoverVisibilityState2(lastToHide) === "showing" && autoPopoverList2.get(document2)?.size) {
hidePopover2(lastToHide, focusPreviousElement, fireEvents);
}
}
var popoverPointerDownTargets2 = /* @__PURE__ */ new WeakMap();
function lightDismissOpenPopovers2(event) {
if (!event.isTrusted) return;
const target = event.composedPath()[0];
if (!target) return;
const document2 = target.ownerDocument;
const topMostPopover = topMostAutoPopover2(document2);
if (!topMostPopover) return;
const ancestor = topMostClickedPopover2(target);
if (ancestor && event.type === "pointerdown") {
popoverPointerDownTargets2.set(document2, ancestor);
} else if (event.type === "pointerup") {
const sameTarget = popoverPointerDownTargets2.get(document2) === ancestor;
popoverPointerDownTargets2.delete(document2);
if (sameTarget) {
hideAllPopoversUntil2(ancestor || document2, false, true);
}
}
}
var initialAriaExpandedValue2 = /* @__PURE__ */ new WeakMap();
function setInvokerAriaExpanded2(el, force = false) {
if (!el) return;
if (!initialAriaExpandedValue2.has(el)) {
initialAriaExpandedValue2.set(el, el.getAttribute("aria-expanded"));
}
const popover = el.popoverTargetElement;
if (popover instanceof HTMLElement && popover.popover === "auto") {
el.setAttribute("aria-expanded", String(force));
} else {
const initialValue = initialAriaExpandedValue2.get(el);
if (!initialValue) {
el.removeAttribute("aria-expanded");
} else {
el.setAttribute("aria-expanded", initialValue);
}
}
}
var ShadowRoot23 = globalThis.ShadowRoot || function() {
};
function isSupported2() {
return typeof HTMLElement !== "undefined" && typeof HTMLElement.prototype === "object" && "popover" in HTMLElement.prototype;
}
function isPolyfilled() {
return Boolean(
document.body?.showPopover && !/native code/i.test(document.body.showPopover.toString())
);
}
function patchSelectorFn2(object, name, mapper) {
const original = object[name];
Object.defineProperty(object, name, {
value(selector) {
return original.call(this, mapper(selector));
}
});
}
var nonEscapedPopoverSelector2 = /(^|[^\\]):popover-open\b/g;
function hasLayerSupport2() {
return typeof globalThis.CSSLayerBlockRule === "function";
}
function getStyles2() {
const useLayer = hasLayerSupport2();
return `
${useLayer ? "@layer popover-polyfill {" : ""}
:where([popover]) {
position: fixed;
z-index: 2147483647;
inset: 0;
padding: 0.25em;
width: fit-content;
height: fit-content;
border-width: initial;
border-color: initial;
border-image: initial;
border-style: solid;
background-color: canvas;
color: canvastext;
overflow: auto;
margin: auto;
}
:where([popover]:not(.\\:popover-open)) {
display: none;
}
:where(dialog[popover].\\:popover-open) {
display: block;
}
:where(dialog[popover][open]) {
display: revert;
}
:where([anchor].\\:popover-open) {
inset: auto;
}
:where([anchor]:popover-open) {
inset: auto;
}
@supports not (background-color: canvas) {
:where([popover]) {
background-color: white;
color: black;
}
}
@supports (width: -moz-fit-content) {
:where([popover]) {
width: -moz-fit-content;
height: -moz-fit-content;
}
}
@supports not (inset: 0) {
:where([popover]) {
top: 0;
left: 0;
right: 0;
bottom: 0;
}
}
${useLayer ? "}" : ""}
`;
}
var popoverStyleSheet2 = null;
function injectStyles2(root) {
const styles = getStyles2();
if (popoverStyleSheet2 === null) {
try {
popoverStyleSheet2 = new CSSStyleSheet();
popoverStyleSheet2.replaceSync(styles);
} catch {
popoverStyleSheet2 = false;
}
}
if (popoverStyleSheet2 === false) {
const sheet = document.createElement("style");
sheet.textContent = styles;
if (root instanceof Document) {
root.head.prepend(sheet);
} else {
root.prepend(sheet);
}
} else {
root.adoptedStyleSheets = [popoverStyleSheet2, ...root.adoptedStyleSheets];
}
}
function apply2() {
if (typeof window === "undefined") return;
window.ToggleEvent = window.ToggleEvent || ToggleEvent2;
function rewriteSelector(selector) {
if (selector?.includes(":popover-open")) {
selector = selector.replace(
nonEscapedPopoverSelector2,
"$1.\\:popover-open"
);
}
return selector;
}
patchSelectorFn2(Document.prototype, "querySelector", rewriteSelector);
patchSelectorFn2(Document.prototype, "querySelectorAll", rewriteSelector);
patchSelectorFn2(Element.prototype, "querySelector", rewriteSelector);
patchSelectorFn2(Element.prototype, "querySelectorAll", rewriteSelector);
patchSelectorFn2(Element.prototype, "matches", rewriteSelector);
patchSelectorFn2(Element.prototype, "closest", rewriteSelector);
patchSelectorFn2(
DocumentFragment.prototype,
"querySelectorAll",
rewriteSelector
);
Object.defineProperties(HTMLElement.prototype, {
popover: {
enumerable: true,
configurable: true,
get() {
if (!this.hasAttribute("popover")) return null;
const value3 = (this.getAttribute("popover") || "").toLowerCase();
if (value3 === "" || value3 == "auto") return "auto";
return "manual";
},
set(value3) {
if (value3 === null) {
this.removeAttribute("popover");
} else {
this.setAttribute("popover", value3);
}
}
},
showPopover: {
enumerable: true,
configurable: true,
value() {
showPopover2(this);
}
},
hidePopover: {
enumerable: true,
configurable: true,
value() {
hidePopover2(this, true, true);
}
},
togglePopover: {
enumerable: true,
configurable: true,
value(force) {
if (visibilityState2.get(this) === "showing" && force === void 0 || force === false) {
hidePopover2(this, true, true);
} else if (force === void 0 || force === true) {
showPopover2(this);
}
}
}
});
const originalAttachShadow = Element.prototype.attachShadow;
if (originalAttachShadow) {
Object.defineProperties(Element.prototype, {
attachShadow: {
enumerable: true,
configurable: true,
writable: true,
value(options) {
const shadowRoot = originalAttachShadow.call(this, options);
injectStyles2(shadowRoot);
return shadowRoot;
}
}
});
}
const originalAttachInternals = HTMLElement.prototype.attachInternals;
if (originalAttachInternals) {
Object.defineProperties(HTMLElement.prototype, {
attachInternals: {
enumerable: true,
configurable: true,
writable: true,
value() {
const internals = originalAttachInternals.call(this);
if (internals.shadowRoot) {
injectStyles2(internals.shadowRoot);
}
return internals;
}
}
});
}
const popoverTargetAssociatedElements = /* @__PURE__ */ new WeakMap();
function applyPopoverInvokerElementMixin(ElementClass) {
Object.defineProperties(ElementClass.prototype, {
popoverTargetElement: {
enumerable: true,
configurable: true,
set(targetElement) {
if (targetElement === null) {
this.removeAttribute("popovertarget");
popoverTargetAssociatedElements.delete(this);
} else if (!(targetElement instanceof Element)) {
throw new TypeError(
`popoverTargetElement must be an element or null`
);
} else {
this.setAttribute("popovertarget", "");
popoverTargetAssociatedElements.set(this, targetElement);
}
},
get() {
if (this.localName !== "button" && this.localName !== "input") {
return null;
}
if (this.localName === "input" && this.type !== "reset" && this.type !== "image" && this.type !== "button") {
return null;
}
if (this.disabled) {
return null;
}
if (this.form && this.type === "submit") {
return null;
}
const targetElement = popoverTargetAssociatedElements.get(this);
if (targetElement && targetElement.isConnected) {
return targetElement;
} else if (targetElement && !targetElement.isConnected) {
popoverTargetAssociatedElements.delete(this);
return null;
}
const root = getRootNode2(this);
const idref = this.getAttribute("popovertarget");
if ((root instanceof Document || root instanceof ShadowRoot23) && idref) {
return root.getElementById(idref) || null;
}
return null;
}
},
popoverTargetAction: {
enumerable: true,
configurable: true,
get() {
const value3 = (this.getAttribute("popovertargetaction") || "").toLowerCase();
if (value3 === "show" || value3 === "hide") return value3;
return "toggle";
},
set(value3) {
this.setAttribute("popovertargetaction", value3);
}
}
});
}
applyPopoverInvokerElementMixin(HTMLButtonElement);
applyPopoverInvokerElementMixin(HTMLInputElement);
const handleInvokerActivation = (event) => {
const composedPath = event.composedPath();
const target = composedPath[0];
if (!(target instanceof Element) || target?.shadowRoot) {
return;
}
const root = getRootNode2(target);
if (!(root instanceof ShadowRoot23 || root instanceof Document)) {
return;
}
const invoker = composedPath.find(
(el) => el.matches?.("[popovertargetaction],[popovertarget]")
);
if (invoker) {
popoverTargetAttributeActivationBehavior2(invoker);
event.preventDefault();
return;
}
};
const onKeydown = (event) => {
const key = event.key;
const target = event.target;
if (!event.defaultPrevented && target && (key === "Escape" || key === "Esc")) {
hideAllPopoversUntil2(target.ownerDocument, true, true);
}
};
const addEventListeners = (root) => {
root.addEventListener("click", handleInvokerActivation);
root.addEventListener("keydown", onKeydown);
root.addEventListener("pointerdown", lightDismissOpenPopovers2);
root.addEventListener("pointerup", lightDismissOpenPopovers2);
};
addEventListeners(document);
injectStyles2(document);
}
// js/utils.js
function inject(callback) {
let styles = callback({
css: (strings, ...values) => `@layer base { ${strings.raw[0] + values.join("")} }`
});
if (document.adoptedStyleSheets === void 0) {
let styleElement = document.createElement("style");
styleElement.textContent = styles;
document.head.appendChild(styleElement);
return;
}
let sheet = new CSSStyleSheet();
sheet.replaceSync(styles);
document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];
}
function closest(el, condition) {
let current = el;
while (current) {
if (condition(current)) return current;
current = current.parentElement;
}
}
function walker(el, callback) {
let walker2 = document.createTreeWalker(
el,
NodeFilter.SHOW_ELEMENT,
callback ? {
acceptNode: (el2) => {
let skipped, rejected;
callback(el2, {
skip: () => skipped = true,
reject: () => rejected = true
});
if (skipped) return NodeFilter.FILTER_SKIP;
if (rejected) return NodeFilter.FILTER_REJECT;
return NodeFilter.FILTER_ACCEPT;
}
} : {}
);
return new Traverse(walker2);
}
var Traverse = class {
constructor(walker2) {
this.walker = walker2;
}
from(el) {
this.walker.currentNode = el;
return this;
}
first() {
return this.walker.firstChild();
}
last() {
return this.walker.lastChild();
}
next(el) {
this.walker.currentNode = el;
return this.walker.nextSibling();
}
nextOrFirst(el) {
let found = this.next(el);
if (found) return found;
this.walker.currentNode = this.walker.root;
return this.first();
}
prev(el) {
this.walker.currentNode = el;
return this.walker.previousSibling();
}
prevOrLast(el) {
let found = this.prev(el);
if (found) return found;
this.walker.currentNode = this.walker.root;
return this.last();
}
closest(el, condition) {
let walker2 = this.from(el).walker;
while (walker2.currentNode) {
if (condition(walker2.currentNode)) return walker2.currentNode;
walker2.parentNode();
}
}
contains(el) {
return this.find((i) => i === el);
}
find(callback) {
return this.walk((el, bail) => {
callback(el) && bail(el);
});
}
findOrFirst(callback) {
let found = this.find(callback);
if (!found) this.walker.currentNode = this.walker.root;
return this.first();
}
each(callback) {
this.walk((el) => callback(el));
}
some(callback) {
return !!this.find(callback);
}
every(callback) {
let every = true;
this.walk((el) => {
callback(el) || (every = false);
});
return every;
}
map(callback) {
let els = [];
this.walk((el) => els.push(callback(el)));
return els;
}
filter(callback) {
let els = [];
this.walk((el) => callback(el) && els.push(el));
return els;
}
walk(callback) {
let current;
let walker2 = this.walker;
let bailed;
while (walker2.nextNode()) {
current = walker2.currentNode;
callback(current, (bailValue) => bailed = bailValue);
if (bailed !== void 0) {
break;
}
}
return bailed;
}
};
function element(name, type) {
customElements.define(`ui-${name}`, type);
}
function on(target, event, handler, options = {}) {
target.addEventListener(event, handler, options);
return {
off: () => target.removeEventListener(event, handler),
pause: (callback) => {
target.removeEventListener(event, handler), callback();
target.addEventListener(event, handler);
}
};
}
function isFocusable3(el) {
let selectors = [
"a[href]",
"area[href]",
"input:not([disabled])",
"select:not([disabled])",
"textarea:not([disabled])",
"button:not([disabled])",
"iframe",
"object",
"embed",
"[tabindex]",
"[contenteditable]"
];
return selectors.some((selector) => el.matches(selector)) && el.tabIndex >= 0;
}
function throttle(func, limit) {
let inThrottle;
return function() {
let context = this, args = arguments;
if (!inThrottle) {
func.apply(context, args);
inThrottle = true;
setTimeout(() => inThrottle = false, limit);
}
};
}
function timeout(callback, delay) {
let timerId;
let start;
let remaining = delay;
let active = false;
let timeout2 = {
pause: () => {
if (!active) return;
clearTimeout(timerId);
remaining -= Date.now() - start;
active = false;
},
resume: () => {
if (active) return;
start = Date.now();
timerId = setTimeout(callback, remaining);
active = true;
},
cancel: () => {
clearTimeout(timerId);
active = false;
remaining = delay;
}
};
timeout2.resume();
return timeout2;
}
var using = "pointer";
document.addEventListener("keydown", () => using = "keyboard", { capture: true });
document.addEventListener("pointerdown", (e) => {
using = e.pointerType === "mouse" ? "mouse" : "touch";
}, { capture: true });
document.addEventListener("pointermove", (e) => {
using = e.pointerType === "mouse" ? "mouse" : "touch";
}, { capture: true });
function isUsingKeyboard() {
return using === "keyboard";
}
function isUsingTouch() {
return using === "touch";
}
function search(el, callback) {
let runningQuery = "";
let clearRunningQuery = debounce(() => {
runningQuery = "";
}, 300);
el.addEventListener("keydown", (e) => {
if (e.key.length === 1 && /[a-zA-Z]/.test(e.key)) {
runningQuery += e.key;
callback(runningQuery);
e.stopPropagation();
}
clearRunningQuery();
});
}
function dispenseId(el, prefix) {
return "lofi-" + (prefix ? prefix + "-" : "") + Math.random().toString(16).slice(2);
}
function assignId(el, prefix) {
let id = el.hasAttribute("id") ? el.getAttribute("id") : dispenseId(el, prefix);
setAttribute2(el, "id", id);
if (!el._x_bindings) el._x_bindings = {};
if (!el._x_bindings.id) el._x_bindings.id = id;
return id;
}
function detangle() {
let blocked = false;
return (callback) => (...args) => {
if (blocked) return;
blocked = true;
callback(...args);
blocked = false;
};
}
function interest(trigger, panel, { gain, lose, focusable, useSafeArea }) {
let engaged = false;
let focusInHander = (e) => {
if (!isUsingKeyboard()) return;
if (trigger.contains(e.target) || panel.contains(e.target)) {
engaged = true;
gain();
} else {
engaged = false;
lose();
}
};
focusable && document.addEventListener("focusin", focusInHander);
let removeFocusInHandler = () => {
document.removeEventListener("focusin", focusInHander);
};
let removeSafeArea = () => {
};
let removePointerMoveHandler = () => {
};
let disinterest = () => {
engaged = false;
lose();
removeSafeArea();
removePointerMoveHandler();
};
let clear = () => {
engaged = false;
removeSafeArea();
removePointerMoveHandler();
};
let pointerEnterHandler = (e) => {
if (isUsingTouch()) return;
if (engaged) return;
engaged = true;
gain();
setTimeout(() => {
let { safeArea, redraw: redrawSafeArea, remove: remove2 } = useSafeArea ? createSafeArea(trigger, panel, e.clientX, e.clientY) : nullSafeArea();
removeSafeArea = remove2;
let pointerStoppedOverSafeAreaTimeout;
let pointerMoveHandler = throttle((e2) => {
let panelRect = panel.getBoundingClientRect();
let triggerRect = trigger.getBoundingClientRect();
let mouseState;
if (safeArea.contains(e2.target) && mouseIsExclusivelyInsideSafeArea(triggerRect, panelRect, e2.clientX, e2.clientY)) mouseState = "safeArea";
else if (panel.contains(e2.target)) mouseState = "panel";
else if (trigger.contains(e2.target)) mouseState = "trigger";
else mouseState = "outside";
if (pointerStoppedOverSafeAreaTimeout) {
clearTimeout(pointerStoppedOverSafeAreaTimeout);
}
switch (mouseState) {
case "outside":
disinterest();
break;
case "trigger":
redrawSafeArea(e2.clientX, e2.clientY);
break;
case "panel":
removeSafeArea();
break;
case "safeArea":
redrawSafeArea(e2.clientX, e2.clientY);
pointerStoppedOverSafeAreaTimeout = setTimeout(() => {
disinterest();
}, 300);
break;
default:
break;
}
}, 100);
document.addEventListener("pointermove", pointerMoveHandler);
removePointerMoveHandler = () => document.removeEventListener("pointermove", pointerMoveHandler);
});
};
trigger.addEventListener("pointerenter", pointerEnterHandler);
let removePointerEnterHandler = () => {
trigger.removeEventListener("pointerenter", pointerEnterHandler);
};
let remove = () => {
clear();
removePointerEnterHandler();
removeFocusInHandler();
};
return { clear, remove };
}
function createSafeArea(trigger, panel, x, y) {
let safeArea = document.createElement("div");
let panelRect = panel.getBoundingClientRect();
let triggerRect = trigger.getBoundingClientRect();
safeArea.style.position = "fixed";
setAttribute2(safeArea, "data-safe-area", "");
let draw = (x2, y2) => {
if (panelRect.top === 0 && panelRect.bottom === 0) return;
let direction;
if (panelRect.left < triggerRect.left) direction = "left";
if (panelRect.right > triggerRect.right) direction = "right";
if (panelRect.top < triggerRect.top && panelRect.bottom < y2) direction = "up";
if (panelRect.bottom > triggerRect.bottom && panelRect.top > y2) direction = "down";
if (direction === void 0) direction = "right";
let left, right, width, top, bottom, height, offset3, shape;
let padding = 10;
switch (direction) {
case "left":
left = panelRect.right;
right = Math.max(panelRect.right, x2) + 5;
width = right - left;
top = Math.min(triggerRect.top, panelRect.top) - padding;
bottom = Math.max(triggerRect.bottom, panelRect.bottom) + padding;
height = bottom - top;
offset3 = y2 - top;
shape = `polygon(0% 0%, 100% ${offset3}px, 0% 100%)`;
break;
case "right":
left = Math.min(panelRect.left, x2) - 5;
right = panelRect.left;
width = right - left;
top = Math.min(triggerRect.top, panelRect.top) - padding;
bottom = Math.max(triggerRect.bottom, panelRect.bottom) + padding;
height = bottom - top;
offset3 = y2 - top;
shape = `polygon(0% ${offset3}px, 100% 0%, 100% 100%)`;
break;
case "up":
left = Math.min(x2, panelRect.left) - padding;
right = Math.max(x2, panelRect.right) + padding;
width = right - left;
top = panelRect.bottom;
bottom = Math.max(panelRect.bottom, y2) + 5;
height = bottom - top;
offset3 = x2 - left;
shape = `polygon(0% 0%, 100% 0%, ${offset3}px 100%)`;
break;
case "down":
left = Math.min(x2, panelRect.left) - padding;
right = Math.max(x2, panelRect.right) + padding;
width = right - left;
top = Math.min(panelRect.top, y2) - 5;
bottom = panelRect.top;
height = bottom - top;
offset3 = x2 - left;
shape = `polygon(${offset3}px 0%, 100% 100%, 0% 100%)`;
break;
}
safeArea.style.left = `${left}px`;
safeArea.style.top = `${top}px`;
safeArea.style.width = `${width}px`;
safeArea.style.height = `${height}px`;
safeArea.style.clipPath = shape;
};
return {
safeArea,
redraw: (x2, y2) => {
if (!safeArea.isConnected) trigger.appendChild(safeArea);
draw(x2, y2);
},
remove: () => {
safeArea.remove();
}
};
}
function mouseIsExclusivelyInsideSafeArea(triggerRect, panelRect, x, y) {
return !mouseIsOverTrigger(triggerRect, x, y) && !mouseIsOverPanel(panelRect, x, y);
}
function mouseIsOverTrigger(triggerRect, x, y) {
if (triggerRect.left <= x && x <= triggerRect.right && (triggerRect.top <= y && y <= triggerRect.bottom)) return true;
return false;
}
function mouseIsOverPanel(panelRect, x, y) {
if (panelRect.left <= x && x <= panelRect.right && (panelRect.top <= y && y <= panelRect.bottom)) return true;
return false;
}
function setAttribute2(el, name, value3) {
if (el._durableAttributeObserver === void 0) {
el._durableAttributeObserver = attributeObserver(el, [name]);
}
if (!el._durableAttributeObserver.hasAttribute(name)) {
el._durableAttributeObserver.addAttribute(name);
}
el._durableAttributeObserver.pause(() => {
el.setAttribute(name, value3);
});
}
function removeAndReleaseAttribute(el, name) {
removeAttribute(el, name);
releaseAttribute(el, name);
}
function removeAttribute(el, name) {
if (el._durableAttributeObserver === void 0) {
el._durableAttributeObserver = attributeObserver(el, [name]);
}
if (!el._durableAttributeObserver.hasAttribute(name)) {
el._durableAttributeObserver.addAttribute(name);
}
el._durableAttributeObserver.pause(() => {
el.removeAttribute(name);
});
}
function releaseAttribute(el, name) {
if (!el?._durableAttributeObserver?.hasAttribute(name)) return;
el._durableAttributeObserver.releaseAttribute(name);
}
function attributeObserver(el, initialAttributes) {
let processMutations = (mutations) => {
mutations.forEach((mutation) => {
if (mutation.oldValue === null) {
el._durableAttributeObserver.pause(() => removeAttribute(el, mutation.attributeName));
} else {
el._durableAttributeObserver.pause(() => setAttribute2(el, mutation.attributeName, mutation.oldValue));
}
});
};
let observer = new MutationObserver((mutations) => processMutations(mutations));
observer.observe(el, { attributeFilter: initialAttributes, attributeOldValue: true });
return {
attributes: initialAttributes,
hasAttribute(name) {
return this.attributes.includes(name);
},
addAttribute(name) {
this.attributes.includes(name) || this.attributes.push(name);
observer.observe(el, { attributeFilter: this.attributes, attributeOldValue: true });
},
releaseAttribute(name) {
if (!this.hasAttribute(name)) return;
observer.observe(el, { attributeFilter: this.attributes, attributeOldValue: true });
},
pause(callback) {
processMutations(observer.takeRecords());
observer.disconnect();
callback();
observer.observe(el, { attributeFilter: this.attributes, attributeOldValue: true });
}
};
}
function nullSafeArea() {
return {
safeArea: { contains: () => false },
redraw: () => {
},
remove: () => {
}
};
}
function debounce(callback, delay) {
let timeout2;
return (...args) => {
clearTimeout(timeout2);
timeout2 = setTimeout(() => {
callback(...args);
}, delay);
};
}
var lockCount = 0;
var pointerEventsLocked = false;
inject(({ css }) => css`[data-flux-allow-scroll] { pointer-events: auto; }`);
function lockScroll(el = null, allowScroll = false, except = []) {
if (allowScroll) return { lock: () => {
}, unlock: () => {
} };
let applyDocumentLockStyles = (disablePointerEvents = false) => {
undoLockStyles(document.documentElement);
let lockStyles = {
overflow: "hidden",
...disablePointerEvents ? { pointerEvents: "none" } : {}
};
if (window.CSS && CSS.supports && CSS.supports("scrollbar-gutter: stable")) {
if (document.documentElement.scrollHeight > document.documentElement.clientHeight) {
lockStyles.scrollbarGutter = "stable";
}
} else {
lockStyles.paddingRight = `calc(${window.innerWidth - document.documentElement.clientWidth}px + ${window.getComputedStyle(document.documentElement).paddingRight})`;
}
setLockStyles(document.documentElement, lockStyles);
if (disablePointerEvents) {
setAttribute2(el, "data-flux-allow-scroll", "");
except.forEach((el2) => {
setAttribute2(el2, "data-flux-allow-scroll", "");
});
pointerEventsLocked = true;
}
};
let removeDocumentLockStyles = (enablePointerEvents = false) => {
undoLockStyles(document.documentElement);
if (enablePointerEvents) {
removeAndReleaseAttribute(el, "data-flux-allow-scroll");
except.forEach((el2) => {
removeAttribute(el2, "data-flux-allow-scroll");
});
pointerEventsLocked = false;
}
};
return {
lock() {
lockCount++;
if (lockCount > 1 && el !== null && pointerEventsLocked) return;
applyDocumentLockStyles(el !== null && !pointerEventsLocked);
},
unlock() {
lockCount = Math.max(0, lockCount - 1);
if (lockCount > 0 && el !== null && !pointerEventsLocked) return;
removeDocumentLockStyles(el !== null && pointerEventsLocked);
if (lockCount > 0) {
applyDocumentLockStyles(false);
}
}
};
}
function setLockStyles(element2, styles) {
let unlockedStyles = JSON.parse(element2.getAttribute(`data-flux-scroll-unlock`) || "{}");
Object.entries(styles).forEach(([style, value3]) => {
if (unlockedStyles[style] === void 0) {
unlockedStyles[style] = element2.style[style];
element2.style[style] = value3;
}
});
element2.setAttribute(`data-flux-scroll-unlock`, JSON.stringify(unlockedStyles));
}
function undoLockStyles(element2) {
let unlockedStyles = JSON.parse(element2.getAttribute(`data-flux-scroll-unlock`) || "{}");
Object.entries(unlockedStyles).forEach(([style, value3]) => {
element2.style[style] = value3;
});
element2.removeAttribute(`data-flux-scroll-unlock`);
}
function setStyle(element2, style, value3) {
let currentValue = element2.style[style];
element2.style[style] = value3;
return () => {
element2.style[style] = currentValue;
};
}
function initFauxButton(el, isDisabled, action) {
let ifKey = (key, callback) => (e) => {
if (e.key === key && !isDisabled()) {
callback();
e.preventDefault();
e.stopPropagation();
}
};
setAttribute2(el, "role", "button");
let syncDisabledAttributes = () => {
if (el.hasAttribute("disabled")) {
setAttribute2(el, "aria-disabled", "true");
setAttribute2(el, "tabindex", "-1");
} else {
removeAttribute(el, "aria-disabled");
setAttribute2(el, "tabindex", "0");
}
};
let observer = new MutationObserver(() => syncDisabledAttributes());
observer.observe(el, { attributes: true, attributeFilter: ["disabled"] });
syncDisabledAttributes();
on(el, "click", () => action());
on(el, "keydown", ifKey("Enter", () => action()));
on(el, "keydown", ifKey(" ", () => {
}));
on(el, "keyup", ifKey(" ", () => action()));
}
function responsiveAttributeValue(el, name, fallback = null) {
let getValue = () => {
let value3 = el.getAttribute(name);
let breakpoints = {
sm: 640,
md: 768,
lg: 1024,
xl: 1280,
"2xl": 1536
};
for (let [breakpoint, minWidth] of Object.entries(breakpoints).reverse()) {
let responsiveValue = el.getAttribute(`${breakpoint}:${name}`);
if (responsiveValue && window.innerWidth >= minWidth) {
return responsiveValue;
}
}
return value3 || fallback;
};
let currentValue = getValue();
let callbacks = [];
new ResizeObserver(() => {
let newValue = getValue();
let memo = JSON.stringify(currentValue);
if (JSON.stringify(newValue) !== memo) {
currentValue = newValue;
callbacks.forEach((callback) => callback(newValue));
}
}).observe(window.document.documentElement);
return [currentValue, (callback) => callbacks.push(callback)];
}
function getLocale() {
return navigator?.language || document.documentElement.lang || "en-US";
}
function hydrateTemplate(template, slotsAndAttributes = { slots: {}, attrs: {} }) {
let { slots = {}, attrs = {} } = slotsAndAttributes;
let clone = template.content.cloneNode(true).firstElementChild;
Object.entries(slots).forEach(([key, value3]) => {
let slotNodes = key === "default" ? clone.querySelectorAll("slot:not([name])") : clone.querySelectorAll(`slot[name="${key}"]`);
slotNodes.forEach((i) => i.replaceWith(
typeof value3 === "string" ? document.createTextNode(value3) : value3
));
});
clone.querySelectorAll("slot").forEach((slot) => slot.remove());
Object.entries(attrs).forEach(([key, value3]) => {
clone.setAttribute(key, value3);
});
clone.setAttribute("data-appended", "");
return clone;
}
function isRTL() {
return document.documentElement.dir === "rtl";
}
function isSafari() {
return /^((?!chrome|android).)*safari/i.test(navigator.userAgent) && !navigator.userAgent.includes("CriOS") && !navigator.userAgent.includes("FxiOS");
}
function isIOS() {
return /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
}
var Observable = class {
constructor() {
this.subscribers = [];
}
subscribe(reason, callback) {
this.subscribers.push({ reason, callback });
}
notify(reason, data) {
this.subscribers.forEach(({ reason: subReason, callback }) => {
if (reason === subReason) {
callback(data);
}
});
}
};
// js/element.js
var UIElement = class extends HTMLElement {
wasDisconnected = false;
constructor() {
super();
this.boot?.();
}
connectedCallback() {
if (this.wasDisconnected) {
this.wasDisconnected = false;
return;
}
queueMicrotask(() => {
this.mount?.();
});
}
disconnectedCallback() {
this.wasDisconnected = true;
queueMicrotask(() => {
if (this.wasDisconnected) {
this.unmount?.();
}
this.wasDisconnected = false;
});
}
mixin(func, options = {}) {
return new func(this, options);
}
// @todo: this is redundant now...
appendMixin(func, options = {}) {
return new func(this, options);
}
use(func) {
let found;
this.mixins.forEach((mixin) => {
if (mixin instanceof func) found = mixin;
});
return found;
}
uses(func) {
let found;
this.mixins.forEach((mixin) => {
if (mixin instanceof func) found = true;
});
return !!found;
}
on(event, handler) {
return on(this, event, handler);
}
root(name, attributes = {}) {
if (name === void 0) return this.__root;
let el = document.createElement(name);
for (let name2 in attributes) {
setAttribute(el, name2, attributes[name2]);
}
let shadow = this.attachShadow({ mode: "open" });
el.appendChild(document.createElement("slot"));
shadow.appendChild(el);
this.__root = el;
return this.__root;
}
};
var UIControl = class extends UIElement {
//
};
// js/mixins/mixin.js
var Mixin = class {
constructor(el, options = {}) {
this.el = el;
this.grouped = options.grouped === void 0 ? true : false;
this.el.mixins = this.el.mixins ? this.el.mixins : /* @__PURE__ */ new Map();
this.el.mixins.set(this.constructor.name, this);
this.el[this.constructor.name] = true;
if (!this.el.use) this.el.use = UIElement.prototype.use.bind(this.el);
this.opts = options;
this.boot?.({
options: (defaults) => {
let options2 = defaults;
Object.entries(this.opts).forEach(([key, value3]) => {
if (value3 !== void 0) {
options2[key] = value3;
}
});
this.opts = options2;
}
});
queueMicrotask(() => {
this.mount?.();
});
}
options() {
return this.opts;
}
hasGroup() {
return !!this.group();
}
group() {
if (this.grouped === false) return;
return closest(this.el, (i) => i[this.groupedByType.name])?.use(this.groupedByType);
}
on(event, handler) {
return on(this.el, event, handler);
}
};
var MixinGroup = class extends Mixin {
constructor(el, options = {}) {
super(el, options);
}
walker() {
return walker(this.el, (el, { skip, reject }) => {
if (el[this.constructor.name] && el !== this.el) return reject();
if (!el[this.groupOfType.name]) return skip();
if (!el.mixins.get(this.groupOfType.name).grouped) return skip();
});
}
};
// js/mixins/controllable.js
var Controllable = class extends Mixin {
boot({ options }) {
options({
bubbles: false
});
this.initialState = this.el.value;
this.getterFunc = () => {
};
this.setterFunc = (value3) => this.initialState = value3;
Object.defineProperty(this.el, "value", {
get: () => {
return this.getterFunc();
},
set: (value3) => {
this.setterFunc(value3);
}
});
}
initial(callback) {
callback(this.initialState);
}
getter(func) {
this.getterFunc = func;
}
setter(func) {
this.setterFunc = func;
}
dispatch() {
this.el.dispatchEvent(new Event("input", {
bubbles: this.options().bubbles,
cancelable: true
}));
this.el.dispatchEvent(new Event("change", {
bubbles: this.options().bubbles,
cancelable: true
}));
}
};
// js/mixins/dialogable.js
var lastMouseDownEvent = null;
document.addEventListener("mousedown", (event) => lastMouseDownEvent = event);
var Dialogable = class extends Mixin {
boot({ options }) {
options({
clickOutside: true,
triggers: []
});
this.onChanges = [];
this.state = false;
this.stopDialogFromFocusingTheFirstElement();
let triggers = this.options().triggers;
let observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if (mutation.attributeName !== "open") return;
this.el.hasAttribute("open") ? this.state = true : this.state = false;
});
this.onChanges.forEach((i) => i());
});
observer.observe(this.el, { attributeFilter: ["open"] });
if (this.options().clickOutside) {
this.el.addEventListener("click", (e) => {
if (e.target !== this.el) {
lastMouseDownEvent = null;
return;
}
if (lastMouseDownEvent && clickHappenedOutside(this.el, lastMouseDownEvent) && clickHappenedOutside(this.el, e)) {
this.cancel();
e.preventDefault();
e.stopPropagation();
}
lastMouseDownEvent = null;
});
}
if (this.el.hasAttribute("open")) {
this.state = true;
this.hide();
this.show();
}
}
onChange(callback) {
this.onChanges.push(callback);
}
show() {
if (!this.el.isConnected) return;
this.el.showModal();
}
hide() {
this.el.close();
}
toggle() {
this.state ? this.hide() : this.show();
}
cancel() {
let event = new Event("cancel", { bubbles: false, cancelable: true });
this.el.dispatchEvent(event);
if (!event.defaultPrevented) {
this.hide();
}
}
getState() {
return this.state;
}
setState(value3) {
value3 ? this.show() : this.hide();
}
// By default, browsers focus the first focusable element inside a dialog when it is opened. This is bad for screen readers because
// the focus could potentially be at the end of the dialog skipping all of the content. This also causes issues for iOS devices
// as when inputs are focused and the keyboard is shown, hiding half of the dialog content...
stopDialogFromFocusingTheFirstElement() {
let placeholder = document.createElement("div");
placeholder.setAttribute("data-flux-focus-placeholder", "");
placeholder.setAttribute("data-appended", "");
placeholder.setAttribute("tabindex", "0");
this.el.prepend(placeholder);
this.onChange(() => {
setAttribute2(placeholder, "style", this.state ? "display: none" : "display: block");
if (this.state && isSafari() && !this.el.hasAttribute("autofocus") && this.el.querySelectorAll("[autofocus]").length === 0) {
setTimeout(() => {
this.el.setAttribute("tabindex", "-1");
this.el.focus();
this.el.blur();
});
}
});
}
};
function clickHappenedOutside(el, event) {
let rect = el.getBoundingClientRect();
let x = event.clientX;
let y = event.clientY;
let isInside = x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom;
return !isInside;
}
// js/mixins/closeable.js
var Closeable = class extends Mixin {
boot() {
this.onCloses = [];
}
onClose(callback) {
this.onCloses.push(callback);
}
close() {
this.onCloses.forEach((callback) => callback());
}
};
// js/modal.js
var UIModal = class extends UIElement {
boot() {
this.querySelectorAll("[data-appended]").forEach((el) => el.remove());
this._controllable = new Controllable(this, { disabled: this.hasAttribute("disabled") });
let button = this.button();
let dialog = this.dialog();
if (!dialog) return;
dialog._dialogable = new Dialogable(dialog, {
clickOutside: !this.hasAttribute("disable-click-outside")
});
dialog._closeable = new Closeable(dialog);
dialog._closeable.onClose(() => dialog._dialogable.hide());
this._controllable.initial((initial) => initial && dialog._dialogable.show());
this._controllable.getter(() => dialog._dialogable.getState());
let detangled = detangle();
this._controllable.setter(detangled((value3) => {
dialog._dialogable.setState(value3);
}));
dialog._dialogable.onChange(detangled(() => {
this._controllable.dispatch();
}));
let refresh = () => {
if (dialog._dialogable.getState()) {
setAttribute2(this, "data-open", "");
button?.setAttribute("data-open", "");
setAttribute2(dialog, "data-open", "");
} else {
removeAttribute(this, "data-open");
button?.removeAttribute("data-open");
removeAttribute(dialog, "data-open");
}
};
dialog._dialogable.onChange(() => refresh());
refresh();
let { lock, unlock } = lockScroll();
dialog._dialogable.onChange(() => {
dialog._dialogable.getState() ? lock() : unlock();
});
button && on(button, "click", (e) => {
dialog._dialogable.show();
});
}
unmount() {
if (this.dialog()?._dialogable?.getState()) {
let { unlock } = lockScroll();
unlock();
}
}
button() {
let button = this.querySelector("button,ui-button");
let dialog = this.dialog();
if (dialog?.contains(button)) return;
return button;
}
dialog() {
return this.querySelector("dialog");
}
showModal() {
let dialog = this.dialog();
if (!dialog) return;
dialog.showModal();
}
};
inject(({ css }) => css`dialog, ::backdrop { margin: auto; }`);
element("modal", UIModal);
// js/mixins/activatable.js
var ActivatableGroup = class extends MixinGroup {
groupOfType = Activatable;
boot({ options }) {
options({
wrap: false,
filter: false
});
this.onChanges = [];
}
onChange(callback) {
this.onChanges.push(callback);
}
activated(activeEl) {
this.onChanges.forEach((i) => i());
}
activateFirst() {
this.filterAwareWalker().first()?.use(Activatable).activate();
}
activateBySearch(query) {
let found = this.filterAwareWalker().find((i) => i.textContent.toLowerCase().trim().startsWith(query.toLowerCase()));
found?.use(Activatable).activate();
}
activateSelectedOrFirst(selectedEl) {
let isHidden = (el) => el.matches("ui-option, ui-option-create") ? getComputedStyle(el).display === "none" : false;
if (!selectedEl || isHidden(selectedEl)) {
this.filterAwareWalker().first()?.use(Activatable).activate();
return;
}
selectedEl?.use(Activatable).activate();
}
activateActiveOrFirst() {
let active = this.getActive();
if (!active) {
this.filterAwareWalker().first()?.use(Activatable).activate();
return;
}
active?.use(Activatable).activate();
}
activateActiveOrLast() {
let active = this.getActive();
if (!active) {
this.filterAwareWalker().last()?.use(Activatable).activate();
return;
}
active?.use(Activatable).activate();
}
activatePrev() {
let active = this.getActive();
if (!active) {
this.filterAwareWalker().last()?.use(Activatable).activate();
return;
}
let found;
if (this.options.wrap) {
found = this.filterAwareWalker().prevOrLast(active);
} else {
found = this.filterAwareWalker().prev(active);
}
found?.use(Activatable).activate();
}
activateNext() {
let active = this.getActive();
if (!active) {
this.filterAwareWalker().first()?.use(Activatable).activate();
return;
}
let found;
if (this.options.wrap) {
found = this.filterAwareWalker().nextOrFirst(active);
} else {
found = this.filterAwareWalker().next(active);
}
found?.use(Activatable).activate();
}
getActive() {
return this.walker().find((i) => i.use(Activatable).isActive());
}
clearActive() {
this.getActive()?.use(Activatable).deactivate();
}
filterAwareWalker() {
let isHidden = (el) => el.matches("ui-option, ui-option-create") ? getComputedStyle(el).display === "none" : false;
return walker(this.el, (el, { skip, reject }) => {
if (el[this.constructor.name] && el !== this.el) return reject();
if (!el[this.groupOfType.name]) return skip();
if (el.hasAttribute("disabled")) return reject();
if (isHidden(el)) return reject();
});
}
};
var Activatable = class _Activatable extends Mixin {
groupedByType = ActivatableGroup;
mount() {
this.el.addEventListener("mouseenter", () => {
this.activate();
});
this.el.addEventListener("mouseleave", () => {
this.deactivate();
});
}
activate(force = false) {
if (this.group()) {
this.group().walker().each((item) => item.use(_Activatable).deactivate(false));
}
if (this.el.hasAttribute("disabled") && !force) return;
setAttribute2(this.el, "data-active", "");
if (isUsingKeyboard()) {
this.el.scrollIntoView({ block: "nearest" });
}
this.group() && this.group().activated(this.el);
}
deactivate(notify = true) {
removeAttribute(this.el, "data-active");
notify && this.group() && this.group().activated(this.el);
}
isActive() {
return this.el.hasAttribute("data-active");
}
};
// js/mixins/filterable.js
var FilterableGroup = class extends MixinGroup {
groupOfType = Filterable;
boot({ options }) {
options({});
this.onChanges = [];
this.lastSearch = "";
}
onChange(callback) {
this.onChanges.push(callback);
}
filter(search2) {
if (search2 === "") {
this.walker().each((i) => {
i.use(Filterable).unfilter();
});
} else {
this.walker().each((i) => {
if (this.matches(i, search2)) {
i.use(Filterable).unfilter();
} else {
i.use(Filterable).filter();
}
});
}
if (this.lastSearch !== search2) {
this.onChanges.forEach((i) => i());
}
this.lastSearch = search2;
}
matches(el, search2) {
return this.normalize(el.textContent).includes(this.normalize(search2));
}
// This function normalizes the value to remove diacritics (accents) and convert to lowercase
// to ensure that the search is case-insensitive and diacritic-insensitive...
normalize(value3) {
return value3.normalize("NFD").replace(/\p{Diacritic}/gu, "").toLowerCase().trim();
}
hasResults() {
return this.walker().some((i) => !i.use(Filterable).isFiltered());
}
};
var Filterable = class extends Mixin {
groupedByType = FilterableGroup;
boot({ options }) {
options({ mirror: null, keep: false });
this.onChanges = [];
}
filter() {
if (this.options().keep) return;
setAttribute2(this.el, "data-hidden", "");
if (this.options().mirror) setAttribute2(this.options().mirror, "data-hidden", "");
}
unfilter() {
if (this.options().keep) return;
removeAttribute(this.el, "data-hidden");
if (this.options().mirror) removeAttribute(this.options().mirror, "data-hidden", "");
}
isFiltered() {
return this.el.hasAttribute("data-hidden");
}
};
// js/mixins/popoverable.js
var currentlyOpenPopoversByScope = /* @__PURE__ */ new Map();
var Popoverable = class extends Mixin {
boot({ options }) {
options({ triggers: [], scope: null });
let scope = this.options().scope || "global";
setAttribute2(this.el, "popover", "manual");
this.triggers = this.options().triggers;
this.onChanges = [];
this.state = false;
on(this.el, "beforetoggle", (e) => {
let oldState = this.state;
this.state = e.newState === "open";
if (this.state) {
closeOtherOpenPopovers(this.el, scope);
let controller = new AbortController();
let activeElement = document.activeElement;
let triggers = [...this.triggers, activeElement];
setTimeout(() => {
closeOnClickOutside(this.el, triggers, controller);
closeOnFocusAway(this.el, triggers, controller);
closeOnEscape(this.el, triggers, controller);
});
this.el.addEventListener("beforetoggle", (e2) => {
if (e2.newState === "closed") {
controller.abort();
activeElement?.focus();
}
}, { signal: controller.signal });
}
if (oldState !== this.state) {
this.onChanges.forEach((i) => i(this.state, oldState));
}
});
on(this.el, "toggle", (e) => {
if (e.newState === "open") {
if (!currentlyOpenPopoversByScope.has(scope)) {
currentlyOpenPopoversByScope.set(scope, /* @__PURE__ */ new Set());
}
currentlyOpenPopoversByScope.get(scope).add(this.el);
} else if (e.newState === "closed") {
if (!currentlyOpenPopoversByScope.has(scope)) return;
currentlyOpenPopoversByScope.get(scope).delete(this.el);
if (currentlyOpenPopoversByScope.get(scope).size === 0) {
currentlyOpenPopoversByScope.delete(scope);
}
}
});
}
onChange(callback) {
this.onChanges.push(callback);
}
setState(value3) {
value3 ? this.show() : this.hide();
}
getState() {
return this.state;
}
toggle() {
this.el.isConnected && this.el.togglePopover();
}
show() {
this.el.isConnected && this.el.showPopover();
}
hide() {
this.el.isConnected && this.el.hidePopover();
}
};
function closeOtherOpenPopovers(el, scope) {
if (!currentlyOpenPopoversByScope.has(scope)) return;
currentlyOpenPopoversByScope.get(scope).forEach((popoverEl) => {
if (el.contains(popoverEl) || popoverEl.contains(el)) return;
popoverEl.hidePopover();
});
}
function closeOnClickOutside(el, except, controller) {
document.addEventListener("click", (e) => {
if (el.contains(e.target) || except.includes(e.target)) return;
el.hidePopover();
}, { signal: controller.signal });
}
function closeOnFocusAway(el, except, controller) {
document.addEventListener("focusin", (e) => {
if (el.contains(e.target) || except.includes(e.target)) return;
controller.abort();
el.hidePopover();
}, {
// Without "capture: true", when you focus away from the popover onto an element that triggers a popover
// on focus (a tooltip), it will focus back this popover's trigger instead of keeping focus on the tooltip button.
// It does this because only one popover can be open at a time, so focusing the tooltip, opens a popover, closing this one,
// which will trigger the "focus back" behavior.
capture: true,
signal: controller.signal
});
}
function closeOnEscape(el, except, controller) {
document.addEventListener("keydown", (e) => {
if (e.key !== "Escape") return;
el.hidePopover();
}, { signal: controller.signal });
}
// js/mixins/disableable.js
var Disableable = class extends Mixin {
boot({ options }) {
options({
disableWithParent: true
});
this.onChanges = [];
Object.defineProperty(this.el, "disabled", {
get: () => {
return this.el.hasAttribute("disabled");
},
set: (value3) => {
if (value3) {
this.el.setAttribute("disabled", "");
} else {
this.el.removeAttribute("disabled");
}
}
});
if (this.el.hasAttribute("disabled")) {
this.el.disabled = true;
} else if (this.options().disableWithParent && this.el.parentElement?.closest("[disabled]")) {
this.el.disabled = true;
}
let observer = new MutationObserver((mutations) => {
this.onChanges.forEach((i) => i(this.el.disabled));
});
observer.observe(this.el, { attributeFilter: ["disabled"] });
}
onChange(callback) {
this.onChanges.push(callback);
}
onInitAndChange(callback) {
callback(this.el.disabled);
this.onChanges.push(callback);
}
enabled(callback) {
return (...args) => {
if (this.el.disabled) return;
return callback(...args);
};
}
disabled(callback) {
return (...args) => {
if (!this.el.disabled) return;
return callback(...args);
};
}
isDisabled() {
return this.el.disabled;
}
};
// node_modules/@floating-ui/utils/dist/floating-ui.utils.mjs
var min = Math.min;
var max = Math.max;
var round = Math.round;
var floor = Math.floor;
var createCoords = (v) => ({
x: v,
y: v
});
var oppositeSideMap = {
left: "right",
right: "left",
bottom: "top",
top: "bottom"
};
var oppositeAlignmentMap = {
start: "end",
end: "start"
};
function clamp(start, value3, end) {
return max(start, min(value3, end));
}
function evaluate(value3, param) {
return typeof value3 === "function" ? value3(param) : value3;
}
function getSide(placement) {
return placement.split("-")[0];
}
function getAlignment(placement) {
return placement.split("-")[1];
}
function getOppositeAxis(axis) {
return axis === "x" ? "y" : "x";
}
function getAxisLength(axis) {
return axis === "y" ? "height" : "width";
}
function getSideAxis(placement) {
return ["top", "bottom"].includes(getSide(placement)) ? "y" : "x";
}
function getAlignmentAxis(placement) {
return getOppositeAxis(getSideAxis(placement));
}
function getAlignmentSides(placement, rects, rtl) {
if (rtl === void 0) {
rtl = false;
}
const alignment = getAlignment(placement);
const alignmentAxis = getAlignmentAxis(placement);
const length = getAxisLength(alignmentAxis);
let mainAlignmentSide = alignmentAxis === "x" ? alignment === (rtl ? "end" : "start") ? "right" : "left" : alignment === "start" ? "bottom" : "top";
if (rects.reference[length] > rects.floating[length]) {
mainAlignmentSide = getOppositePlacement(mainAlignmentSide);
}
return [mainAlignmentSide, getOppositePlacement(mainAlignmentSide)];
}
function getExpandedPlacements(placement) {
const oppositePlacement = getOppositePlacement(placement);
return [getOppositeAlignmentPlacement(placement), oppositePlacement, getOppositeAlignmentPlacement(oppositePlacement)];
}
function getOppositeAlignmentPlacement(placement) {
return placement.replace(/start|end/g, (alignment) => oppositeAlignmentMap[alignment]);
}
function getSideList(side, isStart, rtl) {
const lr = ["left", "right"];
const rl = ["right", "left"];
const tb = ["top", "bottom"];
const bt = ["bottom", "top"];
switch (side) {
case "top":
case "bottom":
if (rtl) return isStart ? rl : lr;
return isStart ? lr : rl;
case "left":
case "right":
return isStart ? tb : bt;
default:
return [];
}
}
function getOppositeAxisPlacements(placement, flipAlignment, direction, rtl) {
const alignment = getAlignment(placement);
let list = getSideList(getSide(placement), direction === "start", rtl);
if (alignment) {
list = list.map((side) => side + "-" + alignment);
if (flipAlignment) {
list = list.concat(list.map(getOppositeAlignmentPlacement));
}
}
return list;
}
function getOppositePlacement(placement) {
return placement.replace(/left|right|bottom|top/g, (side) => oppositeSideMap[side]);
}
function expandPaddingObject(padding) {
return {
top: 0,
right: 0,
bottom: 0,
left: 0,
...padding
};
}
function getPaddingObject(padding) {
return typeof padding !== "number" ? expandPaddingObject(padding) : {
top: padding,
right: padding,
bottom: padding,
left: padding
};
}
function rectToClientRect(rect) {
const {
x,
y,
width,
height
} = rect;
return {
width,
height,
top: y,
left: x,
right: x + width,
bottom: y + height,
x,
y
};
}
// node_modules/@floating-ui/core/dist/floating-ui.core.mjs
function computeCoordsFromPlacement(_ref, placement, rtl) {
let {
reference,
floating
} = _ref;
const sideAxis = getSideAxis(placement);
const alignmentAxis = getAlignmentAxis(placement);
const alignLength = getAxisLength(alignmentAxis);
const side = getSide(placement);
const isVertical = sideAxis === "y";
const commonX = reference.x + reference.width / 2 - floating.width / 2;
const commonY = reference.y + reference.height / 2 - floating.height / 2;
const commonAlign = reference[alignLength] / 2 - floating[alignLength] / 2;
let coords;
switch (side) {
case "top":
coords = {
x: commonX,
y: reference.y - floating.height
};
break;
case "bottom":
coords = {
x: commonX,
y: reference.y + reference.height
};
break;
case "right":
coords = {
x: reference.x + reference.width,
y: commonY
};
break;
case "left":
coords = {
x: reference.x - floating.width,
y: commonY
};
break;
default:
coords = {
x: reference.x,
y: reference.y
};
}
switch (getAlignment(placement)) {
case "start":
coords[alignmentAxis] -= commonAlign * (rtl && isVertical ? -1 : 1);
break;
case "end":
coords[alignmentAxis] += commonAlign * (rtl && isVertical ? -1 : 1);
break;
}
return coords;
}
var computePosition = async (reference, floating, config) => {
const {
placement = "bottom",
strategy = "absolute",
middleware = [],
platform: platform2
} = config;
const validMiddleware = middleware.filter(Boolean);
const rtl = await (platform2.isRTL == null ? void 0 : platform2.isRTL(floating));
let rects = await platform2.getElementRects({
reference,
floating,
strategy
});
let {
x,
y
} = computeCoordsFromPlacement(rects, placement, rtl);
let statefulPlacement = placement;
let middlewareData = {};
let resetCount = 0;
for (let i = 0; i < validMiddleware.length; i++) {
const {
name,
fn
} = validMiddleware[i];
const {
x: nextX,
y: nextY,
data,
reset
} = await fn({
x,
y,
initialPlacement: placement,
placement: statefulPlacement,
strategy,
middlewareData,
rects,
platform: platform2,
elements: {
reference,
floating
}
});
x = nextX != null ? nextX : x;
y = nextY != null ? nextY : y;
middlewareData = {
...middlewareData,
[name]: {
...middlewareData[name],
...data
}
};
if (reset && resetCount <= 50) {
resetCount++;
if (typeof reset === "object") {
if (reset.placement) {
statefulPlacement = reset.placement;
}
if (reset.rects) {
rects = reset.rects === true ? await platform2.getElementRects({
reference,
floating,
strategy
}) : reset.rects;
}
({
x,
y
} = computeCoordsFromPlacement(rects, statefulPlacement, rtl));
}
i = -1;
}
}
return {
x,
y,
placement: statefulPlacement,
strategy,
middlewareData
};
};
async function detectOverflow(state, options) {
var _await$platform$isEle;
if (options === void 0) {
options = {};
}
const {
x,
y,
platform: platform2,
rects,
elements,
strategy
} = state;
const {
boundary = "clippingAncestors",
rootBoundary = "viewport",
elementContext = "floating",
altBoundary = false,
padding = 0
} = evaluate(options, state);
const paddingObject = getPaddingObject(padding);
const altContext = elementContext === "floating" ? "reference" : "floating";
const element2 = elements[altBoundary ? altContext : elementContext];
const clippingClientRect = rectToClientRect(await platform2.getClippingRect({
element: ((_await$platform$isEle = await (platform2.isElement == null ? void 0 : platform2.isElement(element2))) != null ? _await$platform$isEle : true) ? element2 : element2.contextElement || await (platform2.getDocumentElement == null ? void 0 : platform2.getDocumentElement(elements.floating)),
boundary,
rootBoundary,
strategy
}));
const rect = elementContext === "floating" ? {
x,
y,
width: rects.floating.width,
height: rects.floating.height
} : rects.reference;
const offsetParent = await (platform2.getOffsetParent == null ? void 0 : platform2.getOffsetParent(elements.floating));
const offsetScale = await (platform2.isElement == null ? void 0 : platform2.isElement(offsetParent)) ? await (platform2.getScale == null ? void 0 : platform2.getScale(offsetParent)) || {
x: 1,
y: 1
} : {
x: 1,
y: 1
};
const elementClientRect = rectToClientRect(platform2.convertOffsetParentRelativeRectToViewportRelativeRect ? await platform2.convertOffsetParentRelativeRectToViewportRelativeRect({
elements,
rect,
offsetParent,
strategy
}) : rect);
return {
top: (clippingClientRect.top - elementClientRect.top + paddingObject.top) / offsetScale.y,
bottom: (elementClientRect.bottom - clippingClientRect.bottom + paddingObject.bottom) / offsetScale.y,
left: (clippingClientRect.left - elementClientRect.left + paddingObject.left) / offsetScale.x,
right: (elementClientRect.right - clippingClientRect.right + paddingObject.right) / offsetScale.x
};
}
var flip = function(options) {
if (options === void 0) {
options = {};
}
return {
name: "flip",
options,
async fn(state) {
var _middlewareData$arrow, _middlewareData$flip;
const {
placement,
middlewareData,
rects,
initialPlacement,
platform: platform2,
elements
} = state;
const {
mainAxis: checkMainAxis = true,
crossAxis: checkCrossAxis = true,
fallbackPlacements: specifiedFallbackPlacements,
fallbackStrategy = "bestFit",
fallbackAxisSideDirection = "none",
flipAlignment = true,
...detectOverflowOptions
} = evaluate(options, state);
if ((_middlewareData$arrow = middlewareData.arrow) != null && _middlewareData$arrow.alignmentOffset) {
return {};
}
const side = getSide(placement);
const initialSideAxis = getSideAxis(initialPlacement);
const isBasePlacement = getSide(initialPlacement) === initialPlacement;
const rtl = await (platform2.isRTL == null ? void 0 : platform2.isRTL(elements.floating));
const fallbackPlacements = specifiedFallbackPlacements || (isBasePlacement || !flipAlignment ? [getOppositePlacement(initialPlacement)] : getExpandedPlacements(initialPlacement));
const hasFallbackAxisSideDirection = fallbackAxisSideDirection !== "none";
if (!specifiedFallbackPlacements && hasFallbackAxisSideDirection) {
fallbackPlacements.push(...getOppositeAxisPlacements(initialPlacement, flipAlignment, fallbackAxisSideDirection, rtl));
}
const placements2 = [initialPlacement, ...fallbackPlacements];
const overflow = await detectOverflow(state, detectOverflowOptions);
const overflows = [];
let overflowsData = ((_middlewareData$flip = middlewareData.flip) == null ? void 0 : _middlewareData$flip.overflows) || [];
if (checkMainAxis) {
overflows.push(overflow[side]);
}
if (checkCrossAxis) {
const sides2 = getAlignmentSides(placement, rects, rtl);
overflows.push(overflow[sides2[0]], overflow[sides2[1]]);
}
overflowsData = [...overflowsData, {
placement,
overflows
}];
if (!overflows.every((side2) => side2 <= 0)) {
var _middlewareData$flip2, _overflowsData$filter;
const nextIndex = (((_middlewareData$flip2 = middlewareData.flip) == null ? void 0 : _middlewareData$flip2.index) || 0) + 1;
const nextPlacement = placements2[nextIndex];
if (nextPlacement) {
return {
data: {
index: nextIndex,
overflows: overflowsData
},
reset: {
placement: nextPlacement
}
};
}
let resetPlacement = (_overflowsData$filter = overflowsData.filter((d) => d.overflows[0] <= 0).sort((a, b) => a.overflows[1] - b.overflows[1])[0]) == null ? void 0 : _overflowsData$filter.placement;
if (!resetPlacement) {
switch (fallbackStrategy) {
case "bestFit": {
var _overflowsData$filter2;
const placement2 = (_overflowsData$filter2 = overflowsData.filter((d) => {
if (hasFallbackAxisSideDirection) {
const currentSideAxis = getSideAxis(d.placement);
return currentSideAxis === initialSideAxis || // Create a bias to the `y` side axis due to horizontal
// reading directions favoring greater width.
currentSideAxis === "y";
}
return true;
}).map((d) => [d.placement, d.overflows.filter((overflow2) => overflow2 > 0).reduce((acc, overflow2) => acc + overflow2, 0)]).sort((a, b) => a[1] - b[1])[0]) == null ? void 0 : _overflowsData$filter2[0];
if (placement2) {
resetPlacement = placement2;
}
break;
}
case "initialPlacement":
resetPlacement = initialPlacement;
break;
}
}
if (placement !== resetPlacement) {
return {
reset: {
placement: resetPlacement
}
};
}
}
return {};
}
};
};
async function convertValueToCoords(state, options) {
const {
placement,
platform: platform2,
elements
} = state;
const rtl = await (platform2.isRTL == null ? void 0 : platform2.isRTL(elements.floating));
const side = getSide(placement);
const alignment = getAlignment(placement);
const isVertical = getSideAxis(placement) === "y";
const mainAxisMulti = ["left", "top"].includes(side) ? -1 : 1;
const crossAxisMulti = rtl && isVertical ? -1 : 1;
const rawValue = evaluate(options, state);
let {
mainAxis,
crossAxis,
alignmentAxis
} = typeof rawValue === "number" ? {
mainAxis: rawValue,
crossAxis: 0,
alignmentAxis: null
} : {
mainAxis: rawValue.mainAxis || 0,
crossAxis: rawValue.crossAxis || 0,
alignmentAxis: rawValue.alignmentAxis
};
if (alignment && typeof alignmentAxis === "number") {
crossAxis = alignment === "end" ? alignmentAxis * -1 : alignmentAxis;
}
return isVertical ? {
x: crossAxis * crossAxisMulti,
y: mainAxis * mainAxisMulti
} : {
x: mainAxis * mainAxisMulti,
y: crossAxis * crossAxisMulti
};
}
var offset = function(options) {
if (options === void 0) {
options = 0;
}
return {
name: "offset",
options,
async fn(state) {
var _middlewareData$offse, _middlewareData$arrow;
const {
x,
y,
placement,
middlewareData
} = state;
const diffCoords = await convertValueToCoords(state, options);
if (placement === ((_middlewareData$offse = middlewareData.offset) == null ? void 0 : _middlewareData$offse.placement) && (_middlewareData$arrow = middlewareData.arrow) != null && _middlewareData$arrow.alignmentOffset) {
return {};
}
return {
x: x + diffCoords.x,
y: y + diffCoords.y,
data: {
...diffCoords,
placement
}
};
}
};
};
var shift = function(options) {
if (options === void 0) {
options = {};
}
return {
name: "shift",
options,
async fn(state) {
const {
x,
y,
placement
} = state;
const {
mainAxis: checkMainAxis = true,
crossAxis: checkCrossAxis = false,
limiter = {
fn: (_ref) => {
let {
x: x2,
y: y2
} = _ref;
return {
x: x2,
y: y2
};
}
},
...detectOverflowOptions
} = evaluate(options, state);
const coords = {
x,
y
};
const overflow = await detectOverflow(state, detectOverflowOptions);
const crossAxis = getSideAxis(getSide(placement));
const mainAxis = getOppositeAxis(crossAxis);
let mainAxisCoord = coords[mainAxis];
let crossAxisCoord = coords[crossAxis];
if (checkMainAxis) {
const minSide = mainAxis === "y" ? "top" : "left";
const maxSide = mainAxis === "y" ? "bottom" : "right";
const min2 = mainAxisCoord + overflow[minSide];
const max2 = mainAxisCoord - overflow[maxSide];
mainAxisCoord = clamp(min2, mainAxisCoord, max2);
}
if (checkCrossAxis) {
const minSide = crossAxis === "y" ? "top" : "left";
const maxSide = crossAxis === "y" ? "bottom" : "right";
const min2 = crossAxisCoord + overflow[minSide];
const max2 = crossAxisCoord - overflow[maxSide];
crossAxisCoord = clamp(min2, crossAxisCoord, max2);
}
const limitedCoords = limiter.fn({
...state,
[mainAxis]: mainAxisCoord,
[crossAxis]: crossAxisCoord
});
return {
...limitedCoords,
data: {
x: limitedCoords.x - x,
y: limitedCoords.y - y,
enabled: {
[mainAxis]: checkMainAxis,
[crossAxis]: checkCrossAxis
}
}
};
}
};
};
var size = function(options) {
if (options === void 0) {
options = {};
}
return {
name: "size",
options,
async fn(state) {
var _state$middlewareData, _state$middlewareData2;
const {
placement,
rects,
platform: platform2,
elements
} = state;
const {
apply: apply3 = () => {
},
...detectOverflowOptions
} = evaluate(options, state);
const overflow = await detectOverflow(state, detectOverflowOptions);
const side = getSide(placement);
const alignment = getAlignment(placement);
const isYAxis = getSideAxis(placement) === "y";
const {
width,
height
} = rects.floating;
let heightSide;
let widthSide;
if (side === "top" || side === "bottom") {
heightSide = side;
widthSide = alignment === (await (platform2.isRTL == null ? void 0 : platform2.isRTL(elements.floating)) ? "start" : "end") ? "left" : "right";
} else {
widthSide = side;
heightSide = alignment === "end" ? "top" : "bottom";
}
const maximumClippingHeight = height - overflow.top - overflow.bottom;
const maximumClippingWidth = width - overflow.left - overflow.right;
const overflowAvailableHeight = min(height - overflow[heightSide], maximumClippingHeight);
const overflowAvailableWidth = min(width - overflow[widthSide], maximumClippingWidth);
const noShift = !state.middlewareData.shift;
let availableHeight = overflowAvailableHeight;
let availableWidth = overflowAvailableWidth;
if ((_state$middlewareData = state.middlewareData.shift) != null && _state$middlewareData.enabled.x) {
availableWidth = maximumClippingWidth;
}
if ((_state$middlewareData2 = state.middlewareData.shift) != null && _state$middlewareData2.enabled.y) {
availableHeight = maximumClippingHeight;
}
if (noShift && !alignment) {
const xMin = max(overflow.left, 0);
const xMax = max(overflow.right, 0);
const yMin = max(overflow.top, 0);
const yMax = max(overflow.bottom, 0);
if (isYAxis) {
availableWidth = width - 2 * (xMin !== 0 || xMax !== 0 ? xMin + xMax : max(overflow.left, overflow.right));
} else {
availableHeight = height - 2 * (yMin !== 0 || yMax !== 0 ? yMin + yMax : max(overflow.top, overflow.bottom));
}
}
await apply3({
...state,
availableWidth,
availableHeight
});
const nextDimensions = await platform2.getDimensions(elements.floating);
if (width !== nextDimensions.width || height !== nextDimensions.height) {
return {
reset: {
rects: true
}
};
}
return {};
}
};
};
// node_modules/@floating-ui/utils/dist/floating-ui.utils.dom.mjs
function hasWindow() {
return typeof window !== "undefined";
}
function getNodeName(node) {
if (isNode(node)) {
return (node.nodeName || "").toLowerCase();
}
return "#document";
}
function getWindow(node) {
var _node$ownerDocument;
return (node == null || (_node$ownerDocument = node.ownerDocument) == null ? void 0 : _node$ownerDocument.defaultView) || window;
}
function getDocumentElement(node) {
var _ref;
return (_ref = (isNode(node) ? node.ownerDocument : node.document) || window.document) == null ? void 0 : _ref.documentElement;
}
function isNode(value3) {
if (!hasWindow()) {
return false;
}
return value3 instanceof Node || value3 instanceof getWindow(value3).Node;
}
function isElement(value3) {
if (!hasWindow()) {
return false;
}
return value3 instanceof Element || value3 instanceof getWindow(value3).Element;
}
function isHTMLElement(value3) {
if (!hasWindow()) {
return false;
}
return value3 instanceof HTMLElement || value3 instanceof getWindow(value3).HTMLElement;
}
function isShadowRoot(value3) {
if (!hasWindow() || typeof ShadowRoot === "undefined") {
return false;
}
return value3 instanceof ShadowRoot || value3 instanceof getWindow(value3).ShadowRoot;
}
function isOverflowElement(element2) {
const {
overflow,
overflowX,
overflowY,
display
} = getComputedStyle2(element2);
return /auto|scroll|overlay|hidden|clip/.test(overflow + overflowY + overflowX) && !["inline", "contents"].includes(display);
}
function isTableElement(element2) {
return ["table", "td", "th"].includes(getNodeName(element2));
}
function isTopLayer(element2) {
return [":popover-open", ":modal"].some((selector) => {
try {
return element2.matches(selector);
} catch (e) {
return false;
}
});
}
function isContainingBlock(elementOrCss) {
const webkit = isWebKit();
const css = isElement(elementOrCss) ? getComputedStyle2(elementOrCss) : elementOrCss;
return ["transform", "translate", "scale", "rotate", "perspective"].some((value3) => css[value3] ? css[value3] !== "none" : false) || (css.containerType ? css.containerType !== "normal" : false) || !webkit && (css.backdropFilter ? css.backdropFilter !== "none" : false) || !webkit && (css.filter ? css.filter !== "none" : false) || ["transform", "translate", "scale", "rotate", "perspective", "filter"].some((value3) => (css.willChange || "").includes(value3)) || ["paint", "layout", "strict", "content"].some((value3) => (css.contain || "").includes(value3));
}
function getContainingBlock(element2) {
let currentNode = getParentNode(element2);
while (isHTMLElement(currentNode) && !isLastTraversableNode(currentNode)) {
if (isContainingBlock(currentNode)) {
return currentNode;
} else if (isTopLayer(currentNode)) {
return null;
}
currentNode = getParentNode(currentNode);
}
return null;
}
function isWebKit() {
if (typeof CSS === "undefined" || !CSS.supports) return false;
return CSS.supports("-webkit-backdrop-filter", "none");
}
function isLastTraversableNode(node) {
return ["html", "body", "#document"].includes(getNodeName(node));
}
function getComputedStyle2(element2) {
return getWindow(element2).getComputedStyle(element2);
}
function getNodeScroll(element2) {
if (isElement(element2)) {
return {
scrollLeft: element2.scrollLeft,
scrollTop: element2.scrollTop
};
}
return {
scrollLeft: element2.scrollX,
scrollTop: element2.scrollY
};
}
function getParentNode(node) {
if (getNodeName(node) === "html") {
return node;
}
const result = (
// Step into the shadow DOM of the parent of a slotted node.
node.assignedSlot || // DOM Element detected.
node.parentNode || // ShadowRoot detected.
isShadowRoot(node) && node.host || // Fallback.
getDocumentElement(node)
);
return isShadowRoot(result) ? result.host : result;
}
function getNearestOverflowAncestor(node) {
const parentNode = getParentNode(node);
if (isLastTraversableNode(parentNode)) {
return node.ownerDocument ? node.ownerDocument.body : node.body;
}
if (isHTMLElement(parentNode) && isOverflowElement(parentNode)) {
return parentNode;
}
return getNearestOverflowAncestor(parentNode);
}
function getOverflowAncestors(node, list, traverseIframes) {
var _node$ownerDocument2;
if (list === void 0) {
list = [];
}
if (traverseIframes === void 0) {
traverseIframes = true;
}
const scrollableAncestor = getNearestOverflowAncestor(node);
const isBody = scrollableAncestor === ((_node$ownerDocument2 = node.ownerDocument) == null ? void 0 : _node$ownerDocument2.body);
const win = getWindow(scrollableAncestor);
if (isBody) {
const frameElement = getFrameElement(win);
return list.concat(win, win.visualViewport || [], isOverflowElement(scrollableAncestor) ? scrollableAncestor : [], frameElement && traverseIframes ? getOverflowAncestors(frameElement) : []);
}
return list.concat(scrollableAncestor, getOverflowAncestors(scrollableAncestor, [], traverseIframes));
}
function getFrameElement(win) {
return win.parent && Object.getPrototypeOf(win.parent) ? win.frameElement : null;
}
// node_modules/@floating-ui/dom/dist/floating-ui.dom.mjs
function getCssDimensions(element2) {
const css = getComputedStyle2(element2);
let width = parseFloat(css.width) || 0;
let height = parseFloat(css.height) || 0;
const hasOffset = isHTMLElement(element2);
const offsetWidth = hasOffset ? element2.offsetWidth : width;
const offsetHeight = hasOffset ? element2.offsetHeight : height;
const shouldFallback = round(width) !== offsetWidth || round(height) !== offsetHeight;
if (shouldFallback) {
width = offsetWidth;
height = offsetHeight;
}
return {
width,
height,
$: shouldFallback
};
}
function unwrapElement(element2) {
return !isElement(element2) ? element2.contextElement : element2;
}
function getScale(element2) {
const domElement = unwrapElement(element2);
if (!isHTMLElement(domElement)) {
return createCoords(1);
}
const rect = domElement.getBoundingClientRect();
const {
width,
height,
$
} = getCssDimensions(domElement);
let x = ($ ? round(rect.width) : rect.width) / width;
let y = ($ ? round(rect.height) : rect.height) / height;
if (!x || !Number.isFinite(x)) {
x = 1;
}
if (!y || !Number.isFinite(y)) {
y = 1;
}
return {
x,
y
};
}
var noOffsets = /* @__PURE__ */ createCoords(0);
function getVisualOffsets(element2) {
const win = getWindow(element2);
if (!isWebKit() || !win.visualViewport) {
return noOffsets;
}
return {
x: win.visualViewport.offsetLeft,
y: win.visualViewport.offsetTop
};
}
function shouldAddVisualOffsets(element2, isFixed, floatingOffsetParent) {
if (isFixed === void 0) {
isFixed = false;
}
if (!floatingOffsetParent || isFixed && floatingOffsetParent !== getWindow(element2)) {
return false;
}
return isFixed;
}
function getBoundingClientRect(element2, includeScale, isFixedStrategy, offsetParent) {
if (includeScale === void 0) {
includeScale = false;
}
if (isFixedStrategy === void 0) {
isFixedStrategy = false;
}
const clientRect = element2.getBoundingClientRect();
const domElement = unwrapElement(element2);
let scale = createCoords(1);
if (includeScale) {
if (offsetParent) {
if (isElement(offsetParent)) {
scale = getScale(offsetParent);
}
} else {
scale = getScale(element2);
}
}
const visualOffsets = shouldAddVisualOffsets(domElement, isFixedStrategy, offsetParent) ? getVisualOffsets(domElement) : createCoords(0);
let x = (clientRect.left + visualOffsets.x) / scale.x;
let y = (clientRect.top + visualOffsets.y) / scale.y;
let width = clientRect.width / scale.x;
let height = clientRect.height / scale.y;
if (domElement) {
const win = getWindow(domElement);
const offsetWin = offsetParent && isElement(offsetParent) ? getWindow(offsetParent) : offsetParent;
let currentWin = win;
let currentIFrame = getFrameElement(currentWin);
while (currentIFrame && offsetParent && offsetWin !== currentWin) {
const iframeScale = getScale(currentIFrame);
const iframeRect = currentIFrame.getBoundingClientRect();
const css = getComputedStyle2(currentIFrame);
const left = iframeRect.left + (currentIFrame.clientLeft + parseFloat(css.paddingLeft)) * iframeScale.x;
const top = iframeRect.top + (currentIFrame.clientTop + parseFloat(css.paddingTop)) * iframeScale.y;
x *= iframeScale.x;
y *= iframeScale.y;
width *= iframeScale.x;
height *= iframeScale.y;
x += left;
y += top;
currentWin = getWindow(currentIFrame);
currentIFrame = getFrameElement(currentWin);
}
}
return rectToClientRect({
width,
height,
x,
y
});
}
function getWindowScrollBarX(element2, rect) {
const leftScroll = getNodeScroll(element2).scrollLeft;
if (!rect) {
return getBoundingClientRect(getDocumentElement(element2)).left + leftScroll;
}
return rect.left + leftScroll;
}
function getHTMLOffset(documentElement, scroll, ignoreScrollbarX) {
if (ignoreScrollbarX === void 0) {
ignoreScrollbarX = false;
}
const htmlRect = documentElement.getBoundingClientRect();
const x = htmlRect.left + scroll.scrollLeft - (ignoreScrollbarX ? 0 : (
// RTL <body> scrollbar.
getWindowScrollBarX(documentElement, htmlRect)
));
const y = htmlRect.top + scroll.scrollTop;
return {
x,
y
};
}
function convertOffsetParentRelativeRectToViewportRelativeRect(_ref) {
let {
elements,
rect,
offsetParent,
strategy
} = _ref;
const isFixed = strategy === "fixed";
const documentElement = getDocumentElement(offsetParent);
const topLayer = elements ? isTopLayer(elements.floating) : false;
if (offsetParent === documentElement || topLayer && isFixed) {
return rect;
}
let scroll = {
scrollLeft: 0,
scrollTop: 0
};
let scale = createCoords(1);
const offsets = createCoords(0);
const isOffsetParentAnElement = isHTMLElement(offsetParent);
if (isOffsetParentAnElement || !isOffsetParentAnElement && !isFixed) {
if (getNodeName(offsetParent) !== "body" || isOverflowElement(documentElement)) {
scroll = getNodeScroll(offsetParent);
}
if (isHTMLElement(offsetParent)) {
const offsetRect = getBoundingClientRect(offsetParent);
scale = getScale(offsetParent);
offsets.x = offsetRect.x + offsetParent.clientLeft;
offsets.y = offsetRect.y + offsetParent.clientTop;
}
}
const htmlOffset = documentElement && !isOffsetParentAnElement && !isFixed ? getHTMLOffset(documentElement, scroll, true) : createCoords(0);
return {
width: rect.width * scale.x,
height: rect.height * scale.y,
x: rect.x * scale.x - scroll.scrollLeft * scale.x + offsets.x + htmlOffset.x,
y: rect.y * scale.y - scroll.scrollTop * scale.y + offsets.y + htmlOffset.y
};
}
function getClientRects(element2) {
return Array.from(element2.getClientRects());
}
function getDocumentRect(element2) {
const html = getDocumentElement(element2);
const scroll = getNodeScroll(element2);
const body = element2.ownerDocument.body;
const width = max(html.scrollWidth, html.clientWidth, body.scrollWidth, body.clientWidth);
const height = max(html.scrollHeight, html.clientHeight, body.scrollHeight, body.clientHeight);
let x = -scroll.scrollLeft + getWindowScrollBarX(element2);
const y = -scroll.scrollTop;
if (getComputedStyle2(body).direction === "rtl") {
x += max(html.clientWidth, body.clientWidth) - width;
}
return {
width,
height,
x,
y
};
}
function getViewportRect(element2, strategy) {
const win = getWindow(element2);
const html = getDocumentElement(element2);
const visualViewport = win.visualViewport;
let width = html.clientWidth;
let height = html.clientHeight;
let x = 0;
let y = 0;
if (visualViewport) {
width = visualViewport.width;
height = visualViewport.height;
const visualViewportBased = isWebKit();
if (!visualViewportBased || visualViewportBased && strategy === "fixed") {
x = visualViewport.offsetLeft;
y = visualViewport.offsetTop;
}
}
return {
width,
height,
x,
y
};
}
function getInnerBoundingClientRect(element2, strategy) {
const clientRect = getBoundingClientRect(element2, true, strategy === "fixed");
const top = clientRect.top + element2.clientTop;
const left = clientRect.left + element2.clientLeft;
const scale = isHTMLElement(element2) ? getScale(element2) : createCoords(1);
const width = element2.clientWidth * scale.x;
const height = element2.clientHeight * scale.y;
const x = left * scale.x;
const y = top * scale.y;
return {
width,
height,
x,
y
};
}
function getClientRectFromClippingAncestor(element2, clippingAncestor, strategy) {
let rect;
if (clippingAncestor === "viewport") {
rect = getViewportRect(element2, strategy);
} else if (clippingAncestor === "document") {
rect = getDocumentRect(getDocumentElement(element2));
} else if (isElement(clippingAncestor)) {
rect = getInnerBoundingClientRect(clippingAncestor, strategy);
} else {
const visualOffsets = getVisualOffsets(element2);
rect = {
x: clippingAncestor.x - visualOffsets.x,
y: clippingAncestor.y - visualOffsets.y,
width: clippingAncestor.width,
height: clippingAncestor.height
};
}
return rectToClientRect(rect);
}
function hasFixedPositionAncestor(element2, stopNode) {
const parentNode = getParentNode(element2);
if (parentNode === stopNode || !isElement(parentNode) || isLastTraversableNode(parentNode)) {
return false;
}
return getComputedStyle2(parentNode).position === "fixed" || hasFixedPositionAncestor(parentNode, stopNode);
}
function getClippingElementAncestors(element2, cache) {
const cachedResult = cache.get(element2);
if (cachedResult) {
return cachedResult;
}
let result = getOverflowAncestors(element2, [], false).filter((el) => isElement(el) && getNodeName(el) !== "body");
let currentContainingBlockComputedStyle = null;
const elementIsFixed = getComputedStyle2(element2).position === "fixed";
let currentNode = elementIsFixed ? getParentNode(element2) : element2;
while (isElement(currentNode) && !isLastTraversableNode(currentNode)) {
const computedStyle = getComputedStyle2(currentNode);
const currentNodeIsContaining = isContainingBlock(currentNode);
if (!currentNodeIsContaining && computedStyle.position === "fixed") {
currentContainingBlockComputedStyle = null;
}
const shouldDropCurrentNode = elementIsFixed ? !currentNodeIsContaining && !currentContainingBlockComputedStyle : !currentNodeIsContaining && computedStyle.position === "static" && !!currentContainingBlockComputedStyle && ["absolute", "fixed"].includes(currentContainingBlockComputedStyle.position) || isOverflowElement(currentNode) && !currentNodeIsContaining && hasFixedPositionAncestor(element2, currentNode);
if (shouldDropCurrentNode) {
result = result.filter((ancestor) => ancestor !== currentNode);
} else {
currentContainingBlockComputedStyle = computedStyle;
}
currentNode = getParentNode(currentNode);
}
cache.set(element2, result);
return result;
}
function getClippingRect(_ref) {
let {
element: element2,
boundary,
rootBoundary,
strategy
} = _ref;
const elementClippingAncestors = boundary === "clippingAncestors" ? isTopLayer(element2) ? [] : getClippingElementAncestors(element2, this._c) : [].concat(boundary);
const clippingAncestors = [...elementClippingAncestors, rootBoundary];
const firstClippingAncestor = clippingAncestors[0];
const clippingRect = clippingAncestors.reduce((accRect, clippingAncestor) => {
const rect = getClientRectFromClippingAncestor(element2, clippingAncestor, strategy);
accRect.top = max(rect.top, accRect.top);
accRect.right = min(rect.right, accRect.right);
accRect.bottom = min(rect.bottom, accRect.bottom);
accRect.left = max(rect.left, accRect.left);
return accRect;
}, getClientRectFromClippingAncestor(element2, firstClippingAncestor, strategy));
return {
width: clippingRect.right - clippingRect.left,
height: clippingRect.bottom - clippingRect.top,
x: clippingRect.left,
y: clippingRect.top
};
}
function getDimensions(element2) {
const {
width,
height
} = getCssDimensions(element2);
return {
width,
height
};
}
function getRectRelativeToOffsetParent(element2, offsetParent, strategy) {
const isOffsetParentAnElement = isHTMLElement(offsetParent);
const documentElement = getDocumentElement(offsetParent);
const isFixed = strategy === "fixed";
const rect = getBoundingClientRect(element2, true, isFixed, offsetParent);
let scroll = {
scrollLeft: 0,
scrollTop: 0
};
const offsets = createCoords(0);
if (isOffsetParentAnElement || !isOffsetParentAnElement && !isFixed) {
if (getNodeName(offsetParent) !== "body" || isOverflowElement(documentElement)) {
scroll = getNodeScroll(offsetParent);
}
if (isOffsetParentAnElement) {
const offsetRect = getBoundingClientRect(offsetParent, true, isFixed, offsetParent);
offsets.x = offsetRect.x + offsetParent.clientLeft;
offsets.y = offsetRect.y + offsetParent.clientTop;
} else if (documentElement) {
offsets.x = getWindowScrollBarX(documentElement);
}
}
const htmlOffset = documentElement && !isOffsetParentAnElement && !isFixed ? getHTMLOffset(documentElement, scroll) : createCoords(0);
const x = rect.left + scroll.scrollLeft - offsets.x - htmlOffset.x;
const y = rect.top + scroll.scrollTop - offsets.y - htmlOffset.y;
return {
x,
y,
width: rect.width,
height: rect.height
};
}
function isStaticPositioned(element2) {
return getComputedStyle2(element2).position === "static";
}
function getTrueOffsetParent(element2, polyfill) {
if (!isHTMLElement(element2) || getComputedStyle2(element2).position === "fixed") {
return null;
}
if (polyfill) {
return polyfill(element2);
}
let rawOffsetParent = element2.offsetParent;
if (getDocumentElement(element2) === rawOffsetParent) {
rawOffsetParent = rawOffsetParent.ownerDocument.body;
}
return rawOffsetParent;
}
function getOffsetParent(element2, polyfill) {
const win = getWindow(element2);
if (isTopLayer(element2)) {
return win;
}
if (!isHTMLElement(element2)) {
let svgOffsetParent = getParentNode(element2);
while (svgOffsetParent && !isLastTraversableNode(svgOffsetParent)) {
if (isElement(svgOffsetParent) && !isStaticPositioned(svgOffsetParent)) {
return svgOffsetParent;
}
svgOffsetParent = getParentNode(svgOffsetParent);
}
return win;
}
let offsetParent = getTrueOffsetParent(element2, polyfill);
while (offsetParent && isTableElement(offsetParent) && isStaticPositioned(offsetParent)) {
offsetParent = getTrueOffsetParent(offsetParent, polyfill);
}
if (offsetParent && isLastTraversableNode(offsetParent) && isStaticPositioned(offsetParent) && !isContainingBlock(offsetParent)) {
return win;
}
return offsetParent || getContainingBlock(element2) || win;
}
var getElementRects = async function(data) {
const getOffsetParentFn = this.getOffsetParent || getOffsetParent;
const getDimensionsFn = this.getDimensions;
const floatingDimensions = await getDimensionsFn(data.floating);
return {
reference: getRectRelativeToOffsetParent(data.reference, await getOffsetParentFn(data.floating), data.strategy),
floating: {
x: 0,
y: 0,
width: floatingDimensions.width,
height: floatingDimensions.height
}
};
};
function isRTL2(element2) {
return getComputedStyle2(element2).direction === "rtl";
}
var platform = {
convertOffsetParentRelativeRectToViewportRelativeRect,
getDocumentElement,
getClippingRect,
getOffsetParent,
getElementRects,
getClientRects,
getDimensions,
getScale,
isElement,
isRTL: isRTL2
};
function rectsAreEqual(a, b) {
return a.x === b.x && a.y === b.y && a.width === b.width && a.height === b.height;
}
function observeMove(element2, onMove) {
let io = null;
let timeoutId;
const root = getDocumentElement(element2);
function cleanup() {
var _io;
clearTimeout(timeoutId);
(_io = io) == null || _io.disconnect();
io = null;
}
function refresh(skip, threshold) {
if (skip === void 0) {
skip = false;
}
if (threshold === void 0) {
threshold = 1;
}
cleanup();
const elementRectForRootMargin = element2.getBoundingClientRect();
const {
left,
top,
width,
height
} = elementRectForRootMargin;
if (!skip) {
onMove();
}
if (!width || !height) {
return;
}
const insetTop = floor(top);
const insetRight = floor(root.clientWidth - (left + width));
const insetBottom = floor(root.clientHeight - (top + height));
const insetLeft = floor(left);
const rootMargin = -insetTop + "px " + -insetRight + "px " + -insetBottom + "px " + -insetLeft + "px";
const options = {
rootMargin,
threshold: max(0, min(1, threshold)) || 1
};
let isFirstUpdate = true;
function handleObserve(entries) {
const ratio = entries[0].intersectionRatio;
if (ratio !== threshold) {
if (!isFirstUpdate) {
return refresh();
}
if (!ratio) {
timeoutId = setTimeout(() => {
refresh(false, 1e-7);
}, 1e3);
} else {
refresh(false, ratio);
}
}
if (ratio === 1 && !rectsAreEqual(elementRectForRootMargin, element2.getBoundingClientRect())) {
refresh();
}
isFirstUpdate = false;
}
try {
io = new IntersectionObserver(handleObserve, {
...options,
// Handle <iframe>s
root: root.ownerDocument
});
} catch (e) {
io = new IntersectionObserver(handleObserve, options);
}
io.observe(element2);
}
refresh(true);
return cleanup;
}
function autoUpdate(reference, floating, update, options) {
if (options === void 0) {
options = {};
}
const {
ancestorScroll = true,
ancestorResize = true,
elementResize = typeof ResizeObserver === "function",
layoutShift = typeof IntersectionObserver === "function",
animationFrame = false
} = options;
const referenceEl = unwrapElement(reference);
const ancestors = ancestorScroll || ancestorResize ? [...referenceEl ? getOverflowAncestors(referenceEl) : [], ...getOverflowAncestors(floating)] : [];
ancestors.forEach((ancestor) => {
ancestorScroll && ancestor.addEventListener("scroll", update, {
passive: true
});
ancestorResize && ancestor.addEventListener("resize", update);
});
const cleanupIo = referenceEl && layoutShift ? observeMove(referenceEl, update) : null;
let reobserveFrame = -1;
let resizeObserver = null;
if (elementResize) {
resizeObserver = new ResizeObserver((_ref) => {
let [firstEntry] = _ref;
if (firstEntry && firstEntry.target === referenceEl && resizeObserver) {
resizeObserver.unobserve(floating);
cancelAnimationFrame(reobserveFrame);
reobserveFrame = requestAnimationFrame(() => {
var _resizeObserver;
(_resizeObserver = resizeObserver) == null || _resizeObserver.observe(floating);
});
}
update();
});
if (referenceEl && !animationFrame) {
resizeObserver.observe(referenceEl);
}
resizeObserver.observe(floating);
}
let frameId;
let prevRefRect = animationFrame ? getBoundingClientRect(reference) : null;
if (animationFrame) {
frameLoop();
}
function frameLoop() {
const nextRefRect = getBoundingClientRect(reference);
if (prevRefRect && !rectsAreEqual(prevRefRect, nextRefRect)) {
update();
}
prevRefRect = nextRefRect;
frameId = requestAnimationFrame(frameLoop);
}
update();
return () => {
var _resizeObserver2;
ancestors.forEach((ancestor) => {
ancestorScroll && ancestor.removeEventListener("scroll", update);
ancestorResize && ancestor.removeEventListener("resize", update);
});
cleanupIo == null || cleanupIo();
(_resizeObserver2 = resizeObserver) == null || _resizeObserver2.disconnect();
resizeObserver = null;
if (animationFrame) {
cancelAnimationFrame(frameId);
}
};
}
var offset2 = offset;
var shift2 = shift;
var flip2 = flip;
var size2 = size;
var computePosition2 = (reference, floating, options) => {
const cache = /* @__PURE__ */ new Map();
const mergedOptions = {
platform,
...options
};
const platformWithCache = {
...mergedOptions.platform,
_c: cache
};
return computePosition(reference, floating, {
...mergedOptions,
platform: platformWithCache
});
};
// js/mixins/anchorable.js
var Anchorable = class extends Mixin {
boot({ options }) {
options({
reference: null,
auto: true,
position: "bottom start",
gap: "5",
offset: "0",
matchWidth: false,
crossAxis: false,
scrollY: true
});
if (this.options().reference === null) return;
if (this.options().position === null) return;
let [setPosition, cleanupDurablePositioning] = createDurablePositionSetter(this.el, { scrollY: this.options().scrollY });
let reposition = anchor(this.el, this.options().reference, setPosition, {
position: this.options().position,
gap: this.options().gap,
offset: this.options().offset,
matchWidth: this.options().matchWidth,
crossAxis: this.options().crossAxis,
scrollY: this.options().scrollY
});
let cleanupAutoUpdate = () => {
};
this.reposition = (...args) => {
if (this.options().auto) {
cleanupAutoUpdate = autoUpdate(this.options().reference, this.el, reposition);
} else {
reposition(null, ...args);
}
};
this.cleanup = () => {
cleanupAutoUpdate();
cleanupDurablePositioning();
};
}
};
function anchor(target, invoke, setPosition, { position, offset: offsetValue, gap, matchWidth, crossAxis, scrollY }) {
let elMaxHeight = window.getComputedStyle(target).maxHeight;
elMaxHeight = elMaxHeight === "none" ? null : parseFloat(elMaxHeight);
return (event, forceX, forceY) => {
computePosition2(invoke, target, {
placement: compilePlacement(position),
// Placements: ['top', 'top-start', 'top-end', 'right', 'right-start', 'right-end', 'bottom', 'bottom-start', 'bottom-end', 'left', 'left-start', 'left-end']
middleware: [
// Offset needs to be first, as per the Floating UI docs...
offset2({
mainAxis: Number(gap),
alignmentAxis: Number(offsetValue)
}),
flip2(),
shift2({ padding: 5, crossAxis }),
size2({
padding: 5,
apply({ rects, elements, availableHeight }) {
if (matchWidth) {
Object.assign(elements.floating.style, {
width: `${rects.reference.width}px`
});
}
let maxHeight = elMaxHeight;
if (maxHeight === null) {
maxHeight = scrollY ? elements.floating.scrollHeight : elements.floating.offsetHeight;
}
elements.floating.style.maxHeight = availableHeight > maxHeight ? "" : `${availableHeight}px`;
}
})
]
}).then(({ x, y }) => {
setPosition(forceX || x, forceY || y);
});
};
}
function compilePlacement(anchor2) {
let placement = anchor2.split(" ");
switch (placement[0]) {
case "start":
placement[0] = isRTL() ? "right" : "left";
break;
case "end":
placement[0] = isRTL() ? "left" : "right";
break;
}
return placement.join("-");
}
function createDurablePositionSetter(target, { scrollY = true }) {
let position = (x, y) => {
Object.assign(target.style, {
position: "absolute",
overflowY: scrollY ? "auto" : "hidden",
left: `${x}px`,
top: `${y}px`,
// This is required to reset the `popover` default styles, otherwise the dropdown appears in the middle of the screen...
right: "auto",
bottom: "auto"
});
};
let lastX, lastY;
let observer = new MutationObserver(() => position(lastX, lastY));
return [
(x, y) => {
lastX = x;
lastY = y;
observer.disconnect();
position(lastX, lastY);
observer.observe(target, { attributeFilter: ["style"] });
},
() => {
observer.disconnect();
}
];
}
// js/selected.js
var UISelected = class extends UIElement {
boot() {
this.querySelectorAll("[data-appended]").forEach((el) => el.remove());
if (!this.querySelector("template")) {
let template = document.createElement("template");
template.setAttribute("name", "placeholder");
template.innerHTML = "<span>" + this.innerHTML + "</span>";
this.innerHTML = "";
this.appendChild(template);
}
if (!this.querySelector('template[name="options"]')) {
let template = document.createElement("template");
template.setAttribute("name", "options");
template.innerHTML = "<div><slot></slot></div>";
this.appendChild(template);
}
if (!this.querySelector('template[name="option"]')) {
let template = document.createElement("template");
template.setAttribute("name", "option");
template.innerHTML = "<div><slot></slot></div>";
this.appendChild(template);
}
this.templates = {
placeholder: this.querySelector('template[name="placeholder"]'),
overflow: this.querySelector('template[name="overflow"]'),
options: this.querySelector('template[name="options"]'),
option: this.querySelector('template[name="option"]')
};
this.templates.options.elsByValue = /* @__PURE__ */ new Map();
this.max = this.templates.overflow?.getAttribute("max") ? this.templates.overflow.getAttribute("max") : Infinity;
this.selecteds = /* @__PURE__ */ new Map();
this.picker = this.closest("ui-select,ui-pillbox");
this.multiple = this.picker.hasAttribute("multiple");
}
mount() {
queueMicrotask(() => {
this.picker._selectable.onInitAndChange(() => {
this.render(true);
});
let optionsEl = this.picker.list();
if (optionsEl) {
new MutationObserver((mutations) => {
queueMicrotask(() => this.render());
}).observe(optionsEl, { childList: true });
}
});
}
render(retry) {
if (!this.multiple) {
let value3 = this.picker.value;
if (Array.from(this.selecteds.keys()).includes(value3)) {
return;
}
this.selecteds.clear();
let selected = this.picker._selectable.findByValue(value3);
if (selected) {
this.selecteds.set(value3, selected);
} else {
if (!["", null, void 0].includes(value3)) {
if (retry) return setTimeout(() => {
this.render();
});
else throw `Could not find option for value "${value3}"`;
}
}
this.templates.placeholder?.clearPlaceholder?.();
this.templates.option?.clearOption?.();
if (this.selecteds.size > 0) {
this.renderOption();
} else {
this.renderPlaceholder();
}
} else {
let values = this.picker.value;
let removedValues = Array.from(this.selecteds.keys()).filter((i) => !values.includes(i));
let newValues = values.filter((i) => !this.selecteds.has(i));
removedValues.forEach((value3) => this.selecteds.delete(value3));
let newSelecteds = /* @__PURE__ */ new Map();
for (let value3 of newValues) {
let selected = this.picker._selectable.findByValue(value3);
if (!selected) {
if (retry) return setTimeout(() => this.render());
else throw `Could not find option for value "${value3}"`;
}
newSelecteds.set(value3, selected);
}
newSelecteds.forEach((selected, value3) => this.selecteds.set(value3, selected));
this.templates.placeholder?.clearPlaceholder?.();
this.templates.overflow?.clearOverflow?.();
this.templates.options?.clearOptions?.();
if (this.selecteds.size > 0) {
this.renderOptions({
hasOverflowed: (rendered) => {
if (this.max === "auto") {
let willOverflow = false;
this.renderOverflow(this.selecteds.size, this.selecteds.size - rendered);
if (this.clientWidth < this.scrollWidth) {
willOverflow = true;
}
this.templates.overflow?.clearOverflow?.();
if (willOverflow) {
return true;
}
}
return rendered > parseInt(this.max);
},
renderOverflow: (remainder) => {
if (this.templates?.overflow?.getAttribute("mode") !== "append") {
this.templates.options?.clearOptions?.();
}
this.renderOverflow(this.selecteds.size, remainder);
}
});
} else {
this.renderPlaceholder();
}
}
}
renderOptions({ hasOverflowed, renderOverflow }) {
let container = document.createElement("div");
container.style.display = "contents";
let optionsEl = hydrateTemplate2(this.templates.options, {
default: container
});
this.templates.options.after(optionsEl);
this.templates.options.clearOptions = () => {
optionsEl.remove();
this.templates.options.clearOptions = () => {
};
};
let rendered = 0;
let shouldRenderOverflow = false;
for (let [value3, selected] of this.selecteds) {
let fragment2 = new DocumentFragment();
fragment2.append(...selected.el.cloneNode(true).childNodes);
let optionEl = hydrateTemplate2(this.templates.option, {
text: selected.getSelectedLabel() ?? selected.getLabel(),
default: selected.getSelectedLabel() ?? fragment2,
value: value3
});
optionEl.setAttribute("data-value", value3);
optionEl.setAttribute("data-appended", "");
optionEl.deselect = () => selected.deselect();
container.appendChild(optionEl);
rendered++;
if (hasOverflowed(rendered)) {
shouldRenderOverflow = true;
container.removeChild(optionEl);
rendered--;
break;
}
}
let fragment = new DocumentFragment();
fragment.append(...container.childNodes);
container.replaceWith(fragment);
if (shouldRenderOverflow) {
renderOverflow(this.selecteds.size - rendered);
}
}
renderOption() {
for (let [value3, selected] of this.selecteds) {
let fragment = new DocumentFragment();
fragment.append(...selected.el.cloneNode(true).childNodes);
let optionEl = hydrateTemplate2(this.templates.option, {
text: selected.getSelectedLabel() ?? selected.getLabel(),
default: selected.getSelectedLabel() ?? fragment,
value: value3
});
optionEl.setAttribute("data-value", value3);
optionEl.setAttribute("data-appended", value3);
optionEl.deselect = () => selected.deselect();
this.templates.option.after(optionEl);
this.templates.option.clearOption = () => {
optionEl.remove();
this.templates.option.clearOption = () => {
};
};
}
}
renderPlaceholder() {
if (!this.templates.placeholder) return;
let el = hydrateTemplate2(this.templates.placeholder);
el.setAttribute("data-appended", "");
this.templates.placeholder.after(el);
this.templates.placeholder.clearPlaceholder = () => {
el.remove();
this.templates.placeholder.clearPlaceholder = () => {
};
};
}
renderOverflow(count, remainder) {
if (!this.templates.overflow) return;
let el = hydrateTemplate2(this.templates.overflow, {
remainder,
count: this.selecteds.size
});
el.setAttribute("data-appended", "");
this.templates.overflow.after(el);
this.templates.overflow.clearOverflow = () => {
el.remove();
this.templates.placeholder.clearOverflow = () => {
};
};
}
};
var UISelectedRemove = class extends UIElement {
boot() {
this.addEventListener("click", (e) => {
e.stopPropagation();
let value3 = this.closest("[data-value]")?.getAttribute("data-value");
if (value3 === void 0) return;
let selectableGroup = this.closest("ui-pillbox")._selectable;
let selectable = selectableGroup.selectableByValue(value3);
if (selectable) {
selectable.deselect();
} else {
selectableGroup.deselectByValue(value3);
}
});
}
};
function hydrateTemplate2(template, slots = {}) {
let fragment = template.content.cloneNode(true);
Object.entries(slots).forEach(([key, value3]) => {
let slotNodes = key === "default" ? fragment.querySelectorAll("slot:not([name])") : fragment.querySelectorAll(`slot[name="${key}"]`);
slotNodes.forEach((i) => i.replaceWith(
typeof value3 === "string" ? document.createTextNode(value3) : value3
));
});
return fragment.firstElementChild;
}
// js/mixins/selectable.js
var SelectableGroup = class extends MixinGroup {
groupOfType = Selectable;
boot({ options }) {
options({
multiple: false
});
this.state = this.options().multiple ? /* @__PURE__ */ new Set() : null;
this.onChanges = [];
}
onInitAndChange(callback) {
callback();
this.onChanges.push(callback);
}
onChange(callback) {
this.onChanges.push(callback);
}
changed(selectable, silent = false) {
if (selectable.ungrouped) return;
let value3 = selectable.value;
let selected = selectable.isSelected();
let multiple = this.options().multiple;
if (selected) {
multiple ? this.state.add(value3) : this.state = value3;
} else {
multiple ? this.state.delete(value3) : this.state = null;
}
if (!silent) {
this.onChanges.forEach((i) => i(selectable));
}
}
deselectByValue(value3, silent = false) {
this.options().multiple ? this.state.delete(value3) : this.state = null;
if (!silent) {
this.onChanges.forEach((i) => i());
}
}
getState() {
return this.options().multiple ? Array.from(this.state) : this.state;
}
hasValue(value3) {
return this.options().multiple ? this.state.has(value3) : this.state === value3;
}
setState(value3) {
if (value3 === null || value3 === "") value3 = this.options().multiple ? [] : "";
if (this.options().multiple) {
if (!Array.isArray(value3)) value3 = [value3];
value3 = value3.map((i) => i + "");
} else {
value3 = value3 + "";
}
this.state = this.options().multiple ? new Set(value3) : value3;
let values = this.options().multiple ? value3 : [value3];
this.walker().each((el) => {
let selectable = el.use(Selectable);
if (selectable.ungrouped) return;
let selected = values.includes(selectable.value);
if (selected && !selectable.isSelected()) {
selectable.surgicallySelect();
} else if (!selected && selectable.isSelected()) {
selectable.surgicallyDeselect();
}
});
this.onChanges.forEach((i) => i());
}
selected() {
return this.walker().find((item) => item.use(Selectable).isSelected()).use(Selectable);
}
selecteds() {
return this.walker().filter((el) => el.use(Selectable).isSelected()).map((el) => el.use(Selectable));
}
selectFirst() {
this.walker().first()?.use(Selectable).select();
}
selectAll() {
this.walker().filter((el) => !el.use(Selectable).isSelected()).map((el) => el.use(Selectable).select());
}
deselectAll() {
this.walker().filter((el) => el.use(Selectable).isSelected()).map((el) => el.use(Selectable).deselect());
}
allAreSelected() {
let selectableElements = this.walker().filter((el) => true);
return selectableElements.length > 0 && this.walker().filter((el) => el.use(Selectable).isSelected()).length === selectableElements.length;
}
noneAreSelected() {
return this.state === null || this.state?.size === 0;
}
isEmpty() {
return this.noneAreSelected();
}
isNotEmpty() {
return !this.isEmpty();
}
selectableByValue(value3) {
return this.walker().find((el) => el.use(Selectable).value === value3)?.use(Selectable);
}
deselectOthers(except) {
this.walker().each((el) => {
if (el === except) return;
el.use(Selectable).surgicallyDeselect();
});
}
selectedTextValue() {
if (!this.options().multiple) return this.convertValueStringToElementText(this.state);
return Array.from(this.state).map((i) => {
return this.convertValueStringToElementText(i);
}).join(", ");
}
convertValueStringToElementText(value3) {
let selected = this.findByValue(value3);
if (selected) {
return selected.selectedLabel || selected.label || selected.value;
} else {
return value3;
}
}
findByValue(value3) {
return this.selecteds().find((i) => i.value === value3);
}
walker() {
return walker(this.el, (el, { skip, reject }) => {
if (el[this.constructor.name] && el !== this.el) return reject();
if (!el[this.groupOfType.name]) return skip();
if (el.mixins.get(this.groupOfType.name).ungrouped) return skip();
});
}
};
var Selectable = class extends Mixin {
boot({ options }) {
this.groupedByType = SelectableGroup;
options({
ungrouped: false,
togglable: false,
value: void 0,
label: void 0,
selectedLabel: void 0,
selectedInitially: false,
dataAttr: "data-selected",
ariaAttr: "aria-selected"
});
this.ungrouped = this.options().ungrouped;
this.value = this.options().value === void 0 ? this.el.value : this.options().value;
this.value = this.value + "";
this.label = this.options().label;
this.selectedLabel = this.options().selectedLabel;
let state = this.options().selectedInitially;
this.onSelects = [];
this.onUnselects = [];
this.onChanges = [];
let initState = () => {
if (this.group()) {
if (this.group().hasValue(this.value)) state = true;
}
this.multiple = this.hasGroup() ? this.group().options().multiple : false;
this.toggleable = this.options().toggleable || this.multiple;
if (state) {
this.select(true);
} else {
this.state = state;
this.surgicallyDeselect(true);
}
};
initState();
if (!this.hasGroup() && !this.el.isConnected) {
queueMicrotask(() => {
if (this.hasGroup()) {
initState();
}
});
}
}
mount() {
this.el.hasAttribute(this.options().ariaAttr) || setAttribute2(this.el, this.options().ariaAttr, "false");
}
onInitAndChange(callback) {
callback();
this.onChanges.push(callback);
}
onChange(callback) {
this.onChanges.push(callback);
}
onSelect(callback) {
this.onSelects.push(callback);
}
onUnselect(callback) {
this.onUnselects.push(callback);
}
setState(value3) {
value3 ? this.select() : this.deselect();
}
getState() {
return this.state;
}
// @todo: depricate in favor of "trigger"...
press() {
this.toggleable ? this.toggle() : this.select();
}
trigger() {
this.toggleable ? this.toggle() : this.select();
}
toggle() {
this.isSelected() ? this.deselect() : this.select();
}
isSelected() {
return this.state;
}
select(silent = false) {
let changed = !this.isSelected();
this.toggleable || this.group()?.deselectOthers(this.el);
this.state = true;
setAttribute2(this.el, this.options().ariaAttr, "true");
setAttribute2(this.el, this.options().dataAttr, "");
if (changed) {
if (!silent) {
this.onSelects.forEach((i) => i());
this.onChanges.forEach((i) => i());
}
this.group()?.changed(this, silent);
}
}
surgicallySelect() {
let changed = !this.isSelected();
this.state = true;
setAttribute2(this.el, this.options().ariaAttr, "true");
setAttribute2(this.el, this.options().dataAttr, "");
if (changed) {
this.onSelects.forEach((i) => i());
this.onChanges.forEach((i) => i());
}
}
deselect(notify = true) {
let changed = this.isSelected();
this.state = false;
setAttribute2(this.el, this.options().ariaAttr, "false");
removeAttribute(this.el, this.options().dataAttr);
if (changed) {
this.onUnselects.forEach((i) => i());
this.onChanges.forEach((i) => i());
notify && this.group()?.changed(this);
}
}
surgicallyDeselect(silent = false) {
let changed = this.isSelected();
this.state = false;
setAttribute2(this.el, this.options().ariaAttr, "false");
removeAttribute(this.el, this.options().dataAttr);
if (changed && !silent) {
this.onUnselects.forEach((i) => i());
this.onChanges.forEach((i) => i());
}
}
getValue() {
return this.value;
}
getLabel() {
return this.label;
}
getSelectedLabel() {
return this.selectedLabel;
}
};
// js/mixins/submittable.js
var Submittable = class extends Mixin {
boot({ options }) {
options({
name: void 0,
value: void 0,
includeWhenEmpty: true,
shouldUpdateValue: true
});
this.name = this.options().name;
this.value = this.options().value === void 0 ? this.el.value : this.options().value;
this.state = false;
this.observer = new MutationObserver(() => {
this.renderHiddenInputs();
});
this.observer.observe(this.el, { childList: true });
}
mount() {
this.renderHiddenInputs();
}
update(value3) {
if (this.options().shouldUpdateValue) {
this.value = value3;
} else {
this.state = !!value3;
}
this.renderHiddenInputs();
}
valueIsEmpty() {
return this.value === void 0 || this.value === null || this.value === "";
}
renderHiddenInputs() {
this.observer.disconnect();
if (!this.name) return;
let children = this.el.children;
let oldInputs = [];
for (let i = 0; i < children.length; i++) {
let child = children[i];
if (child.hasAttribute("data-flux-hidden")) oldInputs.push(child);
}
oldInputs.forEach((i) => i.remove());
let hiddenInputs;
if (this.options().shouldUpdateValue) {
hiddenInputs = !this.valueIsEmpty() || this.options().includeWhenEmpty ? this.generateInputs(this.name, this.value) : [];
} else {
hiddenInputs = this.state || this.options().includeWhenEmpty ? this.generateInputs(this.name, this.value) : [];
}
hiddenInputs.forEach((hiddenInput) => {
this.el.append(hiddenInput);
});
this.observer.observe(this.el, { childList: true });
}
generateInputs(name, value3, carry = []) {
if (this.isObjectOrArray(value3)) {
for (let key in value3) {
carry = carry.concat(
this.generateInputs(`${name}[${key}]`, value3[key])
);
}
} else {
let el = document.createElement("input");
el.setAttribute("type", "hidden");
el.setAttribute("name", name);
el.setAttribute("value", value3 === null ? "" : "" + value3);
el.setAttribute("data-flux-hidden", "");
el.setAttribute("data-appended", "");
return [el];
}
return carry;
}
isObjectOrArray(value3) {
return typeof value3 === "object" && value3 !== null;
}
submitEnclosingForm() {
let form = this.getAssociatedForm();
if (form) {
form.requestSubmit();
}
}
getAssociatedForm() {
let formId = this.el.getAttribute("form");
if (formId) {
return document.getElementById(formId) || null;
}
return this.el.closest("form");
}
};
// js/select.js
var UISelect = class extends UIControl {
boot() {
let list = this.list();
this._controllable = new Controllable(this, { bubbles: true });
this._selectable = new SelectableGroup(list, {
multiple: this.hasAttribute("multiple")
});
this._submittable = new Submittable(this, {
name: this.getAttribute("name"),
value: this._selectable.getState()
});
this._controllable.initial((initial) => initial && this._selectable.setState(initial));
this._controllable.getter(() => this._selectable.getState());
let detangled = detangle();
this._controllable.setter(detangled((value3) => {
this._selectable.setState(value3);
}));
this._selectable.onChange(detangled(() => {
this._controllable.dispatch();
this.dispatchEvent(new CustomEvent("select", { bubbles: false }));
}));
this._selectable.onInitAndChange(() => {
this._submittable.update(this._selectable.getState());
});
queueMicrotask(() => {
this._submittable.update(this._selectable.getState());
});
}
mount() {
this._disableable = new Disableable(this);
let input = this.input();
let button = this.button();
let list = this.list();
let multiple = this.hasAttribute("multiple");
let autocomplete = this.hasAttribute("autocomplete");
let strictAutocomplete = this.hasAttribute("autocomplete") && this.getAttribute("autocomplete").trim().split(" ").includes("strict");
let listbox = this.querySelector("ui-options") || this;
let listId = initListbox(listbox, "options", multiple);
this._activatable = new ActivatableGroup(listbox, { filter: "data-hidden" });
if (!input && !button) {
this._disableable.onInitAndChange((disabled) => {
disabled ? this.removeAttribute("tabindex") : this.setAttribute("tabindex", "0");
});
}
if (this.hasAttribute("filter") && this.getAttribute("filter") !== "manual") {
this._filterable = new FilterableGroup(list);
this._filterable.onChange(() => {
this._activatable.clearActive();
if (this._filterable.hasResults()) {
this._activatable.activateFirst();
}
});
this.addEventListener("close", () => {
if (this._filterable) {
requestAnimationFrame(() => {
this._filterable.filter("");
});
}
});
}
let popoverEl = this.querySelector("[popover]:not(ui-tooltip > [popover])");
let popoverInputEl = popoverEl?.querySelector('input:not([type="hidden"])');
let inputEl = this.querySelector('input:not([type="hidden"])');
inputEl = popoverEl?.contains(inputEl) ? null : inputEl;
let buttonEl = this.querySelector("button,ui-button");
buttonEl = popoverEl?.contains(buttonEl) ? null : buttonEl;
if (!(popoverEl || inputEl)) {
handleKeyboardNavigation(this, this._activatable);
handleKeyboardSelection(this, this, this._activatable);
handleActivationOnFocus(this, this._activatable, this._selectable);
} else if (!popoverEl && inputEl) {
let input2 = inputEl;
this._disableable.onInitAndChange((disabled) => {
if (disabled) {
input2 && setAttribute2(input2, "disabled", "");
} else {
input2 && removeAttribute(input2, "disabled");
}
});
handleInputClearing(this, input2, this._selectable, this._popoverable);
handleActivationOnFocus(input2, this._activatable, this._selectable);
handleAutocomplete(autocomplete, strictAutocomplete, this, input2, this._selectable, this._popoverable, this._filterable);
preventInputEventsFromBubblingToSelectRoot(input2);
highlightInputContentsWhenFocused(input2);
this._filterable && filterResultsByInput(list, input2, this._filterable);
trackActiveDescendant(input2, this._activatable, this._selectable);
handleKeyboardNavigation(input2, this._activatable);
handleKeyboardSelection(this, input2, this._activatable);
handleMouseSelection(this, this._activatable);
clearInvalidAttributeWhenTyping(input2);
} else if (popoverEl && inputEl) {
let input2 = inputEl;
setAttribute2(input2, "role", "combobox");
setAttribute2(input2, "aria-controls", listId);
let popover = popoverEl;
this._popoverable = new Popoverable(popover);
this._anchorable = new Anchorable(popover, {
reference: input2,
matchWidth: true,
position: this.hasAttribute("position") ? this.getAttribute("position") : void 0,
gap: this.hasAttribute("gap") ? this.getAttribute("gap") : void 0,
offset: this.hasAttribute("offset") ? this.getAttribute("offset") : void 0
});
handleAutocomplete(autocomplete, strictAutocomplete, this, input2, this._selectable, this._popoverable, this._filterable);
this._disableable.onInitAndChange((disabled) => {
if (disabled) {
input2 && setAttribute2(input2, "disabled", "");
} else {
input2 && removeAttribute(input2, "disabled");
}
});
this.querySelectorAll("button,ui-button").forEach((button2) => {
if (popover.contains(button2)) return;
setAttribute2(button2, "tabindex", "-1");
setAttribute2(button2, "aria-controls", listId);
setAttribute2(button2, "aria-haspopup", "listbox");
linkExpandedStateToPopover(button2, this._popoverable);
on(button2, "click", () => {
this._popoverable.toggle();
input2.focus();
});
});
handleInputClearing(this, input2, this._selectable, this._popoverable);
initPopover(this, input2, popover, this._popoverable, this._anchorable);
preventScrollWhenPopoverIsOpen(this, this._popoverable, [input2]);
linkExpandedStateToPopover(input2, this._popoverable);
preventInputEventsFromBubblingToSelectRoot(input2);
highlightInputContentsWhenFocused(input2);
this._filterable && filterResultsByInput(list, input2, this._filterable);
trackActiveDescendant(input2, this._activatable, this._selectable);
controlPopoverWithInput(input2, this._popoverable);
controlPopoverWithKeyboard(input2, this._popoverable, this._activatable, this._selectable);
openPopoverWithMouse(input2, this._popoverable);
controlPopoverWithEscapeKey(this, this._popoverable);
handleKeyboardNavigation(input2, this._activatable);
handleKeyboardSelection(this, input2, this._activatable);
handleMouseSelection(this, this._activatable);
controlActivationWithPopover(this._popoverable, this._activatable, this._selectable);
handlePopoverClosing(this, this._selectable, this._popoverable, multiple);
clearInvalidAttributeWhenTyping(input2);
} else if (popoverEl && popoverInputEl) {
let button2 = buttonEl;
let input2 = popoverInputEl;
let popover = popoverEl;
setAttribute2(button2, "role", "combobox");
setAttribute2(input2, "role", "combobox");
setAttribute2(button2, "aria-controls", listId);
this._disableable.onInitAndChange((disabled) => {
if (disabled) {
button2 && setAttribute2(button2, "disabled", "");
input2 && setAttribute2(input2, "disabled", "");
} else {
button2 && removeAttribute(button2, "disabled");
input2 && removeAttribute(input2, "disabled");
}
});
this._popoverable = new Popoverable(popover);
this._anchorable = new Anchorable(popover, {
reference: button2,
matchWidth: true,
position: this.hasAttribute("position") ? this.getAttribute("position") : void 0,
gap: this.hasAttribute("gap") ? this.getAttribute("gap") : void 0,
offset: this.hasAttribute("offset") ? this.getAttribute("offset") : void 0,
scrollY: false
});
preventInputEventsFromBubblingToSelectRoot(input2);
highlightInputContentsWhenFocused(input2);
this._filterable && filterResultsByInput(list, input2, this._filterable);
focusInputWhenPopoverOpens(input2, this._popoverable);
initPopover(this, button2, popover, this._popoverable, this._anchorable);
preventScrollWhenPopoverIsOpen(this, this._popoverable, [input2]);
linkExpandedStateToPopover(button2, this._popoverable);
handleInputClearing(this, input2, this._selectable, this._popoverable);
controlPopoverWithKeyboard(button2, this._popoverable, this._activatable, this._selectable);
togglePopoverWithMouse(button2, this._popoverable, input2);
controlPopoverWithEscapeKey(this, this._popoverable);
handleKeyboardNavigation(input2, this._activatable);
handleKeyboardSearchNavigation(button2, this._activatable, this._popoverable);
handleKeyboardSelection(this, input2, this._activatable);
handleMouseSelection(this, this._activatable);
controlActivationWithPopover(this._popoverable, this._activatable, this._selectable);
handlePopoverClosing(this, this._selectable, this._popoverable, multiple);
clearInvalidAttributeWhenTyping(input2);
} else if (popoverEl) {
let button2 = buttonEl;
let popover = popoverEl;
setAttribute2(button2, "role", "combobox");
setAttribute2(button2, "aria-controls", listId);
this._disableable.onInitAndChange((disabled) => {
if (disabled) {
button2 && setAttribute2(button2, "disabled", "");
input && setAttribute2(input, "disabled", "");
} else {
button2 && removeAttribute(button2, "disabled");
input && removeAttribute(input, "disabled");
}
});
this._popoverable = new Popoverable(popover);
this._anchorable = new Anchorable(popover, {
reference: button2,
matchWidth: true,
position: this.hasAttribute("position") ? this.getAttribute("position") : void 0,
gap: this.hasAttribute("gap") ? this.getAttribute("gap") : void 0,
offset: this.hasAttribute("offset") ? this.getAttribute("offset") : void 0
});
initPopover(this, button2, popover, this._popoverable, this._anchorable);
preventScrollWhenPopoverIsOpen(this, this._popoverable);
linkExpandedStateToPopover(button2, this._popoverable);
controlPopoverWithKeyboard(button2, this._popoverable, this._activatable, this._selectable);
togglePopoverWithMouse(button2, this._popoverable);
trackActiveDescendant(button2, this._activatable, this._selectable);
controlPopoverWithEscapeKey(this, this._popoverable);
handleKeyboardNavigation(button2, this._activatable);
handleKeyboardSearchNavigation(button2, this._activatable, this._popoverable);
handleKeyboardSelection(this, button2, this._activatable);
handleMouseSelection(this, this._activatable);
controlActivationWithPopover(this._popoverable, this._activatable, this._selectable);
handlePopoverClosing(this, this._selectable, this._popoverable, multiple);
}
let observer = new MutationObserver(() => {
requestAnimationFrame(() => {
if (!this._popoverable || this._popoverable.getState()) {
let firstSelectedOption = this._selectable.selecteds().find((selected) => !selected.el._disableable.isDisabled())?.el;
this._activatable.activateSelectedOrFirst(firstSelectedOption);
} else {
this._activatable.clearActive();
}
});
});
observer.observe(list, { childList: true });
}
unmount() {
if (this._popoverable?.getState()) {
let { unlock } = lockScroll();
unlock();
}
}
trigger() {
return this.button() || this.input();
}
button() {
return Array.from(this.querySelectorAll("button,ui-button")).find(
(button) => button.nextElementSibling?.matches("[popover]")
) || null;
}
input() {
return this.querySelector('input:not([type="hidden"])');
}
list() {
return this.querySelector("ui-options") || this;
}
clear() {
if (!this.input()) return;
this.input().value = "";
this.input().dispatchEvent(new Event("input", { bubbles: false }));
}
open() {
this._popoverable.setState(true);
}
close() {
this._popoverable.setState(false);
}
deselectLast() {
if (!this.hasAttribute("multiple") && this.value !== null) {
this.value = null;
this.dispatchEvent(new Event("input", { bubbles: false }));
this.dispatchEvent(new Event("change", { bubbles: false }));
}
if (this.hasAttribute("multiple") && this.value.length !== 0) {
this.value = this.value.slice(0, -1);
this.dispatchEvent(new Event("input", { bubbles: false }));
this.dispatchEvent(new Event("change", { bubbles: false }));
}
}
};
element("selected-remove", UISelectedRemove);
element("selected", UISelected);
element("select", UISelect);
inject(({ css }) => css`ui-select { display: block; }`);
inject(({ css }) => css`ui-selected-option { display: contents; }`);
function handleKeyboardNavigation(el, activatable) {
on(el, "keydown", (e) => {
if (!["ArrowDown", "ArrowUp"].includes(e.key)) return;
if (e.key === "ArrowDown") {
activatable.activateNext();
e.preventDefault();
e.stopPropagation();
} else if (e.key === "ArrowUp") {
activatable.activatePrev();
e.preventDefault();
e.stopPropagation();
}
});
}
function handleKeyboardSearchNavigation(el, activatable, popoverable) {
search(el, (query) => {
activatable.activateBySearch(query);
if (!popoverable.getState()) {
activatable.getActive()?.click();
}
});
}
function handleKeyboardSelection(root, el, activatable) {
on(el, "keydown", (e) => {
if (e.key === "Enter") {
let activeEl = activatable.getActive();
e.preventDefault();
e.stopPropagation();
if (!activeEl) return;
if (activeEl._disableable?.isDisabled()) return;
activeEl.click();
root.dispatchEvent(new CustomEvent("interaction", {
bubbles: false,
cancelable: false,
detail: { optionEl: activeEl }
}));
if (activeEl.hasAttribute("action")) {
root.dispatchEvent(new CustomEvent("action", {
bubbles: false,
cancelable: false,
detail: { optionEl: activeEl }
}));
}
}
});
}
function handleMouseSelection(root, activatable, pointerdown = false) {
on(root, pointerdown ? "pointerdown" : "click", (e) => {
if (e.target.closest("ui-option, ui-option-create")) {
let option = e.target.closest("ui-option, ui-option-create");
if (option._disableable.isDisabled()) return;
option._selectable?.trigger();
root.dispatchEvent(new CustomEvent("interaction", {
bubbles: false,
cancelable: false,
detail: { optionEl: option }
}));
if (option.hasAttribute("action")) {
root.dispatchEvent(new CustomEvent("action", {
bubbles: false,
cancelable: false,
detail: { optionEl: option }
}));
}
e.preventDefault();
e.stopPropagation();
}
});
}
function handleActivationOnFocus(el, activatable, selectable) {
on(el, "focus", () => {
let firstSelectedOption = selectable.selecteds().find((selected) => !selected.el._disableable.isDisabled())?.el;
activatable.activateSelectedOrFirst(firstSelectedOption);
});
on(el, "blur", () => {
activatable.clearActive();
});
}
function initListbox(el, multiple) {
let listId = assignId(el, "options");
setAttribute2(el, "role", "listbox");
setAttribute2(el, "aria-multiselectable", multiple ? "true" : "false");
return listId;
}
function linkExpandedStateToPopover(el, popoverable) {
setAttribute2(el, "aria-haspopup", "listbox");
let refreshPopover = () => {
setAttribute2(el, "aria-expanded", popoverable.getState() ? "true" : "false");
popoverable.getState() ? setAttribute2(el, "data-open", "") : removeAttribute(el, "data-open", "");
};
popoverable.onChange(() => {
refreshPopover();
});
refreshPopover();
}
function initPopover(root, trigger, popover, popoverable, anchorable) {
let refreshPopover = () => {
Array.from([root, popover]).forEach((i) => {
popoverable.getState() ? setAttribute2(i, "data-open", "") : removeAttribute(i, "data-open", "");
});
popoverable.getState() ? anchorable.reposition() : anchorable.cleanup();
};
popoverable.onChange(() => refreshPopover());
refreshPopover();
popoverable.onChange(() => {
if (popoverable.getState()) {
root.dispatchEvent(new Event("open", {
bubbles: false,
cancelable: false
}));
} else {
root.dispatchEvent(new Event("close", {
bubbles: false,
cancelable: false
}));
}
});
}
function controlActivationWithPopover(popoverable, activatable, selectable) {
popoverable.onChange(() => {
if (popoverable.getState()) {
let firstSelectedOption = selectable.selecteds().find((selected) => !selected.el._disableable.isDisabled())?.el;
setTimeout(() => {
activatable.activateSelectedOrFirst(firstSelectedOption);
});
} else {
activatable.clearActive();
}
});
}
function controlPopoverWithEscapeKey(root, popoverable) {
on(root, "keydown", (e) => {
if (e.key === "Escape" && popoverable.getState()) {
popoverable.setState(false);
e.preventDefault();
e.stopImmediatePropagation();
}
});
}
function controlPopoverWithKeyboard(button, popoverable) {
on(button, "keydown", (e) => {
if (!["ArrowDown", "ArrowUp"].includes(e.key)) return;
if (e.key === "ArrowDown") {
if (!popoverable.getState()) {
popoverable.setState(true);
e.preventDefault();
e.stopImmediatePropagation();
}
} else if (e.key === "ArrowUp") {
if (!popoverable.getState()) {
popoverable.setState(true);
e.preventDefault();
e.stopImmediatePropagation();
}
}
});
}
function openPopoverWithMouse(el, popoverable) {
on(el, "click", () => {
if (!popoverable.getState()) {
popoverable.setState(true);
el.focus();
}
});
}
function togglePopoverWithMouse(button, popoverable, input = null) {
on(button, "click", () => {
popoverable.setState(!popoverable.getState());
button.focus();
if (popoverable.getState() && input) {
input.focus();
}
});
}
function focusInputWhenPopoverOpens(input, popoverable) {
popoverable.onChange(() => {
if (popoverable.getState()) {
setTimeout(() => input.focus());
}
});
}
function filterResultsByInput(list, input, filterable) {
on(input, "input", (e) => {
filterable.filter(e.target.value);
});
let observer = new MutationObserver(() => {
filterable.filter(input.value);
});
observer.observe(list, { childList: true });
}
function highlightInputContentsWhenFocused(input) {
on(input, "focus", () => input.select());
}
function preventInputEventsFromBubblingToSelectRoot(input) {
on(input, "change", (e) => e.stopPropagation());
on(input, "input", (e) => e.stopPropagation());
}
function controlPopoverWithInput(input, popoverable) {
on(input, "keydown", (e) => {
if (/^[a-zA-Z0-9]$/.test(e.key) || e.key === "Backspace") {
popoverable.getState() || popoverable.setState(true);
}
});
}
function handleInputClearing(root, input, selectable, popoverable) {
let shouldClear = root.hasAttribute("clear");
if (!shouldClear) return;
let setInputValue = (value3) => {
if (input.value === value3) return;
input.value = value3;
input.dispatchEvent(new Event("input", { bubbles: false }));
};
let clear = root.getAttribute("clear");
let clearOnAction = clear === "" || clear.split(" ").includes("action");
let clearOnSelect = clear === "" || clear.split(" ").includes("select");
let clearOnClose = clear === "" || clear.split(" ").includes("close");
let clearOnEsc = clear === "" || clear.split(" ").includes("esc");
if (clear === "none") clearOnAction = clearOnSelect = clearOnClose = clearOnEsc = false;
if (clearOnAction) {
root.addEventListener("action", (e) => {
setInputValue("");
});
} else if (clearOnSelect) {
selectable.onChange(() => {
queueMicrotask(() => setInputValue(""));
});
}
if (clearOnClose) {
popoverable.onChange(() => {
if (!popoverable.getState()) {
setInputValue("");
}
});
}
if (clearOnEsc) {
on(input, "keydown", (e) => {
if (e.key === "Escape") {
setInputValue("");
}
});
}
}
function handlePopoverClosing(root, selectable, popoverable, multiple) {
let closeOnInteraction = !multiple;
let closeOnAction = !multiple;
let closeOnSelect = !multiple;
if (root.hasAttribute("close")) {
let close = root.getAttribute("close");
closeOnInteraction = close === "";
closeOnAction = close.split(" ").includes("action");
closeOnSelect = close.split(" ").includes("select");
if (close === "none") return;
}
if (closeOnInteraction || closeOnAction) {
root.addEventListener("interaction", (e) => {
let optionEl = e.detail.optionEl;
if (!optionEl.hasAttribute("action")) {
popoverable.setState(false);
return;
}
setTimeout(() => {
if (!optionEl.hasAttribute("data-flux-loading") && !optionEl.hasAttribute("data-loading")) {
popoverable.setState(false);
return;
}
let observer = new MutationObserver(() => {
requestAnimationFrame(() => {
if (!root.querySelector("input[data-invalid]")) {
popoverable.setState(false);
}
});
observer.disconnect();
});
observer.observe(optionEl, { attributes: true, attributeFilter: ["data-loading", "data-flux-loading"] });
}, 10);
});
} else if (closeOnSelect) {
selectable.onChange(() => {
popoverable.setState(false);
});
}
}
function trackActiveDescendant(input, activatable, selectable) {
activatable.onChange(() => {
let activeEl = activatable.getActive();
activeEl ? setAttribute2(input, "aria-activedescendant", activeEl.id) : removeAttribute(input, "aria-activedescendant");
});
selectable.onChange((selectableItem) => {
if (!selectableItem) return;
let activeEl = selectableItem.el;
activeEl && setAttribute2(input, "aria-activedescendant", activeEl.id);
});
}
function handleAutocomplete(autocomplete, isStrict, root, input, selectable, popoverable, filterable) {
if (!autocomplete) {
setAttribute2(input, "autocomplete", "off");
setAttribute2(input, "aria-autocomplete", "none");
return;
}
let setInputValue = (value3) => {
if (input.value === value3) return;
input.value = value3;
input.dispatchEvent(new Event("input", { bubbles: false }));
};
setAttribute2(input, "autocomplete", "off");
setAttribute2(input, "aria-autocomplete", "list");
if (input.value !== "") {
selectable.setState(input.value);
}
let sync = () => {
if (selectable.isNotEmpty()) {
requestAnimationFrame(() => {
setInputValue(selectable.selectedTextValue());
if (isStrict) setAttribute2(input, "data-selected", selectable.selectedTextValue());
});
} else {
setInputValue("");
removeAttribute(input, "data-selected");
}
};
queueMicrotask(() => {
selectable.onInitAndChange(() => sync());
});
root.addEventListener("interaction", (e) => {
if (e.detail.optionEl._selectable?.isSelected()) sync();
});
if (isStrict) {
popoverable.onChange(() => {
if (!popoverable.getState()) {
requestAnimationFrame(() => {
setInputValue(input.getAttribute("data-selected"));
});
}
});
}
}
function preventScrollWhenPopoverIsOpen(root, popoverable, except = []) {
let { lock, unlock } = lockScroll(popoverable.el, false, except);
popoverable.onChange(() => {
popoverable.getState() ? lock() : unlock();
});
}
function clearInvalidAttributeWhenTyping(input) {
on(input, "input", () => {
if (input.hasAttribute("data-invalid")) {
input.removeAttribute("data-invalid");
input.removeAttribute("aria-invalid");
}
});
}
// js/pillbox.js
var UIPillbox = class extends UISelect {
mount() {
this._disableable = new Disableable(this);
let input = this.input();
let list = this.list();
let multiple = this.hasAttribute("multiple");
let triggerEl = this.querySelector("ui-pillbox-trigger");
let listbox = this.querySelector("ui-options") || this;
let listId = initListbox(listbox, "options", multiple);
this._activatable = new ActivatableGroup(listbox, { filter: "data-hidden" });
if (this.hasAttribute("filter") && this.getAttribute("filter") !== "manual") {
this._filterable = new FilterableGroup(list);
this._filterable.onChange(() => {
this._activatable.clearActive();
if (this._filterable.hasResults()) {
this._activatable.activateFirst();
}
});
this.addEventListener("close", () => {
if (this._filterable) {
this._filterable.filter("");
}
});
}
let popoverEl = this.querySelector("[popover]:not(ui-tooltip > [popover])");
let popoverInputEl = popoverEl?.querySelector('input:not([type="hidden"])');
let inlineInputEl = this.querySelector("ui-selected input");
if (!popoverEl) throw new Error("Popover element not found");
if (popoverInputEl) {
let trigger = triggerEl;
let input2 = popoverInputEl;
let popover = popoverEl;
setAttribute2(trigger, "role", "button");
setAttribute2(input2, "aria-autocomplete", "list");
setAttribute2(input2, "aria-controls", listId);
setAttribute2(input2, "role", "combobox");
this._disableable.onInitAndChange((disabled) => {
if (disabled) {
trigger && setAttribute2(trigger, "disabled", "");
input2 && setAttribute2(input2, "disabled", "");
} else {
trigger && removeAttribute(trigger, "disabled");
input2 && removeAttribute(input2, "disabled");
}
});
this._popoverable = new Popoverable(popover);
this._anchorable = new Anchorable(popover, {
reference: trigger,
matchWidth: true,
position: this.hasAttribute("position") ? this.getAttribute("position") : void 0,
gap: this.hasAttribute("gap") ? this.getAttribute("gap") : void 0,
offset: this.hasAttribute("offset") ? this.getAttribute("offset") : void 0,
scrollY: false
});
trackActiveDescendant(input2, this._activatable, this._selectable);
preventInputEventsFromBubblingToSelectRoot(input2);
highlightInputContentsWhenFocused(input2);
this._filterable && filterResultsByInput(list, input2, this._filterable);
focusInputWhenPopoverOpens(input2, this._popoverable);
initPopover(this, trigger, popover, this._popoverable, this._anchorable);
preventScrollWhenPopoverIsOpen(this, this._popoverable, [input2]);
linkExpandedStateToPopover(trigger, this._popoverable);
handleInputClearing(this, input2, this._selectable, this._popoverable);
controlPopoverWithKeyboard(trigger, this._popoverable, this._activatable, this._selectable);
togglePopoverWithMouse(trigger, this._popoverable);
controlPopoverWithEscapeKey(this, this._popoverable);
handleKeyboardNavigation(input2, this._activatable);
handleKeyboardSearchNavigation(trigger, this._activatable, this._popoverable);
handleKeyboardSelection(this, input2, this._activatable);
handleMouseSelection(this, this._activatable);
controlActivationWithPopover(this._popoverable, this._activatable, this._selectable);
handlePopoverClosing(this, this._selectable, this._popoverable, multiple);
clearInvalidAttributeWhenTyping(input2);
openPopoverWithSpacebar(trigger);
} else if (inlineInputEl) {
let trigger = triggerEl;
let input2 = inlineInputEl;
let popover = popoverEl;
setAttribute2(trigger, "role", "button");
setAttribute2(input2, "aria-autocomplete", "list");
setAttribute2(input2, "aria-controls", listId);
setAttribute2(input2, "role", "combobox");
this._disableable.onInitAndChange((disabled) => {
if (disabled) {
trigger && setAttribute2(trigger, "disabled", "");
input2 && setAttribute2(input2, "disabled", "");
} else {
trigger && removeAttribute(trigger, "disabled");
input2 && removeAttribute(input2, "disabled");
}
});
this._popoverable = new Popoverable(popover, {
triggers: [input2, trigger]
// Make sure that focusing the input doesn't close the popover...
});
this._anchorable = new Anchorable(popover, {
reference: trigger,
matchWidth: true,
position: this.hasAttribute("position") ? this.getAttribute("position") : void 0,
gap: this.hasAttribute("gap") ? this.getAttribute("gap") : void 0,
offset: this.hasAttribute("offset") ? this.getAttribute("offset") : void 0
});
trackActiveDescendant(input2, this._activatable, this._selectable);
preventInputEventsFromBubblingToSelectRoot(input2);
highlightInputContentsWhenFocused(input2);
this._filterable && filterResultsByInput(list, input2, this._filterable);
focusInputWhenPopoverOpens(input2, this._popoverable);
initPopover(this, trigger, popover, this._popoverable, this._anchorable);
preventScrollWhenPopoverIsOpen(this, this._popoverable, [trigger]);
linkExpandedStateToPopover(trigger, this._popoverable);
handleInputClearing(this, input2, this._selectable, this._popoverable);
controlPopoverWithInput(input2, this._popoverable);
controlPopoverWithKeyboard(input2, this._popoverable, this._activatable, this._selectable);
openPopoverWithMouse(trigger, this._popoverable, input2);
controlPopoverWithEscapeKey(this, this._popoverable);
handleKeyboardNavigation(input2, this._activatable);
handleKeyboardSearchNavigation(trigger, this._activatable, this._popoverable);
handleKeyboardSelection(this, input2, this._activatable);
handleMouseSelection(this, this._activatable);
controlActivationWithPopover(this._popoverable, this._activatable, this._selectable);
handlePopoverClosing(this, this._selectable, this._popoverable, multiple);
focusInputOnSelection(this, this._selectable, input2);
hideInputPlaceholderWhenNotEmpty(this._selectable, input2);
deselectLastItemWithBackspace(this._selectable, input2);
clearInvalidAttributeWhenTyping(input2);
forwardClicksToInputWhenPopoverIsOpen(this._popoverable, trigger, input2);
} else {
let trigger = triggerEl;
let popover = popoverEl;
setAttribute2(trigger, "role", "combobox");
setAttribute2(trigger, "aria-controls", listId);
setAttribute2(trigger, "aria-autocomplete", "none");
this._disableable.onInitAndChange((disabled) => {
if (disabled) {
trigger && setAttribute2(trigger, "disabled", "");
input && setAttribute2(input, "disabled", "");
} else {
trigger && removeAttribute(trigger, "disabled");
input && removeAttribute(input, "disabled");
}
});
this._popoverable = new Popoverable(popover);
this._anchorable = new Anchorable(popover, {
reference: trigger,
matchWidth: true,
position: this.hasAttribute("position") ? this.getAttribute("position") : void 0,
gap: this.hasAttribute("gap") ? this.getAttribute("gap") : void 0,
offset: this.hasAttribute("offset") ? this.getAttribute("offset") : void 0
});
initPopover(this, trigger, popover, this._popoverable, this._anchorable);
preventScrollWhenPopoverIsOpen(this, this._popoverable);
linkExpandedStateToPopover(trigger, this._popoverable);
controlPopoverWithKeyboard(trigger, this._popoverable, this._activatable, this._selectable);
togglePopoverWithMouse(trigger, this._popoverable);
trackActiveDescendant(trigger, this._activatable, this._selectable);
controlPopoverWithEscapeKey(this, this._popoverable);
handleKeyboardNavigation(trigger, this._activatable);
handleKeyboardSearchNavigation(trigger, this._activatable, this._popoverable);
handleKeyboardSelection(this, trigger, this._activatable);
handleMouseSelection(this, this._activatable);
controlActivationWithPopover(this._popoverable, this._activatable, this._selectable);
handlePopoverClosing(this, this._selectable, this._popoverable, multiple);
openPopoverWithSpacebar(trigger);
}
let observer = new MutationObserver(() => {
requestAnimationFrame(() => {
if (!this._popoverable || this._popoverable.getState()) {
let firstSelectedOption = this._selectable.selecteds().find((selected) => !selected.el._disableable.isDisabled())?.el;
this._activatable.activateSelectedOrFirst(firstSelectedOption);
} else {
this._activatable.clearActive();
}
});
});
observer.observe(list, { childList: true });
}
list() {
return this.querySelector("ui-options") || this;
}
};
var UIPillboxTrigger = class extends UIElement {
boot() {
if (this.querySelector("input")) {
setAttribute2(this, "tabindex", "-1");
} else {
setAttribute2(this, "tabindex", "0");
}
this._disableable = new Disableable(this);
let disableClick = (e) => {
e.preventDefault();
e.stopImmediatePropagation();
};
this._disableable.onInitAndChange((disabled) => {
if (disabled) {
this.addEventListener("click", disableClick, true);
} else {
this.removeEventListener("click", disableClick, true);
}
});
}
mount() {
}
};
element("pillbox-trigger", UIPillboxTrigger);
element("pillbox", UIPillbox);
inject(({ css }) => css`ui-pillbox { display: block; }`);
function openPopoverWithSpacebar(el) {
on(el, "keydown", (e) => {
if (e.key === " ") {
e.preventDefault();
e.stopImmediatePropagation();
el.click();
}
});
}
function focusInputOnSelection(root, selectable, input) {
selectable.onChange(() => {
if (document.activeElement !== input && document.activeElement.closest("ui-pillbox") === root) {
input.focus();
}
});
}
function hideInputPlaceholderWhenNotEmpty(selectable, input) {
selectable.onInitAndChange(() => {
if (selectable.noneAreSelected()) {
setAttribute2(input, "placeholder", input.getAttribute("data-placeholder"));
} else {
setAttribute2(input, "placeholder", "");
}
});
}
function deselectLastItemWithBackspace(selectable, input) {
on(input, "keydown", (e) => {
if (input.value == "" && e.key === "Backspace") {
let last = selectable.findByValue(
selectable.getState().at(-1)
);
last?.deselect();
}
});
}
function forwardClicksToInputWhenPopoverIsOpen(popoverable, trigger, input) {
on(trigger, "click", (e) => {
if (popoverable.getState()) {
input.focus();
e.preventDefault();
e.stopImmediatePropagation();
}
});
}
// js/options.js
var UIOptions = class extends UIElement {
boot() {
setAttribute2(this, "tabindex", "-1");
if (this.hasAttribute("popover")) {
this.addEventListener("lofi-close-popovers", () => {
this.hidePopover();
});
}
setAttribute2(this, "role", "listbox");
}
mount() {
let picker = this.closest("ui-autocomplete, ui-combobox, ui-select, ui-pillbox");
let input = picker?.input();
if (input) displayEmptyAndCreateOptions(this, input, picker._filterable);
}
};
var UIOption = class extends UIElement {
mount() {
let target = this;
this._disableable = new Disableable(target, {
disableWithParent: false
});
this._disableable.onInitAndChange((disabled) => {
if (disabled) {
setAttribute2(target, "aria-disabled", "true");
} else {
removeAttribute(target, "aria-disabled");
}
});
let id = assignId(target, "option");
setAttribute2(target, "role", "option");
this._filterable = new Filterable(target, {
mirror: this,
keep: !!this.closest("ui-option-empty, ui-empty") || this.getAttribute("filter") === "manual"
});
this._activatable = new Activatable(target);
if (!this.hasAttribute("action")) {
this._selectable = new Selectable(target, {
value: this.getValue(),
label: this.getLabel(),
selectedLabel: this.getSelectedLabel(),
selectedInitially: this.hasAttribute("selected")
});
}
let observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if (mutation.attributeName === "selected") {
if (this.hasAttribute("selected")) this._selectable.setState(true);
else this._selectable.setState(false);
}
});
});
observer.observe(this, { attributeFilter: ["selected"] });
}
get selected() {
if (!this?._selectable) return false;
return this._selectable.isSelected();
}
set selected(value3) {
if (!this?._selectable) return false;
this._selectable.setState(value3);
}
getSelectedLabel() {
return this.getAttribute("selected-label");
}
getLabel() {
return this.hasAttribute("label") ? this.getAttribute("label") : this.textContent.trim();
}
getValue() {
return this.hasAttribute("value") ? this.getAttribute("value") : this.textContent.trim();
}
};
var UIOptionCreate = class extends UIElement {
mount() {
this._activatable = new Activatable(this);
this._filterable = new Filterable(this, { keep: true });
this._disableable = new Disableable(this, {
disableWithParent: false
});
this._disableable.onInitAndChange((disabled) => {
if (disabled) {
setAttribute2(this, "aria-disabled", "true");
} else {
removeAttribute(this, "aria-disabled");
}
});
}
};
var UIOptionEmpty = class extends UIElement {
};
var UIEmpty = class extends UIOptionEmpty {
};
inject(({ css }) => css`ui-options:not([popover]), ui-option { display: block; cursor: default; }`);
inject(({ css }) => css`ui-option-create { display: block; cursor: default; }`);
inject(({ css }) => css`ui-option-empty { display: block; cursor: default; }`);
inject(({ css }) => css`ui-empty { display: block; cursor: default; }`);
element("options", UIOptions);
element("option", UIOption);
element("option-create", UIOptionCreate);
element("option-empty", UIOptionEmpty);
element("empty", UIEmpty);
function normalizeScopedSelector(selector) {
if (!CSS.supports("selector(&)")) {
return selector.replace("&", ":scope");
}
return selector;
}
function displayEmptyAndCreateOptions(list, input, filterable) {
let empty = list.querySelector(normalizeScopedSelector("& > ui-option-empty, & > ui-empty"));
let create = list.querySelector(normalizeScopedSelector("& > ui-option-create"));
let minLength = create?.hasAttribute("min-length") ? parseInt(create.getAttribute("min-length")) : void 0;
setAttribute2(empty, "data-hidden", "");
if (create) setAttribute2(create, "data-hidden", "");
let isHidden = (el) => el.hasAttribute("data-hidden");
let isUnique = (el) => el.textContent.toLowerCase().trim() !== input.value.toLowerCase().trim();
let getItems = () => Array.from(list.querySelectorAll(normalizeScopedSelector("& > ui-option")));
let showLoading = () => {
if (empty.hasAttribute("when-loading")) {
let emptyContent = empty.textContent;
empty.textContent = empty.getAttribute("when-loading");
empty.__hideLoading = () => {
empty.textContent = emptyContent;
empty.__hideLoading = void 0;
};
}
};
let revertDisable;
let debounceEnable;
let refresh = () => {
clearTimeout(revertDisable);
clearTimeout(debounceEnable);
if (input.hasAttribute("data-flux-loading") || input.hasAttribute("data-loading")) return;
let items = getItems();
let isEmpty = items.every((i) => isHidden(i));
if (create) {
if (minLength && input.value.trim().length < minLength) {
setAttribute2(create, "data-hidden", "");
} else {
if (items.every((i) => isUnique(i))) {
removeAttribute(create, "data-hidden");
} else {
setAttribute2(create, "data-hidden", "");
}
}
if (isEmpty) create._activatable.activate(true);
let enable = () => {
removeAttribute(create, "disabled");
};
if (filterable) {
enable();
} else {
debounceEnable = setTimeout(enable, 150);
}
}
if (isEmpty && (!create || isHidden(create))) {
removeAttribute(empty, "data-hidden");
} else {
setAttribute2(empty, "data-hidden", "");
}
empty.__hideLoading?.();
};
if (filterable) {
filterable.onChange(() => refresh());
if (create) {
on(input, "input", () => {
if (minLength && input.value.trim().length < minLength) {
setAttribute2(create, "data-hidden", "");
}
});
}
} else {
let observer = new MutationObserver(() => {
requestAnimationFrame(() => refresh());
});
observer.observe(list, { childList: true });
observer.observe(input, { attributes: true, attributeFilter: ["data-loading", "data-flux-loading"] });
if (create) {
on(input, "input", (e) => {
clearTimeout(revertDisable);
clearTimeout(debounceEnable);
let isEmpty = getItems().every((i) => isHidden(i));
if (isEmpty && input.value.trim() === "" && !isHidden(create)) {
showLoading();
removeAttribute(empty, "data-hidden");
setAttribute2(create, "data-hidden", "");
} else if (input.value.trim() === "" && !isHidden(create)) {
setAttribute2(create, "data-hidden", "");
}
if (minLength && input.value.trim().length >= minLength) {
removeAttribute(create, "data-hidden");
}
setAttribute2(create, "disabled", "");
revertDisable = setTimeout(() => {
removeAttribute(create, "disabled");
if (isEmpty) create._activatable.activate();
}, 200);
});
}
}
refresh();
}
// js/calendar/date.js
var DateValue = class _DateValue {
constructor(year, month, day = 1) {
this._date = new Date(Date.UTC(year, month - 1, day));
}
isBetween(min2, max2) {
if (!min2 && !max2) return true;
if (!min2) return this._date <= max2._date;
if (!max2) return this._date >= min2._date;
return this._date >= min2._date && this._date <= max2._date;
}
isSameDay(date) {
if (!date) return false;
return this._date.getUTCDate() === date._date.getUTCDate() && this._date.getUTCMonth() === date._date.getUTCMonth() && this._date.getUTCFullYear() === date._date.getUTCFullYear();
}
isBefore(date) {
if (!date) return false;
return this._date < date._date;
}
isAfter(date) {
if (!date) return false;
return this._date > date._date;
}
/** Immutable manipulators */
incrementDays(days) {
let copy = this.getCopy();
copy._date.setUTCDate(copy._date.getUTCDate() + days);
return copy;
}
addMonths(months) {
let copy = this.getCopy();
copy._date.setUTCMonth(copy._date.getUTCMonth() + months);
return copy;
}
addDays(days) {
let copy = this.getCopy();
copy._date.setUTCDate(copy._date.getUTCDate() + days);
return copy;
}
/** Getters */
getYear() {
return this._date.getUTCFullYear();
}
getMonth() {
return this._date.getUTCMonth() + 1;
}
getPaddedMonth() {
return String(this.getMonth()).padStart(2, "0");
}
getDay() {
return this._date.getUTCDate();
}
getPaddedDay() {
return String(this.getDay()).padStart(2, "0");
}
getDate() {
return this._date;
}
getCopy() {
return new _DateValue(this.getYear(), this.getMonth(), this.getDay());
}
getDayOfWeek() {
return this._date.getUTCDay();
}
getDaysInMonth() {
return new _DateValue(this.getYear(), this.getMonth() + 1, 0).getDay();
}
getFirstDayOfMonth() {
return new _DateValue(this.getYear(), this.getMonth(), 1).getDayOfWeek();
}
getWeekNumber() {
let firstDayOfYear = new Date(Date.UTC(this._date.getUTCFullYear(), 0, 1));
let firstThursday = new Date(firstDayOfYear);
firstThursday.setUTCDate(1 + (11 - firstDayOfYear.getUTCDay()) % 7);
let targetThursday = new Date(this._date);
targetThursday.setUTCDate(this._date.getUTCDate() + (11 - this._date.getUTCDay()) % 7);
let weeksBetween = Math.floor((targetThursday.getTime() - firstThursday.getTime()) / (7 * 24 * 60 * 60 * 1e3));
return weeksBetween + 1;
}
/** Setters */
setDay(day) {
this._date.setUTCDate(day);
}
setMonth(month) {
this._date.setUTCMonth(month - 1);
}
setYear(year) {
this._date.setUTCFullYear(year);
}
/** Static factories: */
static fromIsoDateString(isoString) {
if (!isoString) return null;
let [year, month, day] = isoString.split("T")[0]?.split("-")?.map(Number);
return new _DateValue(year, month, day);
}
static fromLocalDate(date) {
if (!date) return null;
return new _DateValue(date.getUTCFullYear(), date.getUTCMonth() + 1, date.getUTCDate());
}
static fromDate(date) {
if (!date) return null;
return new _DateValue(date.getFullYear(), date.getMonth() + 1, date.getDate());
}
static fromParts(year, month, day) {
return new _DateValue(year, month, day);
}
static today() {
return _DateValue.fromDate(/* @__PURE__ */ new Date());
}
static firstDayOfMonth(date) {
return new _DateValue(date.getYear(), date.getMonth(), 1);
}
/** Formats */
toIsoDateString() {
return [this.getYear(), this.getPaddedMonth(), this.getPaddedDay()].join("-");
}
toParts() {
return [this.getYear(), this.getMonth(), this.getDay()];
}
toDate() {
return new Date(this.getYear(), this.getMonth() - 1, this.getDay());
}
toFormattedString(locale, options) {
return this.toDate().toLocaleDateString(locale, options);
}
};
// js/calendar/render.js
function renderMonth(monthEl, config, viewState, metadata) {
let headingTemplate = monthEl.querySelector('template[name="heading"]');
let weekdayTemplate = monthEl.querySelector('template[name="weekday"]');
let weekTemplate = monthEl.querySelector('template[name="week"]');
headingTemplate && renderHeading(headingTemplate, config, viewState);
weekdayTemplate && renderWeekdays(weekdayTemplate, config);
weekTemplate && renderDates(weekTemplate, config, viewState, metadata);
}
function renderHeading(template, config, viewState) {
renderTemplate(template, (hydrate) => {
return hydrate({
slots: {
default: new Intl.DateTimeFormat(config.locale, {
month: template.hasAttribute("display") ? template.getAttribute("display") : "long",
year: "numeric",
timeZone: "UTC"
}).format(new DateValue(viewState.year, viewState.month).getDate())
}
});
});
}
function renderWeekdays(template, config) {
let format = (date) => {
if (template.hasAttribute("display")) {
return new Intl.DateTimeFormat(config.locale, { weekday: template.getAttribute("display") }).format(date);
}
let safeTwoCharLocales = ["en", "es", "de", "fr", "it", "pt"];
if (safeTwoCharLocales.includes(config.locale.split("-")[0])) {
let formatter2 = new Intl.DateTimeFormat(config.locale, { weekday: "short" });
return formatter2.format(date).slice(0, 2);
}
let formatter = new Intl.DateTimeFormat(config.locale, { weekday: "narrow" });
return formatter.format(date);
};
let weekdays = Array.from({ length: 7 }, (_, idx) => {
let adjustedIdx = (idx + config.startDay) % 7;
let date = new Date(2024, 0, adjustedIdx + 7);
return format(date);
});
renderTemplate(template, (hydrate) => {
return weekdays.map((weekday) => hydrate({ slots: { default: weekday } }));
});
}
function renderDates(template, config, viewState, metadata) {
let month = viewState.month;
let year = viewState.year;
let firstDay = (new DateValue(year, month).getFirstDayOfMonth() - config.startDay + 7) % 7;
let totalDays = new DateValue(year, month).getDaysInMonth();
let [prevYear, prevMonth] = new DateValue(year, month).addMonths(-1).toParts();
let prevMonthDays = new DateValue(prevYear, prevMonth).getDaysInMonth();
let [displayDates, actualDates] = [[], []];
for (let i = 0; i < firstDay; i++) {
displayDates.push(0);
let prevDate = prevMonthDays - firstDay + i + 1;
actualDates.push(new DateValue(prevYear, prevMonth, prevDate).toIsoDateString());
}
for (let i = 1; i <= totalDays; i++) {
displayDates.push(i);
actualDates.push(new DateValue(year, month, i).toIsoDateString());
}
let totalCells = firstDay + totalDays;
let remainingDays = (7 - totalCells % 7) % 7;
let [nextYear, nextMonth] = new DateValue(year, month).addMonths(1).toParts();
for (let i = 1; i <= remainingDays; i++) {
displayDates.push(0);
actualDates.push(new DateValue(nextYear, nextMonth, i).toIsoDateString());
}
if (config.fixedWeeks) {
let currentWeeks = Math.ceil(displayDates.length / 7);
let targetWeeks = config.fixedWeeks;
let weeksDiff = targetWeeks - currentWeeks;
if (weeksDiff > 0) {
for (let i = 0; i < weeksDiff * 7; i++) {
displayDates.push(0);
actualDates.push(DateValue.fromIsoDateString(actualDates[actualDates.length - 1]).addDays(1).toIsoDateString());
}
} else if (weeksDiff < 0) {
displayDates.length = targetWeeks * 7;
actualDates.length = targetWeeks * 7;
}
}
let splitIntoWeeks = (arr) => Array.from(
{ length: Math.ceil(arr.length / 7) },
(_, idx) => arr.slice(idx * 7, (idx + 1) * 7)
);
let displayWeeks = splitIntoWeeks(displayDates);
let actualWeeks = splitIntoWeeks(actualDates);
renderTemplate(template, (hydrate) => {
return displayWeeks.map((week, weekIdx) => {
let weekEl = hydrate();
let actualWeekDates = actualWeeks[weekIdx];
let numberTemplate = weekEl.querySelector('template[name="number"]');
if (numberTemplate) {
let fourthDayIdx = (4 - config.startDay + 7) % 7;
let weekNumber = DateValue.fromIsoDateString(actualWeekDates[fourthDayIdx]).getWeekNumber();
renderTemplate(numberTemplate, (hydrate2) => {
return hydrate2({ slots: { default: weekNumber } });
});
}
renderTemplate(weekEl.querySelector('template[name="day"]'), (hydrate2) => {
return week.map((day, dayIdx) => {
if (day === 0) {
let weekDate = DateValue.fromIsoDateString(actualWeekDates[dayIdx]);
let dayNumber = weekDate.getDay();
return hydrate2({
slots: { default: dayNumber },
attrs: { "data-date": actualWeekDates[dayIdx], "data-outside": "" }
});
}
let date = DateValue.fromIsoDateString(actualWeekDates[dayIdx]);
let dayEl = hydrate2({
slots: { default: day },
attrs: { "data-date": actualWeekDates[dayIdx] }
});
let subtext = metadata.subtext(date);
let details = metadata.details(date);
let variant = metadata.variant(date);
if (![false, null, void 0].includes(variant)) {
dayEl.dataset.dateVariant = variant;
}
if (![false, null, void 0].includes(subtext)) {
let template2 = dayEl.querySelector('template[name="subtext"]');
template2 && renderTemplate(template2, (hydrate3) => hydrate3({ slots: { default: subtext } }));
}
if (![false, null, void 0].includes(details)) {
let template2 = dayEl.querySelector('template[name="details"]');
template2 && renderTemplate(template2, (hydrate3) => hydrate3({ slots: { default: details } }));
}
return dayEl;
});
});
return weekEl;
});
});
}
function updateMonth(el, disabled, config, viewState, selectable, validator) {
let getFirstDateToMakeTabbable = (month, year) => {
return selectable.lowerBound(() => {
let isCurrentMonth = DateValue.today().getMonth() === month && DateValue.today().getYear() === year;
return isCurrentMonth ? DateValue.today() : new DateValue(year, month);
});
};
let tabbable = getFirstDateToMakeTabbable(viewState.month, viewState.year);
el.querySelectorAll("[data-date]").forEach((cell) => {
setAttribute2(cell, "role", "gridcell");
let button = cell.querySelector("button,ui-button");
let date = dateFromCell(cell);
if (!date) return;
button ? setAttribute2(button, "aria-label", date.toFormattedString(config.locale, { day: "numeric", month: "long", year: "numeric", weekday: "long" })) : setAttribute2(cell, "aria-label", date.toFormattedString(config.locale, { day: "numeric", month: "long", year: "numeric", weekday: "long" }));
if (!validator.isValid(date)) {
setAttribute2(cell, "disabled", "");
setAttribute2(cell, "aria-disabled", "true");
button && setAttribute2(button, "disabled", "");
validator.isUnavailable(date) && setAttribute2(cell, "data-unavailable", "");
} else if (disabled) {
setAttribute2(cell, "disabled", "");
setAttribute2(cell, "aria-disabled", "true");
button && setAttribute2(button, "disabled", "");
} else {
removeAttribute(cell, "disabled");
removeAttribute(cell, "data-unavailable");
removeAttribute(cell, "aria-disabled");
button && removeAttribute(button, "disabled");
}
if (DateValue.today().isSameDay(date)) {
setAttribute2(cell, "data-today", "");
} else {
removeAttribute(cell, "data-today", "");
}
selectable.attributes(cell, date);
if (date.isSameDay(tabbable)) {
button && setAttribute2(button, "tabindex", "0");
} else {
button && setAttribute2(button, "tabindex", "-1");
}
});
}
function renderTemplate(template, callback) {
if (!template) return;
let cleanup = () => {
let sibling = template.nextElementSibling;
while (sibling && sibling.hasAttribute("data-appended")) {
let toRemove = sibling;
sibling = sibling.nextElementSibling;
toRemove.remove();
}
};
cleanup();
let hydrated = callback(({ slots = {}, attrs = {} } = {}) => {
let clone = template.content.cloneNode(true).firstElementChild;
Object.entries(slots).forEach(([key, value3]) => {
let slotNodes = key === "default" ? clone.querySelectorAll("slot:not([name])") : clone.querySelectorAll(`slot[name="${key}"]`);
slotNodes.forEach((i) => i.replaceWith(
typeof value3 === "string" ? document.createTextNode(value3) : value3
));
});
clone.querySelectorAll("slot").forEach((slot) => slot.remove());
Object.entries(attrs).forEach(([key, value3]) => {
clone.setAttribute(key, value3);
});
return clone;
});
hydrated = Array.isArray(hydrated) ? hydrated : [hydrated];
hydrated.reverse().forEach((node) => {
setAttribute2(node, "data-appended", "");
template.after(node);
});
return { cleanup };
}
function dateFromCell(cell) {
if (!cell) return null;
if (!cell.hasAttribute("data-date")) return null;
return DateValue.fromIsoDateString(cell.getAttribute("data-date"));
}
// js/time-picker/selectable.js
var SelectableModes = class {
static SINGLE = "single";
static MULTIPLE = "multiple";
};
var ObservableTrigger = class {
static SELECTION = "selection";
static ACTIVATION = "activation";
static VIEW_CHANGE = "view-change";
};
var Selectable2 = class _Selectable {
constructor(selection, config, observable) {
this.config = config;
this.observable = observable;
this.selection = selection;
}
select(value3) {
let previousSelection = this.selection;
this.selection = this.selection.select(value3, this.config);
if (this.selection.shouldNotify(previousSelection)) this.observable.notify(ObservableTrigger.SELECTION);
else this.observable.notify(ObservableTrigger.ACTIVATION);
}
setValue(value3) {
let previousSelection = this.selection;
this.selection = _Selectable.createSelectionFromValue(value3, this.config);
if (this.selection.shouldNotify(previousSelection)) this.observable.notify(ObservableTrigger.SELECTION);
else this.observable.notify(ObservableTrigger.ACTIVATION);
}
getValue() {
return this.selection.value();
}
isSelectable(value3) {
return this.selection.selectable(value3, this.config);
}
/** Passthrough methods */
contains(...params) {
return this.selection.contains(...params);
}
hasSelection() {
return this.selection.hasSelection();
}
lowerBound(...params) {
return this.selection.lowerBound(...params);
}
upperBound(...params) {
return this.selection.upperBound(...params);
}
display(...params) {
return this.selection.display(this.config, ...params);
}
attributes(...params) {
return this.selection.attributes(...params);
}
static createSelectionFromValue(value3, config) {
if (config.mode === SelectableModes.MULTIPLE) {
value3 ??= [];
return new MultipleSelection(value3);
} else {
if (!value3) return new NoneSelection();
return new SingleSelection(value3);
}
}
static createFromValueStringAttribute(value3, config, observable) {
let selection = _Selectable.createSelectionFromValueStringAttribute(value3, config);
return new _Selectable(selection, config, observable);
}
static createSelectionFromValueStringAttribute(value3, config) {
if (config.mode === SelectableModes.MULTIPLE) {
value3 = value3 ? value3.split(",").map((i) => i.trim()) : [];
}
return _Selectable.createSelectionFromValue(value3, config);
}
};
var Selection = class {
contains() {
}
shouldNotify(previousSelection) {
return true;
}
hasSelection() {
return false;
}
lowerBound(fallback) {
return value(fallback);
}
upperBound(fallback) {
return this.lowerBound(fallback);
}
selectable(value3, config) {
return true;
}
display(config) {
}
value() {
}
attributes(el, value3) {
if (this.contains(value3)) {
setAttribute2(el, "data-selected", "");
setAttribute2(el, "aria-selected", "true");
} else {
removeAttribute(el, "data-selected");
setAttribute2(el, "aria-selected", "false");
}
}
};
var NoneSelection = class _NoneSelection extends Selection {
contains() {
return false;
}
shouldNotify(selection) {
return !(selection instanceof _NoneSelection);
}
hasSelection() {
return false;
}
lowerBound(fallback) {
return value(fallback);
}
select(value3) {
return new SingleSelection(value3);
}
display(config) {
return "";
}
value() {
return null;
}
};
var SingleSelection = class _SingleSelection extends Selection {
constructor(value3) {
super();
this._value = value3;
}
contains(value3) {
return this._value === value3;
}
shouldNotify(previousSelection) {
if (previousSelection instanceof _SingleSelection && this._value === previousSelection._value) return false;
return true;
}
hasSelection() {
return true;
}
lowerBound() {
return this._value;
}
select(value3) {
if (this._value === value3) return new NoneSelection();
return new _SingleSelection(value3);
}
display(config) {
return formatTime(this._value, config.timeFormat, config.locale);
}
value() {
return this._value;
}
};
var MultipleSelection = class _MultipleSelection extends Selection {
constructor(values) {
super();
this._values = values.sort((a, b) => timeInMinutes(a) < timeInMinutes(b) ? -1 : 1);
}
contains(value3) {
return this._values.some((i) => i === value3);
}
shouldNotify(previousSelection) {
if (previousSelection instanceof _MultipleSelection && this._values.every((i) => previousSelection._values.includes(i)) && previousSelection._values.every((i) => this._values.includes(i))) return false;
return true;
}
hasSelection() {
return this._values.length > 0;
}
lowerBound(fallback) {
let sortedValues = this._values.sort((a, b) => timeInMinutes(a) < timeInMinutes(b) ? -1 : 1);
return sortedValues[0] || value(fallback);
}
upperBound(fallback) {
let sortedValues = this._values.sort((a, b) => timeInMinutes(a) < timeInMinutes(b) ? -1 : 1);
return sortedValues[sortedValues.length - 1] || value(fallback);
}
select(value3) {
let containsValue = this._values.some((i) => i === value3);
if (containsValue) return new _MultipleSelection(this._values.filter((i) => i !== value3));
return new _MultipleSelection([...this._values, value3]);
}
display(config) {
return this._values.sort((a, b) => timeInMinutes(a) < timeInMinutes(b) ? -1 : 1).map((i) => formatTime(i, config.timeFormat, config.locale)).join(", ");
}
value() {
return this._values;
}
};
function value(i = null) {
return typeof i === "function" ? i() : i;
}
// js/time-picker/trigger.js
var UITimePickerTrigger = class extends UIElement {
boot() {
this.picker = this.closest("ui-time-picker");
let inputs = this.querySelectorAll("input");
this._disableable = new Disableable(this);
let disableClick = (e) => {
e.preventDefault();
e.stopImmediatePropagation();
};
this._disableable.onInitAndChange((disabled) => {
if (disabled) {
this.addEventListener("click", disableClick, true);
} else {
this.removeEventListener("click", disableClick, true);
}
});
if (inputs.length === 0) return;
if (inputs.length < 2) throw new Error("Time picker inputs missing");
this.hourInput = inputs[0];
this.minuteInput = inputs[1];
this.meridiemInput = inputs[2] || null;
if (this.meridiemInput && this.use24HourFormat()) {
this.meridiemInput.style.display = "none";
this.meridiemInput = null;
}
this._disableable.onInitAndChange((disabled) => {
if (disabled) {
this.hourInput.setAttribute("disabled", "");
this.minuteInput.setAttribute("disabled", "");
this.meridiemInput?.setAttribute("disabled", "");
} else {
this.hourInput.removeAttribute("disabled");
this.minuteInput.removeAttribute("disabled");
this.meridiemInput?.removeAttribute("disabled");
}
});
this.clearInputs();
initCursorSelectionListeners(this.hourInput);
initCursorSelectionListeners(this.minuteInput);
this.meridiemInput && initCursorSelectionListeners(this.meridiemInput);
this.hourInput.addEventListener("keydown", (e) => {
if (e.key === "ArrowRight") return this.minuteInput.focus();
});
this.minuteInput.addEventListener("keydown", (e) => {
if (e.key === "ArrowLeft") return this.hourInput.focus();
if (e.key === "ArrowRight") return this.meridiemInput?.focus();
});
this.meridiemInput?.addEventListener("keydown", (e) => {
if (e.key === "ArrowLeft") return this.minuteInput.focus();
});
blockDefaultInputs(this.hourInput);
blockDefaultInputs(this.minuteInput);
this.meridiemInput && blockDefaultInputs(this.meridiemInput);
this.initHourInputListeners();
this.initMinuteInputListeners();
this.meridiemInput && this.initMeridiemInputListeners();
this.meridiemInput && this.setMeridiemWidthBasedOnLocale();
this.picker.observable.subscribe(ObservableTrigger.SELECTION, () => {
this.updateInputsFromSelectable(this.picker.selectable);
});
this.updateInputsFromSelectable(this.picker.selectable);
}
focus() {
if (this.hourInput) return this.hourInput.focus();
this.querySelector("button,ui-button")?.focus();
}
use24HourFormat() {
if (this.picker.config.timeFormat === "24-hour") return true;
if (this.picker.config.timeFormat === "12-hour") return false;
return localeIs24HourFormat(this.picker.config.locale);
}
processTime() {
let time = getTime(
this.hourInput.value,
this.minuteInput.value,
this.meridiemInput?.value
);
if (!time) return;
this.updateSelectable(time);
this.updateInputsFromSelectable(this.picker.selectable);
}
updateSelectable(time) {
this.picker.selectable.setValue(time);
}
updateInputsFromSelectable(selectable) {
let time = selectable.getValue();
this.updateInputs(time);
}
// Time is in 24 hour format
updateInputs(time) {
if (!time) return this.clearInputs();
let [hours, minutes] = time.split(":");
let meridiem = null;
if (this.meridiemInput) {
hours = parseInt(hours);
meridiem = getLocalisedMeridiem(hours, this.picker.config.locale);
if (hours > 12) {
hours = hours - 12;
} else if (hours === 0) {
hours = 12;
}
hours = hours.toString();
}
this.hourInput.value = hours.padStart(2, "0");
this.minuteInput.value = minutes.padStart(2, "0");
this.meridiemInput && (this.meridiemInput.value = meridiem);
}
clearInputs() {
this.hourInput.value = "--";
this.minuteInput.value = "--";
this.meridiemInput && (this.meridiemInput.value = "--");
}
initHourInputListeners() {
let isEditing = false;
this.hourInput.addEventListener("keydown", (e) => {
if (!["ArrowUp", "ArrowDown"].includes(e.key)) return;
e.preventDefault();
e.stopPropagation();
let number = parseInt(this.hourInput.value);
let currentTime = this.picker.selectable.getValue();
let [hours, minutes] = currentTime?.split(":") || ["00", "00"];
hours = parseInt(hours);
if (e.key === "ArrowUp") {
if (currentTime === null || hours === 23) {
hours = 0;
} else {
hours++;
}
} else if (e.key === "ArrowDown") {
if (currentTime === null || hours === 0) {
hours = 23;
} else {
hours--;
}
}
let newTime = getTime(hours.toString(), minutes);
this.updateSelectable(newTime);
this.updateInputsFromSelectable(this.picker.selectable);
highlightInputContents(this.hourInput);
});
this.hourInput.addEventListener("keydown", (e) => {
if (!/[0-9]/.test(e.key)) return;
let number = parseInt(e.key);
if (this.hourInput.value === "" || this.hourInput.value === "--" || !isEditing) {
isEditing = true;
this.hourInput.value = `0${number}`;
number > 2 ? this.minuteInput.focus() : highlightInputContents(this.hourInput);
return;
}
let existingNumber = parseInt(this.hourInput.value);
if (existingNumber === 2 && (number >= 0 && number <= 3)) {
this.hourInput.value = `${existingNumber}${number}`;
this.minuteInput.focus();
return;
}
if (existingNumber === 1 || existingNumber === 0) {
this.hourInput.value = `${existingNumber}${number}`;
this.minuteInput.focus();
return;
}
this.hourInput.value = `0${number}`;
number > 2 ? this.minuteInput.focus() : highlightInputContents(this.hourInput);
});
this.hourInput.addEventListener("blur", (e) => {
isEditing = false;
this.processTime();
});
}
initMinuteInputListeners() {
let isEditing = false;
this.minuteInput.addEventListener("keydown", (e) => {
if (!["ArrowUp", "ArrowDown"].includes(e.key)) return;
e.preventDefault();
e.stopPropagation();
let number = parseInt(this.minuteInput.value);
if (e.key === "ArrowUp") {
if (isNaN(number) || number === 59) {
number = 0;
} else {
number = number + 1;
}
} else if (e.key === "ArrowDown") {
if (isNaN(number) || number === 0) {
number = 59;
} else {
number = number - 1;
}
}
this.minuteInput.value = number.toString().padStart(2, "0");
this.processTime();
highlightInputContents(this.minuteInput);
});
this.minuteInput.addEventListener("keydown", (e) => {
if (!/[0-9]/.test(e.key)) return;
let number = parseInt(e.key);
if (this.minuteInput.value === "" || this.minuteInput.value === "--" || !isEditing) {
isEditing = true;
this.minuteInput.value = `0${number}`;
this.processTime();
number > 5 ? this.meridiemInput?.focus() : highlightInputContents(this.minuteInput);
return;
}
let existingNumber = parseInt(this.minuteInput.value);
if (existingNumber <= 5) {
this.minuteInput.value = `${existingNumber}${number}`;
this.processTime();
this.meridiemInput?.focus();
return;
}
this.minuteInput.value = `0${number}`;
this.processTime();
number > 5 ? this.meridiemInput?.focus() : highlightInputContents(this.minuteInput);
});
this.minuteInput.addEventListener("blur", (e) => {
isEditing = false;
this.processTime();
});
}
initMeridiemInputListeners() {
this.meridiemInput?.addEventListener("keydown", (e) => {
if (!["ArrowUp", "ArrowDown"].includes(e.key)) return;
e.preventDefault();
e.stopPropagation();
let value3 = this.meridiemInput.value;
if (e.key === "ArrowUp") {
if (value3 === "" || value3 === "AM") {
value3 = "PM";
} else {
value3 = "AM";
}
} else if (e.key === "ArrowDown") {
if (value3 === "" || value3 === "PM") {
value3 = "AM";
} else {
value3 = "PM";
}
}
this.meridiemInput.value = value3;
this.processTime();
highlightInputContents(this.meridiemInput);
});
this.meridiemInput?.addEventListener("keydown", (e) => {
if (!["a", "p", "A", "P"].includes(e.key)) return;
if (e.key === "a" || e.key === "A") {
this.meridiemInput.value = "AM";
} else if (e.key === "p" || e.key === "P") {
this.meridiemInput.value = "PM";
}
this.processTime();
highlightInputContents(this.meridiemInput);
});
}
// Not all locales have the same width meridiem, like US is `AM` but Canada is `a.m.`,
// so we need to calculate the width based on the locale...
setMeridiemWidthBasedOnLocale() {
let meridiem = getLocalisedMeridiem(12, this.picker.config.locale);
if (!meridiem) return;
this.meridiemInput.style.width = `calc(${meridiem.length}ch + 2px)`;
}
};
function initCursorSelectionListeners(input) {
input.addEventListener("focus", (e) => {
highlightInputContents(input);
});
input.addEventListener("mousedown", (e) => {
highlightInputContents(input);
});
input.addEventListener("mouseup", (e) => {
e.preventDefault();
highlightInputContents(input);
});
}
function blockDefaultInputs(input) {
input.addEventListener("keydown", (e) => {
if (e.ctrlKey || e.metaKey || e.altKey) return;
if (["Tab"].includes(e.key)) return;
e.preventDefault();
});
}
function highlightInputContents(input) {
input.setSelectionRange(0, input.value.length);
}
function getLocalisedMeridiem(hours, locale) {
let formatter = new Intl.DateTimeFormat(locale, {
hour: "numeric",
hour12: true
});
let parts = formatter.formatToParts(new Date(2024, 0, 1, hours, 0));
let medridiem = parts.find((part) => part.type === "dayPeriod")?.value;
if (medridiem) return medridiem;
return hours >= 12 ? "PM" : "AM";
}
function getTime(hour, minute, meridiem = null) {
if (hour === "--" && minute === "--" && (meridiem === null || meridiem === "--")) return null;
if (meridiem === "PM" && hour === "--") hour = "12";
if (hour === "--") hour = "00";
if (minute === "--") minute = "00";
if (meridiem === "--") meridiem = null;
hour = hour.padStart(2, "0");
minute = minute.padStart(2, "0");
let time = meridiem ? hour + ":" + minute + " " + meridiem : hour + ":" + minute;
return convertTimeStringTo24HourFormat(time);
}
function localeIs24HourFormat(locale) {
let formatter = new Intl.DateTimeFormat(locale, { hour: "numeric" });
let midnight = formatter.format(new Date(2024, 0, 1, 0, 0));
return midnight.startsWith("00");
}
function convertTimeStringTo24HourFormat(time) {
let match = time.trim().match(/^(\d{1,2}):(\d{2})(?:\s*(am|pm|AM|PM))?$/i);
if (!match) throw new Error(`Invalid time string: ${time}`);
let hours = parseInt(match[1], 10);
let minutes = parseInt(match[2], 10);
let meridiem = match[3]?.toUpperCase();
if (minutes > 59 || hours > 23 || meridiem !== "AM" && meridiem !== "PM" && meridiem !== void 0) throw new Error(`Invalid time string: ${time}`);
if (hours >= 13 || hours === 0) {
return `${String(hours).padStart(2, "0")}:${String(minutes).padStart(2, "0")}`;
}
if (meridiem) {
if (hours === 12) {
hours = meridiem === "AM" ? 0 : 12;
} else if (meridiem === "PM") {
hours += 12;
}
}
return `${String(hours).padStart(2, "0")}:${String(minutes).padStart(2, "0")}`;
}
// js/time-picker/index.js
var UITimePicker = class extends UIControl {
boot() {
this.config = {
timeFormat: this.hasAttribute("time-format") ? this.getAttribute("time-format") : "auto",
interval: this.interval(),
min: this.min(),
max: this.max(),
unavailable: this.unavailable(),
openTo: this.openTo(),
locale: this.hasAttribute("locale") ? this.getAttribute("locale") : navigator.language,
mode: this.hasAttribute("multiple") ? SelectableModes.MULTIPLE : SelectableModes.SINGLE,
dropdown: this.hasAttribute("dropdown") && this.getAttribute("dropdown") === "false" ? false : true
};
this.observable = new Observable();
this._controllable = new Controllable(this, { bubbles: true });
this._submittable = new Submittable(this, {
name: this.getAttribute("name"),
value: this.getAttribute("value"),
includeWhenEmpty: false
});
this.selectable = Selectable2.createFromValueStringAttribute(this.getAttribute("value"), this.config, this.observable);
this._controllable.getter(() => this.selectable.getValue());
let detangled = detangle();
this._controllable.setter(detangled((value3) => {
this.selectable.setValue(value3);
}));
this.observable.subscribe(ObservableTrigger.SELECTION, () => {
this._controllable.dispatch();
this.dispatchEvent(new CustomEvent("input", { bubbles: false }));
});
this.observable.subscribe(ObservableTrigger.SELECTION, () => {
this._submittable.update(this.selectable.getValue());
});
this._disableable = new Disableable(this);
if (!this.config.dropdown) return;
let popoverEl = this.querySelector("[popover]");
if (!popoverEl) return;
let triggerEl = this.trigger();
let optionsEl = this.querySelector("ui-time-picker-options");
let optionsId = initOptions(optionsEl, this.config.mode === SelectableModes.MULTIPLE);
this._popoverable = new Popoverable(popoverEl, {
triggers: [triggerEl]
});
this._anchorable = new Anchorable(popoverEl, {
reference: triggerEl,
position: this.hasAttribute("position") ? this.getAttribute("position") : void 0,
gap: this.hasAttribute("gap") ? this.getAttribute("gap") : void 0,
offset: this.hasAttribute("offset") ? this.getAttribute("offset") : void 0,
matchWidth: true
});
this._activatable = new ActivatableGroup(optionsEl, { filter: "data-hidden" });
this._disableable.onInitAndChange((disabled) => {
if (disabled) {
setAttribute2(triggerEl, "disabled", "");
triggerEl.querySelectorAll("button,ui-button").forEach((button) => setAttribute2(button, "disabled", ""));
} else {
removeAttribute(triggerEl, "disabled");
triggerEl.querySelectorAll("button,ui-button").forEach((button) => removeAttribute(button, "disabled"));
}
});
triggerEl.addEventListener("click", (e) => {
this._popoverable.toggle();
triggerEl.focus();
});
triggerEl.querySelectorAll("button,ui-button").forEach((button) => {
initTriggerButton(button, this._popoverable, optionsId);
trackActiveDescendant2(button, this._activatable, this.observable);
});
initPopover2(this, popoverEl, this._popoverable, this._anchorable);
preventScrollWhenPopoverIsOpen2(this, this._popoverable);
controlPopoverWithKeyboard(triggerEl, this._popoverable);
controlPopoverWithEscapeKey(this, this._popoverable);
handleKeyboardNavigation(triggerEl, this._activatable);
handleKeyboardSearchNavigation(triggerEl, this._activatable, this._popoverable);
handleKeyboardSelection(this, triggerEl, this._activatable);
controlActivationWithPopover2(this._popoverable, this._activatable, this.selectable, this.config.openTo);
handlePopoverClosing2(this, this.config.mode, this.observable, this.selectable, this._popoverable);
let observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if (!["interval", "unavailable", "max", "min", "open-to"].includes(mutation.attributeName)) return;
this.config.interval = this.interval();
this.config.unavailable = this.unavailable();
this.config.min = this.min();
this.config.max = this.max();
this.config.openTo = this.openTo();
this.observable.notify(ObservableTrigger.VIEW_CHANGE);
});
});
observer.observe(this, { attributes: true });
}
trigger() {
return this.querySelector("ui-time-picker-trigger");
}
list() {
return this.querySelector("ui-options") || this;
}
clear() {
this.selectable.setValue(null);
}
interval() {
if (this.hasAttribute("interval")) {
return parseInt(this.getAttribute("interval"));
}
return 30;
}
min() {
if (this.hasAttribute("min")) {
let min2 = this.getAttribute("min");
if (min2 === "now") {
return (/* @__PURE__ */ new Date()).toLocaleTimeString("en-US", { hour: "2-digit", minute: "2-digit", hour12: false });
}
if (validateTimeString(min2)) {
return min2;
}
return console.warn(`Invalid min attribute: ${min2}`);
}
return void 0;
}
max() {
if (this.hasAttribute("max")) {
let max2 = this.getAttribute("max");
if (max2 === "now") {
return (/* @__PURE__ */ new Date()).toLocaleTimeString("en-US", { hour: "2-digit", minute: "2-digit", hour12: false });
}
if (validateTimeString(max2)) {
return max2;
}
return console.warn(`Invalid max attribute: ${max2}`);
}
return void 0;
}
unavailable() {
if (this.hasAttribute("unavailable")) {
let unavailable = this.getAttribute("unavailable").split(",").map((i) => i.trim());
if (unavailable.every((i) => i.includes("-") ? validateTimeRangeString(i) : validateTimeString(i))) {
return unavailable;
}
return console.warn(`Invalid unavailable attribute: ${unavailable}`);
}
return [];
}
openTo() {
if (this.hasAttribute("open-to")) {
let openTo = this.getAttribute("open-to");
if (openTo === "now") {
return (/* @__PURE__ */ new Date()).toLocaleTimeString("en-US", { hour: "2-digit", minute: "2-digit", hour12: false });
}
if (validateTimeString(openTo)) {
return openTo;
}
return console.warn(`Invalid open-to attribute: ${openTo}`);
}
return void 0;
}
};
var UISelectedTime = class extends UIElement {
boot() {
this.picker = this.closest("ui-time-picker");
if (!this.querySelector('template[name="time"]')) {
let template = document.createElement("template");
template.setAttribute("name", "time");
template.innerHTML = "<div><slot></slot></div>";
}
this.templates = {
placeholder: this.querySelector('template[name="placeholder"]'),
time: this.querySelector('template[name="time"]')
};
this.picker.observable.subscribe(ObservableTrigger.SELECTION, () => {
this.render(this.picker);
});
this.render(this.picker);
}
mount() {
this.render(this.picker);
}
render(picker) {
this.templates.placeholder?.clearPlaceholder?.();
this.templates.time?.clearTime?.();
if (picker.selectable.hasSelection()) {
let { cleanup } = renderTemplate(this.templates.time, (hydrate) => {
return hydrate({ slots: { default: picker.selectable.display(picker.config.locale) } });
});
this.templates.time.clearTime = cleanup;
} else {
if (!this.templates.placeholder) return;
let { cleanup } = renderTemplate(this.templates.placeholder, (hydrate) => {
return hydrate({ slots: {} });
});
this.templates.placeholder.clearPlaceholder = cleanup;
}
}
};
var UITimePickerOptions = class extends UIElement {
boot() {
this.picker = this.closest("ui-time-picker");
this.render();
this.picker.observable.subscribe(ObservableTrigger.SELECTION, () => {
this.render();
});
this.picker.observable.subscribe(ObservableTrigger.VIEW_CHANGE, () => {
this.render();
});
let { enable: enableListeners, disable: disableListeners } = initializeEventListeners(this, this.picker.selectable);
this.picker._disableable.onInitAndChange((disabled) => {
disabled ? disableListeners() : enableListeners();
});
}
render() {
let template = this.querySelector('template[name="option"]');
if (!template) return;
renderTemplate(template, (hydrate) => {
let times = generateTimes(this.picker.config);
return times.map(({ value: value3, label }) => {
let isDisabled = this.picker.config.unavailable.some((unavailableTime) => timesAreOverlapping(value3, unavailableTime));
let attrs = {
"data-time": value3,
"role": "option"
};
if (isDisabled) attrs.disabled = "";
let el = hydrate({ attrs, slots: { default: label } });
this.picker.selectable.attributes(el, value3);
el._activatable = new Activatable(el);
assignId(el, "option");
return el;
});
});
}
};
element("time-picker", UITimePicker);
element("time-picker-trigger", UITimePickerTrigger);
element("selected-time", UISelectedTime);
element("time-picker-options", UITimePickerOptions);
inject(({ css }) => css`ui-time-picker { display: block; }`);
function initOptions(options, multiple) {
let optionsId = assignId(options, "options");
setAttribute2(options, "role", "listbox");
setAttribute2(options, "aria-multiselectable", multiple ? "true" : "false");
return optionsId;
}
function initTriggerButton(el, popoverable, optionsId) {
setAttribute2(el, "role", "combobox");
setAttribute2(el, "aria-controls", optionsId);
setAttribute2(el, "aria-haspopup", "listbox");
linkExpandedStateToPopover2(el, popoverable);
on(el, "click", (e) => {
e.stopPropagation();
popoverable.setState(!popoverable.getState());
el.focus();
});
}
function initPopover2(root, popover, popoverable, anchorable) {
let refreshPopover = () => {
Array.from([root, popover]).forEach((i) => {
popoverable.getState() ? setAttribute2(i, "data-open", "") : removeAttribute(i, "data-open", "");
});
popoverable.getState() ? anchorable.reposition() : anchorable.cleanup();
};
popoverable.onChange(() => refreshPopover());
refreshPopover();
popoverable.onChange(() => {
if (popoverable.getState()) {
root.dispatchEvent(new Event("open", {
bubbles: false,
cancelable: false
}));
} else {
root.dispatchEvent(new Event("close", {
bubbles: false,
cancelable: false
}));
}
});
}
function preventScrollWhenPopoverIsOpen2(root, popoverable) {
let { lock, unlock } = lockScroll(popoverable.el);
popoverable.onChange(() => {
popoverable.getState() ? lock() : unlock();
});
}
function linkExpandedStateToPopover2(el, popoverable) {
setAttribute2(el, "aria-haspopup", "listbox");
let refreshPopover = () => {
setAttribute2(el, "aria-expanded", popoverable.getState() ? "true" : "false");
popoverable.getState() ? setAttribute2(el, "data-open", "") : removeAttribute(el, "data-open", "");
};
popoverable.onChange(() => {
refreshPopover();
});
refreshPopover();
}
function trackActiveDescendant2(el, activatable) {
activatable.onChange(() => {
let activeEl = activatable.getActive();
activeEl ? setAttribute2(el, "aria-activedescendant", activeEl.id) : removeAttribute(el, "aria-activedescendant");
});
}
function handlePopoverClosing2(root, mode, observable, selectable, popoverable) {
if (mode === SelectableModes.MULTIPLE) return;
observable.subscribe(ObservableTrigger.SELECTION, () => {
if (selectable.hasSelection()) {
popoverable.setState(false);
}
});
}
function initializeEventListeners(el, selectable) {
let blocked = false;
let readonly = el.hasAttribute("readonly");
on(el, "click", (e) => {
if (blocked || readonly) return;
let option = e.target.closest("[data-time]");
if (!option) return;
let time = option.getAttribute("data-time");
setTimeout(() => {
validateTimeString(time) && selectable.select(time);
});
});
return {
enable: () => {
},
disable: () => {
}
};
}
function validateTimeString(time) {
return new RegExp(`^${timeRegex()}$`).test(time);
}
function validateTimeRangeString(time) {
return new RegExp(`^${timeRegex()}-${timeRegex()}$`).test(time);
}
function timeRegex() {
return "([01]?[0-9]|2[0-3]):[0-5][0-9]";
}
function timesAreOverlapping(first, second) {
let [firstStart, firstEnd] = first.split("-").map((t) => {
let [hours, minutes] = t.split(":").map(Number);
return hours * 60 + minutes;
});
let [secondStart, secondEnd] = second.split("-").map((t) => {
let [hours, minutes] = t.split(":").map(Number);
return hours * 60 + minutes;
});
if (isNaN(firstEnd)) firstEnd = firstStart;
if (isNaN(secondEnd)) secondEnd = secondStart;
return !(firstEnd < secondStart || firstStart > secondEnd);
}
function formatTime(time, timeFormat, locale) {
let [hours, minutes] = time.split(":").map(Number);
let hour12Map = {
"12-hour": true,
"24-hour": false,
"auto": void 0
};
let formatter = new Intl.DateTimeFormat(locale, {
hour: "numeric",
minute: "numeric",
hour12: hour12Map[timeFormat]
});
return formatter.format(new Date(2024, 0, 1, hours, minutes));
}
function timeInMinutes(time) {
if (!time) return null;
let [hours, minutes] = time.split(":");
if (isNaN(hours) || isNaN(minutes)) return null;
return parseInt(hours) * 60 + parseInt(minutes);
}
function controlActivationWithPopover2(popoverable, activatable, selectable, openTo = null) {
popoverable.onChange(() => {
if (popoverable.getState()) {
let selectedValues = selectable.getValue();
if (!Array.isArray(selectedValues)) {
selectedValues = selectedValues === null ? [] : [selectedValues];
}
let selectables = activatable.filterAwareWalker();
let firstSelectedOption = selectables.find((el) => selectedValues.includes(el.getAttribute("data-time")));
let firstOptionToActivate = null;
if (!firstSelectedOption && openTo) {
firstOptionToActivate = findCloestOptionToOpenTo(activatable, openTo);
}
setTimeout(() => {
let optionToScrollTo = firstSelectedOption || firstOptionToActivate;
activatable.activateSelectedOrFirst(optionToScrollTo);
optionToScrollTo?.scrollIntoView({ block: "nearest" });
});
} else {
activatable.clearActive();
}
});
}
function findCloestOptionToOpenTo(activatable, openTo) {
let openToInMinutes = timeInMinutes(openTo);
let closestOption = null;
let closestOptionTimeInMinutes = null;
activatable.filterAwareWalker().walk((option, bail) => {
let optionTime = option.getAttribute("data-time");
let optionTimeInMinutes = timeInMinutes(optionTime);
if (optionTimeInMinutes > openToInMinutes) return;
if (Math.abs(optionTimeInMinutes - openToInMinutes) < Math.abs(closestOptionTimeInMinutes - openToInMinutes)) {
closestOption = option;
closestOptionTimeInMinutes = optionTimeInMinutes;
}
});
return closestOption;
}
function generateTimes({ interval = 30, timeFormat = "auto", locale = navigator.language, min: min2, max: max2 } = {}) {
let times = [];
let minInMinutes = 0;
let maxInMinutes = 24 * 60 - 1;
if (min2) {
let minDate = new Date(2024, 0, 1);
let [minHours, minMinutes] = min2.split(":");
minDate.setHours(minHours, minMinutes);
minInMinutes = minDate.getHours() * 60 + minDate.getMinutes();
}
if (max2) {
let maxDate = new Date(2024, 0, 1, 23, 59, 59);
let [maxHours, maxMinutes] = max2.split(":");
maxDate.setHours(maxHours, maxMinutes);
maxInMinutes = maxDate.getHours() * 60 + maxDate.getMinutes();
}
for (let minutes = minInMinutes; minutes <= maxInMinutes; minutes += interval) {
let hours = Math.floor(minutes / 60);
let mins = minutes % 60;
let value3 = `${String(hours).padStart(2, "0")}:${String(mins).padStart(2, "0")}`;
let label = formatTime(value3, timeFormat, locale);
times.push({ value: value3, label });
}
return times;
}
// js/mixins/disclosable.js
var Disclosable = class extends Mixin {
boot({ options }) {
this.onChanges = [];
this.state = false;
}
onChange(callback) {
this.onChanges.push(callback);
}
getState() {
return this.state;
}
setState(value3) {
let oldState = this.state;
this.state = !!value3;
if (this.state !== oldState) {
this.onChanges.forEach((i) => i());
}
}
};
// js/disclosure.js
var UIDisclosure = class extends UIElement {
boot() {
let button = this.button();
let details = this.details();
if (!button) {
return console.warn("ui-disclosure: no trigger element found", this);
} else if (!details) {
return console.warn("ui-disclosure: no panel element found", this);
}
this._disabled = this.hasAttribute("disabled");
this._controllable = new Controllable(this, { disabled: this._disabled });
details._disclosable = new Disclosable(details);
this._controllable.initial((initial) => initial && details._disclosable.setState(true));
this._controllable.getter(() => details._disclosable.getState());
this._controllable.setter((value3) => details._disclosable.setState(value3));
details._disclosable.onChange(() => {
this.dispatchEvent(new CustomEvent("lofi-disclosable-change", { bubbles: true }));
this._controllable.dispatch();
});
let refresh = () => {
if (details._disclosable.getState()) {
setAttribute2(this, "data-open", "");
setAttribute2(button, "data-open", "");
setAttribute2(details, "data-open", "");
} else {
removeAttribute(this, "data-open");
removeAttribute(button, "data-open");
removeAttribute(details, "data-open");
}
};
details._disclosable.onChange(() => refresh());
refresh();
if (!this._disabled) {
on(button, "click", (e) => {
details._disclosable.setState(!details._disclosable.getState());
});
}
let id = assignId(details, "disclosure");
setAttribute2(button, "aria-controls", id);
setAttribute2(button, "aria-expanded", "false");
details._disclosable.onChange(() => {
details._disclosable.getState() ? setAttribute2(button, "aria-expanded", "true") : setAttribute2(button, "aria-expanded", "false");
});
if (this.hasAttribute("open")) {
details._disclosable.setState(true);
}
}
button() {
return this.querySelector("button,ui-button");
}
details() {
return this.lastElementChild;
}
};
var UIDisclosureGroup = class _UIDisclosureGroup extends UIElement {
boot() {
this.exclusive = this.hasAttribute("exclusive");
if (this.exclusive) {
on(this, "lofi-disclosable-change", (e) => {
e.stopPropagation();
if (e.target.localName === "ui-disclosure" && e.target.value) {
this.disclosureWalker().each((el) => {
if (el === e.target) return;
el.value = false;
});
}
});
}
}
disclosureWalker() {
return walker(this, (el, { skip, reject }) => {
if (el instanceof _UIDisclosureGroup && el !== this) return reject();
if (el.localName !== "ui-disclosure") return reject();
});
}
};
inject(({ css }) => css`ui-disclosure { display: block; }`);
element("disclosure", UIDisclosure);
element("disclosure-group", UIDisclosureGroup);
// js/resizable.js
var UIResizable = class extends UIElement {
boot() {
}
};
var UIGrip = class extends UIElement {
boot() {
let dimension = this.hasAttribute("resize") ? this.getAttribute("resize") : "both";
let shrink = this.hasAttribute("shrink");
let container = this.closest("ui-resizable");
let maxWidth, maxHeight;
let hasAttemptedAResizeYet = false;
if (!container) throw "Resizable container not found";
this.addEventListener("pointerdown", (e) => {
if (!hasAttemptedAResizeYet) {
maxWidth = container.offsetWidth;
maxHeight = container.offsetHeight;
hasAttemptedAResizeYet = true;
}
let startX = e.clientX;
let startY = e.clientY;
let startWidth = parseInt(getComputedStyle(container).width, 10);
let startHeight = parseInt(getComputedStyle(container).height, 10);
let resize = (e2) => {
let width = startWidth + (e2.clientX - startX);
let height = startHeight + (e2.clientY - startY);
if (dimension === "width" || dimension === "both") {
if (shrink) {
container.style.width = `${Math.min(width, maxWidth)}px`;
} else {
container.style.width = `${width}px`;
}
}
if (dimension === "height" || dimension === "both") {
if (shrink) {
container.style.height = `${Math.min(height, maxHeight)}px`;
} else {
container.style.height = `${height}px`;
}
}
};
document.addEventListener("pointermove", resize);
document.addEventListener("pointerup", () => {
this.releasePointerCapture(e.pointerId);
document.removeEventListener("pointermove", resize);
}, { once: true });
this.setPointerCapture(e.pointerId);
});
}
};
inject(({ css }) => css`ui-resizable { display: block; }`);
element("resizable", UIResizable);
element("grip", UIGrip);
// js/checkbox.js
var UICheckboxGroup = class _UICheckboxGroup extends UIControl {
boot() {
this._disableable = new Disableable(this);
let undoDisableds = [];
this._disableable.onInitAndChange((disabled) => {
if (disabled) {
this.walker().each((el) => {
if (!el.hasAttribute("disabled")) {
el.setAttribute("disabled", "");
undoDisableds.push(() => el.removeAttribute("disabled"));
}
});
} else {
undoDisableds.forEach((fn) => fn());
undoDisableds = [];
}
});
this._selectable = new SelectableGroup(this, { multiple: true });
this._controllable = new Controllable(this, { disabled: this._disabled, bubbles: true });
this.walker().each((el) => {
el.addEventListener("input", (e) => e.stopPropagation());
el.addEventListener("change", (e) => e.stopPropagation());
});
this._submittable = new Submittable(this, {
name: this.getAttribute("name"),
value: this.getAttribute("value"),
includeWhenEmpty: false
});
this._controllable.initial((initial) => initial && this._selectable.setState(initial));
this._controllable.getter(() => this._selectable.getState());
this._detangled = detangle();
this._controllable.setter(this._detangled((value3) => {
this._selectable.setState(value3);
}));
this._selectable.onChange(this._detangled(() => {
this._controllable.dispatch();
}));
this._selectable.onInitAndChange(() => {
this._submittable.update(this._selectable.getState());
});
setAttribute2(this, "role", "group");
queueMicrotask(() => {
this._submittable.update(this._selectable.getState());
});
}
initCheckAll(checkAll) {
let detangled = detangle();
checkAll._selectable.onChange(detangled(() => {
if (checkAll.indeterminate) {
this._selectable.selectAll();
checkAll.checked = true;
checkAll.indeterminate = false;
} else if (checkAll.checked) {
this._selectable.selectAll();
checkAll.checked = true;
checkAll.indeterminate = false;
} else {
this._selectable.deselectAll();
checkAll.checked = false;
checkAll.indeterminate = false;
}
}));
let setCheckAllIndeterminate = () => {
if (this._selectable.allAreSelected()) {
checkAll.indeterminate = false;
checkAll._selectable.select();
} else if (this._selectable.noneAreSelected()) {
checkAll.indeterminate = false;
checkAll._selectable.deselect();
} else {
checkAll.indeterminate = true;
}
};
this._selectable.onChange(detangled(() => {
setCheckAllIndeterminate();
}));
setCheckAllIndeterminate();
}
walker() {
return walker(this, (el, { skip, reject }) => {
if (el instanceof _UICheckboxGroup) return reject();
if (!(el.localName === "ui-checkbox")) return skip();
});
}
};
var UICheckbox = class extends UIControl {
boot() {
let button = this;
this.isIndeterminate = false;
this._disableable = new Disableable(this);
if (this.hasAttribute("all")) {
this._selectable = new Selectable(button, {
ungrouped: true,
toggleable: true,
value: this.hasAttribute("value") ? this.getAttribute("value") : Math.random().toString(36).substring(2, 10),
label: this.hasAttribute("label") ? this.getAttribute("label") : null,
selectedInitially: this.hasAttribute("checked"),
dataAttr: "data-checked",
ariaAttr: "aria-checked"
});
queueMicrotask(() => {
this.closest("ui-checkbox-group")?.initCheckAll(this);
});
} else {
this._selectable = new Selectable(button, {
toggleable: true,
dataAttr: "data-checked",
ariaAttr: "aria-checked",
value: this.hasAttribute("value") ? this.getAttribute("value") : Math.random().toString(36).substring(2, 10),
label: this.hasAttribute("label") ? this.getAttribute("label") : null,
selectedInitially: this.hasAttribute("checked")
});
this._submittable = new Submittable(this, {
name: this.getAttribute("name"),
value: this.getAttribute("value") ?? "on",
// Default value for checkboxes...
includeWhenEmpty: false,
shouldUpdateValue: false
});
this._selectable.onChange(() => {
if (this.indeterminate) this.indeterminate = false;
});
this._selectable.onInitAndChange(() => {
this._submittable.update(this._selectable.isSelected());
});
this.value = this._selectable.getValue();
queueMicrotask(() => {
this._submittable.update(this._selectable.isSelected());
});
}
this._detangled = detangle();
this._selectable.onChange(this._detangled(() => {
this.dispatchEvent(new Event("input", { bubbles: true, cancelable: true }));
this.dispatchEvent(new Event("change", { bubbles: true, cancelable: true }));
}));
setAttribute2(button, "role", "checkbox");
this._disableable.onInitAndChange((disabled) => {
disabled ? removeAttribute(button, "tabindex", "0") : setAttribute2(button, "tabindex", "0");
});
on(button, "click", this._disableable.disabled((e) => {
e.preventDefault();
e.stopPropagation();
}), { capture: true });
on(button, "click", this._disableable.enabled((e) => {
this._selectable.press();
}));
on(button, "keydown", this._disableable.enabled((e) => {
if (e.key === "Enter") {
this.closest("form")?.requestSubmit();
}
}));
on(button, "keydown", this._disableable.enabled((e) => {
if (e.key === " ") {
e.preventDefault();
e.stopPropagation();
}
}));
on(button, "keyup", this._disableable.enabled((e) => {
if (e.key === " ") {
this._selectable.press();
e.preventDefault();
e.stopPropagation();
}
}));
respondToLabelClick(button);
}
get checked() {
return this._selectable.isSelected();
}
set checked(value3) {
let groupDetangled = this.closest("ui-checkbox-group")?._detangled || ((i) => i);
this._detangled(groupDetangled(() => {
value3 ? this._selectable.select() : this._selectable.deselect();
}))();
}
get indeterminate() {
return this.isIndeterminate;
}
set indeterminate(value3) {
this.isIndeterminate = !!value3;
if (this.isIndeterminate) {
setAttribute2(this, "data-indeterminate", "");
} else {
removeAttribute(this, "data-indeterminate");
}
}
};
element("checkbox-group", UICheckboxGroup);
element("checkbox", UICheckbox);
inject(({ css }) => css`ui-checkbox-group { display: block; }`);
inject(({ css }) => css`ui-checkbox { display: inline-block; user-select: none; }`);
function respondToLabelClick(el) {
el.closest("label")?.addEventListener("click", (e) => {
if (!el.contains(e.target)) {
el._selectable.press();
}
});
}
// js/dropdown.js
var UIDropdown = class extends UIElement {
boot() {
let trigger = this.trigger();
let overlay = this.overlay();
if (!trigger) {
return console.warn("ui-dropdown: no trigger element found", this);
} else if (!overlay) {
return console.warn("ui-dropdown: no [popover] overlay found", this);
}
this._disabled = this.hasAttribute("disabled");
this._controllable = new Controllable(this);
overlay._popoverable = new Popoverable(overlay);
overlay._anchorable = new Anchorable(overlay, {
reference: trigger,
position: this.hasAttribute("position") ? this.getAttribute("position") : void 0,
gap: this.hasAttribute("gap") ? this.getAttribute("gap") : void 0,
offset: this.hasAttribute("offset") ? this.getAttribute("offset") : void 0
});
overlay._popoverable.onChange(() => {
overlay._popoverable.getState() ? overlay._anchorable.reposition() : overlay._anchorable.cleanup();
});
if (!this.hasAttribute("hover")) {
let { lock, unlock } = lockScroll(overlay._popoverable.el);
overlay._popoverable.onChange(() => {
overlay._popoverable.getState() ? lock() : unlock();
});
}
this._controllable.initial((initial) => overlay._popoverable.setState(initial));
this._controllable.getter(() => overlay._popoverable.getState());
let detangled = detangle();
this._controllable.setter((value3) => overlay._popoverable.setState(value3));
overlay._popoverable.onChange(detangled(() => this._controllable.dispatch()));
if (this.hasAttribute("hover")) {
let off = () => {
};
interest(trigger, overlay, {
gain() {
overlay._popoverable.setState(true);
let listener = on(document, "scroll", () => {
if (overlay._popoverable.getState()) {
overlay._popoverable.setState(false);
off();
}
});
off = listener.off;
},
lose() {
overlay._popoverable.setState(false);
off();
},
focusable: false
});
}
on(trigger, "click", () => overlay._popoverable.toggle());
if (overlay._popoverable.getState()) {
setAttribute2(this, "data-open", "");
setAttribute2(trigger, "data-open", "");
setAttribute2(overlay, "data-open", "");
} else {
removeAttribute(this, "data-open");
removeAttribute(trigger, "data-open");
removeAttribute(overlay, "data-open");
}
overlay._popoverable.onChange(() => {
if (overlay._popoverable.getState()) {
setAttribute2(this, "data-open", "");
setAttribute2(trigger, "data-open", "");
setAttribute2(overlay, "data-open", "");
} else {
removeAttribute(this, "data-open");
removeAttribute(trigger, "data-open");
removeAttribute(overlay, "data-open");
}
});
let id = assignId(overlay, "dropdown");
setAttribute2(trigger, "aria-haspopup", "true");
setAttribute2(trigger, "aria-controls", id);
setAttribute2(trigger, "aria-expanded", overlay._popoverable.getState() ? "true" : "false");
overlay._popoverable.onChange(() => {
setAttribute2(trigger, "aria-expanded", overlay._popoverable.getState() ? "true" : "false");
});
overlay._popoverable.onChange(() => {
setTimeout(
() => overlay._popoverable.getState() ? overlay.onPopoverShow?.() : overlay.onPopoverHide?.()
);
});
}
unmount() {
if (this.overlay()?._popoverable?.getState() && !this.hasAttribute("hover")) {
let { unlock } = lockScroll();
unlock();
}
}
trigger() {
return this.querySelector("button,ui-button,a");
}
overlay() {
return this.lastElementChild?.matches("[popover]") && this.lastElementChild;
}
};
element("dropdown", UIDropdown);
// js/file-upload.js
var UIFileUpload = class extends UIElement {
boot() {
this.type = "file";
}
mount() {
this._disableable = new Disableable(this);
this._files = [];
this.inputEl = this.querySelector('input[data-slot="receiver"]');
if (this.inputEl) {
this.forwardAcceptAttribute();
this.configureSRInput();
}
this.triggerEl = this.findTriggerElement();
this.rootEl = this.closest("ui-file-upload");
let hasMultiple = this.hasAttribute("multiple") || this.rootEl && this.rootEl.hasAttribute("multiple");
if (hasMultiple) {
setAttribute2(this.inputEl, "multiple", "");
}
Object.defineProperty(this, "multiple", {
get() {
return hasMultiple;
}
});
Object.defineProperty(this, "files", {
get() {
return this._files;
},
set(newValue) {
if (newValue === null || newValue === "") {
this._files = [];
} else if (Array.isArray(newValue)) {
this._files = newValue;
} else if (newValue instanceof FileList) {
this._files = Array.from(newValue);
} else {
this._files = [newValue];
}
this.dispatchEvent(new Event("change", { bubbles: true }));
}
});
this.observer = new MutationObserver(() => {
this.ensureInputsExist();
});
this.observer.observe(this, { childList: true });
this.style.setProperty("--flux-file-upload-progress", "0%");
this.style.setProperty("--flux-file-upload-progress-as-string", "'0%'");
on(this, "livewire-upload-start", () => {
setAttribute2(this, "data-loading", "");
this.disabled = true;
this.style.setProperty("--flux-file-upload-progress", "0");
this.style.setProperty("--flux-file-upload-progress-as-string", "'0%'");
});
on(this, "livewire-upload-finish", () => {
removeAttribute(this, "data-loading");
this.disabled = false;
this.style.setProperty("--flux-file-upload-progress", "100%");
this.style.setProperty("--flux-file-upload-progress-as-string", "'100%'");
});
on(this, "livewire-upload-cancel", () => {
removeAttribute(this, "data-loading");
this.disabled = false;
this.style.setProperty("--flux-file-upload-progress", "0%");
this.style.setProperty("--flux-file-upload-progress-as-string", "'0%'");
});
on(this, "livewire-upload-error", () => {
removeAttribute(this, "data-loading");
this.disabled = false;
this.style.setProperty("--flux-file-upload-progress", "0%");
this.style.setProperty("--flux-file-upload-progress-as-string", "'0%'");
});
on(this, "livewire-upload-progress", (e) => {
let percentage = e.detail.progress;
this.style.setProperty("--flux-file-upload-progress", `${percentage}%`);
this.style.setProperty("--flux-file-upload-progress-as-string", `'${percentage}%'`);
});
this._disableable.onInitAndChange((disabled) => {
this.inputEl.disabled = disabled;
if (this.triggerEl) {
if (disabled) {
removeAttribute(this.triggerEl, "tabindex");
} else {
setAttribute2(this.triggerEl, "tabindex", "0");
}
}
});
on(this.inputEl, "click", (e) => {
e.stopPropagation();
this.clear();
});
this.initDragListeners();
this.initClickListeners();
}
addFiles(newFiles) {
let files = Array.from(newFiles);
let hasMultiple = this.multiple;
if (hasMultiple) {
this._files = [...this._files, ...files];
} else {
this._files = files.slice(0, 1);
}
this.dispatchEvent(new Event("change", { bubbles: true }));
}
removeFile(index) {
this._files = this._files.filter((_, i) => i !== index);
this.dispatchEvent(new Event("change", { bubbles: true }));
}
clear() {
this.inputEl.value = null;
this._files = [];
}
forwardAcceptAttribute() {
if (this.hasAttribute("accept")) {
this.inputEl.setAttribute("accept", this.getAttribute("accept"));
}
}
configureSRInput() {
this.inputEl.tabIndex = -1;
Object.assign(this.inputEl.style, {
position: "absolute",
width: "1px",
height: "1px",
padding: "0",
margin: "-1px",
overflow: "hidden",
clip: "rect(0, 0, 0, 0)",
whiteSpace: "nowrap",
border: "0"
});
}
findTriggerElement() {
let children = Array.from(this.children);
return children.find((child) => !child.hasAttribute("data-slot"));
}
ensureInputsExist() {
if (!this.inputEl || !this.querySelector('input[data-slot="receiver"]')) {
this.inputEl = this.querySelector('input[data-slot="receiver"]');
if (this.inputEl) {
this.configureSRInput();
let hasMultiple = this.hasAttribute("multiple") || this.rootEl && this.rootEl.hasAttribute("multiple");
if (hasMultiple) {
setAttribute2(this.inputEl, "multiple", "");
}
this.inputEl.disabled = this.disabled;
}
}
if (!this.triggerEl || !this.contains(this.triggerEl)) {
this.triggerEl = this.findTriggerElement();
if (this.triggerEl && !this.disabled) {
setAttribute2(this.triggerEl, "tabindex", "0");
} else if (this.triggerEl && this.disabled) {
removeAttribute(this.triggerEl, "tabindex");
}
}
}
initDragListeners() {
if (!this.triggerEl) return;
on(this.triggerEl, "dragenter", this._disableable.enabled((e) => {
e.preventDefault();
setAttribute2(this, "data-dragging", "");
this.clear();
}));
on(this.triggerEl, "dragover", this._disableable.enabled((e) => {
e.preventDefault();
setAttribute2(this, "data-dragging", "");
}));
on(this.triggerEl, "drop", this._disableable.enabled((e) => {
e.preventDefault();
removeAttribute(this, "data-dragging");
if (e.dataTransfer.files && e.dataTransfer.files.length > 0) {
this.addFiles(e.dataTransfer.files);
}
}));
on(this.triggerEl, "dragleave", (e) => {
removeAttribute(this, "data-dragging");
});
}
initClickListeners() {
if (!this.triggerEl) return;
on(this.triggerEl, "click", this._disableable.disabled((e) => {
e.preventDefault();
e.stopPropagation();
}), { capture: true });
on(this.triggerEl, "click", this._disableable.enabled((e) => {
e.preventDefault();
this.inputEl.click();
}));
on(this.inputEl, "change", (e) => {
e.stopPropagation();
if (this.inputEl.files && this.inputEl.files.length > 0 && !this.disabled) {
this.addFiles(this.inputEl.files);
}
});
on(this.triggerEl, "keydown", this._disableable.enabled((e) => {
if (["Enter", " "].includes(e.key)) {
e.preventDefault();
}
if (["Enter"].includes(e.key)) {
this.inputEl.click();
}
}));
on(this.triggerEl, "keyup", this._disableable.enabled((e) => {
if (e.key === " ") {
e.preventDefault();
this.inputEl.click();
}
}));
on(this.triggerEl, "focus", this._disableable.enabled(() => {
setAttribute2(this, "data-focus", "");
}));
on(this.triggerEl, "blur", () => {
removeAttribute(this, "data-focus");
});
}
};
element("file-upload", UIFileUpload);
// js/calendar/observable.js
var ObservableTrigger2 = class {
static SELECTION = 1;
static ACTIVATION = 2;
static VIEW_CHANGE = 3;
};
var Observable2 = class {
constructor() {
this.subscribers = [];
this.subscriberTypes = /* @__PURE__ */ new WeakMap();
}
subscribe(type, callback) {
let types = Array.isArray(type) ? type : [type];
this.subscribers.push(callback);
if (!this.subscriberTypes.has(callback)) this.subscriberTypes.set(callback, []);
this.subscriberTypes.get(callback).push(...types);
}
notify(type) {
let types = Array.isArray(type) ? type : [type];
this.subscribers.forEach((callback) => {
if (types.length && !this.subscriberTypes.get(callback)?.some((t) => types.includes(t))) return;
callback();
});
}
};
// js/calendar/selectable.js
var CalendarModes = class {
static SINGLE = "single";
static MULTIPLE = "multiple";
static RANGE = "range";
};
var Selectable3 = class _Selectable {
constructor(selection, config, observable) {
this.config = config;
this.observable = observable;
this.selection = selection;
this.active = null;
this.displayResolver = (i) => i;
}
setDisplayResolver(resolver) {
this.displayResolver = resolver;
}
select(date) {
let previousSelection = this.selection;
this.selection = this.selection.select(date, this.config);
if (this.selection.shouldNotify(previousSelection)) this.observable.notify(ObservableTrigger2.SELECTION);
else this.observable.notify(ObservableTrigger2.ACTIVATION);
}
activate(date) {
let memo = this.active;
if (!date) {
this.active = null;
} else {
this.active = date;
}
this.selection.activate(date);
if (memo !== this.active) this.observable.notify(ObservableTrigger2.ACTIVATION);
}
setValue(value3) {
let previousSelection = this.selection;
this.selection = this.createSelectionFromValue(value3, this.config);
if (this.selection.shouldNotify(previousSelection)) this.observable.notify(ObservableTrigger2.SELECTION);
else this.observable.notify(ObservableTrigger2.ACTIVATION);
}
getValue() {
return this.selection.value();
}
isSelectable(date) {
return this.selection.selectable(date, this.config);
}
/** Passthrough methods */
contains(...params) {
return this.selection.contains(...params);
}
hasSelection() {
return this.selection.hasSelection();
}
lowerBound(...params) {
return this.selection.lowerBound(...params);
}
upperBound(...params) {
return this.selection.upperBound(...params);
}
display(...params) {
return this.displayResolver(this.selection.display(...params));
}
attributes(...params) {
return this.selection.attributes(...params);
}
createSelectionFromValue(value3, config) {
if (config.mode === CalendarModes.MULTIPLE) {
let dates = value3 ? value3.map((i) => DateValue.fromIsoDateString(i)) : [];
return new MultipleSelection2(dates);
} else if (config.mode === CalendarModes.RANGE) {
let { start, end, preset } = value3 || {};
if (preset && presets[preset] && preset !== "custom") return new PresetRangeSelection(preset, config);
if (!start && !end) return new EmptyRangeSelection();
if (!end) return new PartialRangeSelection(DateValue.fromIsoDateString(start));
return new RangeSelection(DateValue.fromIsoDateString(start), DateValue.fromIsoDateString(end));
} else {
if (!value3) return new NoneSelection2();
return new SingleSelection2(DateValue.fromIsoDateString(value3));
}
}
static createFromValueStringAttribute(value3, config, observable) {
let selection = _Selectable.createSelectionFromValueStringAttribute(value3, config);
return new _Selectable(selection, config, observable);
}
static createSelectionFromValueStringAttribute(value3, config) {
if (config.mode === CalendarModes.MULTIPLE) {
let dates = value3 ? value3.split(",").map((i) => i.trim()).map((i) => DateValue.fromIsoDateString(i)) : [];
return new MultipleSelection2(dates);
} else if (config.mode === CalendarModes.RANGE) {
if (!value3) return new EmptyRangeSelection();
let [start, end] = value3.split("/").map((i) => i.trim());
if (!end && start && presets[start] && start !== "custom") {
return new PresetRangeSelection(start, config);
}
start = DateValue.fromIsoDateString(start);
if (!end) {
return new PartialRangeSelection(start);
}
end = DateValue.fromIsoDateString(end);
return new RangeSelection(start, end);
} else {
if (!value3) return new NoneSelection2();
return new SingleSelection2(DateValue.fromIsoDateString(value3));
}
}
};
var DeferredSelectable = class {
constructor(selectable, observable) {
this.selectable = selectable;
this.observable = observable;
this._selection = this.selectable.selection;
this.selectable.observable.subscribe(ObservableTrigger2.SELECTION, () => {
this._blockSync() || this.sync();
});
this._blockSync = () => {
};
}
blockSyncIf(condition) {
this._blockSync = condition;
}
sync() {
this._selection = this.selectable.selection;
this.observable.notify(ObservableTrigger2.SELECTION);
}
setValue(value3) {
return this.selectable.setValue(value3);
}
getValue() {
return this._selection.value();
}
isSelectable(date) {
return this._selection.selectable(date, this.config);
}
hasSelection() {
return this._selection.hasSelection();
}
display(...params) {
return this.selectable.displayResolver(this._selection.display(...params));
}
};
var Selection2 = class {
contains() {
}
shouldNotify(previousSelection) {
return true;
}
hasSelection() {
return false;
}
lowerBound(fallback) {
return value2(fallback);
}
upperBound(fallback) {
return this.lowerBound(fallback);
}
selectable(date, config) {
return true;
}
display() {
}
value() {
}
activate() {
}
attributes(el, date) {
if (this.contains(date)) {
setAttribute2(el, "data-selected", "");
setAttribute2(el, "aria-selected", "true");
} else {
removeAttribute(el, "data-selected");
setAttribute2(el, "aria-selected", "false");
}
}
};
var NoneSelection2 = class _NoneSelection extends Selection2 {
shouldNotify(selection) {
return !(selection instanceof _NoneSelection);
}
hasSelection() {
return false;
}
contains() {
return false;
}
select(date) {
return new SingleSelection2(date);
}
lowerBound(fallback) {
return value2(fallback);
}
display(locale) {
return "";
}
value() {
return null;
}
};
var SingleSelection2 = class _SingleSelection extends Selection2 {
constructor(date) {
super();
this._date = date;
}
hasSelection() {
return true;
}
shouldNotify(previousSelection) {
if (previousSelection instanceof _SingleSelection && this._date.isSameDay(previousSelection._date)) return false;
return true;
}
select(date) {
if (this._date.isSameDay(date)) return new NoneSelection2();
return new _SingleSelection(date);
}
contains(date) {
return this._date.isSameDay(date);
}
lowerBound() {
return this._date;
}
display(locale) {
return this._date.toFormattedString(locale, { day: "numeric", month: "short", year: "numeric" });
}
value() {
return this._date.toIsoDateString();
}
};
var MultipleSelection2 = class _MultipleSelection extends Selection2 {
constructor(dates) {
super();
this._dates = dates;
}
hasSelection() {
return this._dates.length > 0;
}
shouldNotify(previousSelection) {
if (previousSelection instanceof _MultipleSelection && this._dates.every((i) => previousSelection._dates.includes(i)) && previousSelection._dates.every((i) => this._dates.includes(i))) return false;
return true;
}
select(date) {
let containsDate = this._dates.some((i) => i.isSameDay(date));
if (containsDate) return new _MultipleSelection(this._dates.filter((i) => !i.isSameDay(date)));
return new _MultipleSelection([...this._dates, date]);
}
contains(date) {
return this._dates.some((i) => i.isSameDay(date));
}
lowerBound(fallback) {
let sortedDates = this._dates.sort((a, b) => a.isBefore(b) ? -1 : 1);
return sortedDates[0] || value2(fallback);
}
upperBound(fallback) {
let sortedDates = this._dates.sort((a, b) => a.isBefore(b) ? -1 : 1);
return sortedDates[sortedDates.length - 1] || value2(fallback);
}
display(locale) {
return this._dates.map((i) => i.toFormattedString(locale, { day: "numeric", month: "short", year: "numeric" })).join(", ");
}
value() {
return this._dates.map((i) => i.toIsoDateString());
}
};
var EmptyRangeSelection = class _EmptyRangeSelection extends Selection2 {
constructor() {
super();
}
hasSelection() {
return false;
}
shouldNotify(previousSelection) {
return !(previousSelection instanceof _EmptyRangeSelection || previousSelection instanceof PartialRangeSelection);
}
select(date) {
return new PartialRangeSelection(date);
}
contains() {
return false;
}
lowerBound(fallback) {
return value2(fallback);
}
display(locale) {
return "";
}
value() {
return null;
}
};
var PartialRangeSelection = class _PartialRangeSelection extends Selection2 {
constructor(start) {
super();
this._start = start;
this._endPreview = null;
}
hasSelection() {
return false;
}
shouldNotify(previousSelection) {
return false;
}
select(date, config) {
if (date.isBefore(this._start)) return new _PartialRangeSelection(date);
if (date.isSameDay(this._start) && config.minRange > 1) {
return new EmptyRangeSelection();
}
return new RangeSelection(this._start, date);
}
activate(date) {
this._endPreview = date;
}
selectable(date, config) {
if (config.maxRange) {
if (date.isBefore(this._start)) return false;
if (this._start.addDays(config.maxRange - 1).isBefore(date)) return false;
}
if (config.minRange) {
if (this._start.isSameDay(date)) return true;
if (date.isBefore(this._start)) return false;
if (this._start.addDays(config.minRange - 1).isAfter(date)) return false;
}
let nextUnavailable = config.unavailable.filter((d) => d.isAfter(this._start)).sort((a, b) => a.toDate() - b.toDate())[0];
let prevUnavailable = config.unavailable.filter((d) => d.isBefore(this._start)).sort((a, b) => b.toDate() - a.toDate())[0];
if (date.isAfter(this._start)) {
return !nextUnavailable || date.isBefore(nextUnavailable);
}
if (date.isBefore(this._start)) {
return !prevUnavailable || date.isAfter(prevUnavailable);
}
return true;
}
contains(date) {
return date.isSameDay(this._start);
}
lowerBound() {
return this._start;
}
display(locale) {
return new Intl.DateTimeFormat(locale, { day: "numeric", month: "short", year: "numeric", timeZone: "UTC" }).format(this._start.getDate()) + " -";
}
value() {
return null;
}
attributes(el, date) {
if (this._endPreview && date.isBetween(this._start, this._endPreview)) {
setAttribute2(el, "data-in-range", "");
setAttribute2(el, "aria-selected", "true");
} else {
removeAttribute(el, "data-in-range");
removeAttribute(el, "aria-selected");
}
date.isSameDay(this._start) ? setAttribute2(el, "data-selected", "") : removeAttribute(el, "data-selected");
date.isSameDay(this._start) ? setAttribute2(el, "aria-selected", "true") : removeAttribute(el, "aria-selected");
date.isSameDay(this._start) ? setAttribute2(el, "data-start", "") : removeAttribute(el, "data-start");
date.isSameDay(this._endPreview) ? setAttribute2(el, "data-end-preview", "") : removeAttribute(el, "data-end-preview");
}
};
var RangeSelection = class _RangeSelection extends Selection2 {
constructor(start, end) {
super();
this._start = start;
this._end = end;
}
hasSelection() {
return true;
}
shouldNotify(previousSelection) {
if (previousSelection instanceof _RangeSelection && this._start.isSameDay(previousSelection._start) && this._end.isSameDay(previousSelection._end)) return false;
return true;
}
select(date) {
return new PartialRangeSelection(date);
}
contains(date) {
return date.isBetween(this._start, this._end);
}
lowerBound() {
return this._start;
}
upperBound() {
return this._end;
}
display(locale) {
return new Intl.DateTimeFormat(locale, { day: "numeric", month: "short", year: "numeric", timeZone: "UTC" }).formatRange(this._start.getDate(), this._end.getDate()).replaceAll("\u2009", " ");
}
value() {
return { start: this._start.toIsoDateString(), end: this._end.toIsoDateString() };
}
attributes(el, date) {
date.isSameDay(this._start) || date.isSameDay(this._end) ? setAttribute2(el, "data-selected", "") : removeAttribute(el, "data-selected");
date.isSameDay(this._start) ? setAttribute2(el, "data-start", "") : removeAttribute(el, "data-start");
date.isSameDay(this._end) ? setAttribute2(el, "data-end", "") : removeAttribute(el, "data-end");
if (this.contains(date)) {
setAttribute2(el, "data-in-range", "");
setAttribute2(el, "aria-selected", "true");
} else {
removeAttribute(el, "data-in-range");
removeAttribute(el, "aria-selected");
}
}
};
var PresetRangeSelection = class _PresetRangeSelection extends Selection2 {
constructor(preset, config) {
super();
this._preset = preset;
this._config = config;
}
get _start() {
let [start] = presets[this._preset](this._config);
return this._config.min && start.isBefore(this._config.min) ? this._config.min : start;
}
get _end() {
let [, end] = presets[this._preset](this._config);
return this._config.max && end.isAfter(this._config.max) ? this._config.max : end;
}
hasSelection() {
return true;
}
shouldNotify(previousSelection) {
return !(previousSelection instanceof _PresetRangeSelection && this._preset === previousSelection._preset);
}
select(date) {
return new PartialRangeSelection(date, this._config);
}
contains(date) {
return date.isBetween(this._start, this._end);
}
lowerBound() {
if (this._preset === "allTime") return DateValue.today();
return this._start;
}
upperBound() {
if (this._preset === "allTime") return DateValue.today();
return DateValue.today();
}
display(locale) {
return new Intl.DateTimeFormat(locale, { day: "numeric", month: "short", year: "numeric", timeZone: "UTC" }).formatRange(this._start.getDate(), this._end.getDate()).replaceAll("\u2009", " ");
}
value() {
return { start: this._start.toIsoDateString(), end: this._end.toIsoDateString(), preset: this._preset };
}
attributes(el, date) {
date.isSameDay(this._start) || date.isSameDay(this._end) ? setAttribute2(el, "data-selected", "") : removeAttribute(el, "data-selected");
date.isSameDay(this._start) ? setAttribute2(el, "data-start", "") : removeAttribute(el, "data-start");
date.isSameDay(this._end) ? setAttribute2(el, "data-end", "") : removeAttribute(el, "data-end");
if (this.contains(date)) {
setAttribute2(el, "data-in-range", "");
setAttribute2(el, "aria-selected", "true");
} else {
removeAttribute(el, "data-in-range");
removeAttribute(el, "aria-selected");
}
}
};
function value2(i = null) {
return typeof i === "function" ? i() : i;
}
var presets = {
today: () => {
return [DateValue.today(), DateValue.today()];
},
yesterday: () => {
let date = DateValue.today().incrementDays(-1);
return [date, date];
},
thisWeek: (config) => {
let start = DateValue.today().getCopy().incrementDays(config.startDay - DateValue.today().getDayOfWeek());
let end = start.incrementDays(6);
return [start, end];
},
lastWeek: (config) => {
let start = DateValue.today().incrementDays(config.startDay - (DateValue.today().getDayOfWeek() + 7));
let end = start.incrementDays(6);
return [start, end];
},
last7Days: () => {
let end = DateValue.today();
let start = DateValue.today().incrementDays(-6);
return [start, end];
},
thisMonth: () => {
let start = DateValue.fromParts(DateValue.today().getYear(), DateValue.today().getMonth(), 1);
let end = DateValue.fromParts(DateValue.today().getYear(), DateValue.today().getMonth(), DateValue.today().getDaysInMonth());
return [start, end];
},
lastMonth: () => {
let month = DateValue.today().getMonth() - 1;
let year = DateValue.today().getYear();
if (month < 1) {
month += 12;
year--;
}
let start = DateValue.fromParts(year, month, 1);
let end = DateValue.fromParts(year, month, start.getDaysInMonth());
return [start, end];
},
thisQuarter: () => {
let quarter = Math.floor((DateValue.today().getMonth() - 1) / 3);
let startMonth = quarter * 3 + 1;
let endMonth = startMonth + 2;
let start = DateValue.fromParts(DateValue.today().getYear(), startMonth, 1);
let endMonthStart = DateValue.fromParts(DateValue.today().getYear(), endMonth, 1);
let end = DateValue.fromParts(DateValue.today().getYear(), endMonth, endMonthStart.getDaysInMonth());
return [start, end];
},
lastQuarter: () => {
let quarter = Math.floor((DateValue.today().getMonth() - 4) / 3);
let startMonth = quarter * 3 + 1;
let endMonth = startMonth + 2;
let year = DateValue.today().getYear();
if (startMonth < 1) {
startMonth += 12;
endMonth += 12;
year--;
}
let start = DateValue.fromParts(year, startMonth, 1);
let endMonthStart = DateValue.fromParts(year, endMonth, 1);
let end = DateValue.fromParts(year, endMonth, endMonthStart.getDaysInMonth());
return [start, end];
},
thisYear: () => {
let start = DateValue.fromParts(DateValue.today().getYear(), 1, 1);
let end = DateValue.fromParts(DateValue.today().getYear(), 12, 31);
return [start, end];
},
lastYear: () => {
let year = DateValue.today().getYear() - 1;
let start = DateValue.fromParts(year, 1, 1);
let end = DateValue.fromParts(year, 12, 31);
return [start, end];
},
last14Days: () => {
let end = DateValue.today();
let start = DateValue.today().incrementDays(-13);
return [start, end];
},
last30Days: () => {
let end = DateValue.today();
let start = DateValue.today().incrementDays(-29);
return [start, end];
},
last3Months: () => {
let end = DateValue.today();
let day = DateValue.today().getDay() + 1;
let month = DateValue.today().getMonth() - 3;
let year = DateValue.today().getYear();
if (month < 1) {
month += 12;
year--;
}
let start = DateValue.fromParts(year, month, day);
return [start, end];
},
last6Months: () => {
let end = DateValue.today();
let day = DateValue.today().getDay() + 1;
let month = DateValue.today().getMonth() - 6;
let year = DateValue.today().getYear();
if (month < 1) {
month += 12;
year--;
}
let start = DateValue.fromParts(year, month, day);
return [start, end];
},
yearToDate: () => {
let start = DateValue.fromParts(DateValue.today().getYear(), 1, 1);
let end = DateValue.today();
return [start, end];
},
allTime: (config) => {
if (!config.min) throw new Error("Min date is required for allTime preset");
let start = config.min;
let end = DateValue.today();
return [start, end];
}
};
// js/calendar/view.js
var CalendarViewState = class {
constructor(month, year, config, observable) {
this.month = month;
this.year = year;
this.config = config;
this.observable = observable;
}
generateOffsetState(offset3) {
return new CalendarOffsetViewState(this, offset3);
}
canNavigatePrevious() {
let [prevYear, prevMonth] = new DateValue(this.year, this.month).addMonths(-1).toParts();
return !(this.config.min && DateValue.fromParts(prevYear, prevMonth).isBefore(DateValue.firstDayOfMonth(this.config.min)));
}
canNavigateNext() {
let [nextYear, nextMonth] = new DateValue(this.year, this.month).addMonths(this.config.months).toParts();
return !(this.config.max && DateValue.fromParts(nextYear, nextMonth).isAfter(this.config.max));
}
nextMonth() {
if (!this.canNavigateNext()) return;
this.adjustMonth(1);
}
previousMonth() {
this.adjustMonth(-1);
}
setMonth(month) {
if (!month) return;
if (this.isWithinMinAndMax(month, this.year)) {
this.month = month;
}
this.observable.notify(ObservableTrigger2.VIEW_CHANGE);
}
setYear(year) {
if (!year) return;
if (this.isWithinMinAndMax(this.month, year)) {
this.year = year;
}
this.observable.notify(ObservableTrigger2.VIEW_CHANGE);
}
setDate(date) {
if (!date) return;
if (this.isWithinMinAndMax(date.getMonth(), date.getYear())) {
this.month = date.getMonth();
this.year = date.getYear();
}
this.observable.notify(ObservableTrigger2.VIEW_CHANGE);
}
isWithinMinAndMax(month, year) {
if (this.config.min && DateValue.fromParts(year, month).isBefore(DateValue.firstDayOfMonth(this.config.min))) return false;
if (this.config.max && DateValue.fromParts(year, month).isAfter(this.config.max)) return false;
return true;
}
adjustMonth(delta) {
let [nextYear, nextMonth] = new DateValue(this.year, this.month).addMonths(delta).toParts();
if (this.config.min && DateValue.fromParts(nextYear, nextMonth).isBefore(DateValue.firstDayOfMonth(this.config.min))) return;
if (this.config.max && DateValue.fromParts(nextYear, nextMonth).isAfter(this.config.max)) return;
[this.month, this.year] = [nextMonth, nextYear];
this.observable.notify(ObservableTrigger2.VIEW_CHANGE);
}
};
var CalendarOffsetViewState = class {
constructor(viewState, offset3 = 0) {
this.offset = offset3;
this.viewState = viewState;
}
get month() {
let [, newMonth] = new DateValue(this.viewState.year, this.viewState.month).addMonths(this.offset).toParts();
return newMonth;
}
get year() {
let [newYear] = new DateValue(this.viewState.year, this.viewState.month).addMonths(this.offset).toParts();
return newYear;
}
};
// js/calendar/validator.js
var Validator = class {
constructor(selectable, metadata, config) {
this.min = config.min;
this.max = config.max;
this.unavailable = config.unavailable;
this.selectable = selectable;
this.metadata = metadata;
}
isBetweenMinMax(date) {
return date.isBetween(this.min, this.max);
}
isUnavailable(date) {
return this.unavailable.some((i) => i.isSameDay(date)) || this.metadata.unavailable(date);
}
isBlocked(date) {
return !this.selectable.isSelectable(date);
}
isValid(date) {
return this.isBetweenMinMax(date) && !this.isUnavailable(date) && !this.isBlocked(date);
}
};
// js/calendar/meta.js
var DateMetadata = class {
constructor(observable) {
this.metadata = {};
this.observable = observable;
}
resetFromJSON(json) {
this.reset(JSON.parse(json));
}
appendFromJSON(json) {
this.append(JSON.parse(json));
}
append(object) {
this.metadata = { ...this.metadata, ...object };
this.observable.notify(ObservableTrigger2.VIEW_CHANGE);
}
reset(object) {
this.metadata = object;
this.observable.notify(ObservableTrigger2.VIEW_CHANGE);
}
get(date) {
return this.metadata[date.toIsoDateString()];
}
has(date) {
return this.metadata[date.toIsoDateString()] !== void 0;
}
subtext(date) {
return this.metadata[date.toIsoDateString()]?.subtext;
}
details(date) {
return this.metadata[date.toIsoDateString()]?.details;
}
variant(date) {
return this.metadata[date.toIsoDateString()]?.variant;
}
unavailable(date) {
return !!this.metadata[date.toIsoDateString()]?.unavailable;
}
};
// js/calendar/index.js
var UICalendar = class extends UIElement {
boot() {
let elDrivingConfig = this.closest("ui-date-picker") || this;
this.querySelectorAll("[data-appended]").forEach((el) => el.remove());
let [months, onMonthsChange] = responsiveAttributeValue(elDrivingConfig, "months", 1);
this.observable = new Observable2();
let locale = elDrivingConfig.hasAttribute("locale") ? elDrivingConfig.getAttribute("locale") : getLocale();
this.config = {
mode: elDrivingConfig.getAttribute("mode") === "range" ? CalendarModes.RANGE : elDrivingConfig.hasAttribute("multiple") ? CalendarModes.MULTIPLE : CalendarModes.SINGLE,
months: parseInt(months),
min: this.getMinDate(elDrivingConfig),
max: this.getMaxDate(elDrivingConfig),
maxRange: elDrivingConfig.hasAttribute("max-range") ? parseInt(elDrivingConfig.getAttribute("max-range")) : null,
minRange: elDrivingConfig.hasAttribute("min-range") ? parseInt(elDrivingConfig.getAttribute("min-range")) : null,
startDay: elDrivingConfig.hasAttribute("start-day") ? parseInt(elDrivingConfig.getAttribute("start-day")) : (new Intl.Locale(locale).weekInfo?.firstDay || 7) % 7,
unavailable: this.getUnavailableDates(elDrivingConfig),
locale,
fixedWeeks: elDrivingConfig.hasAttribute("fixed-weeks") ? 6 : null
};
onMonthsChange((months2) => {
this.config.months = parseInt(months2);
this.observable.notify(ObservableTrigger2.VIEW_CHANGE);
});
this.selectable = Selectable3.createFromValueStringAttribute(elDrivingConfig.getAttribute("value"), this.config, this.observable);
this.metadata = new DateMetadata(this.observable);
this.validator = new Validator(this.selectable, this.metadata, this.config);
let openToDate = elDrivingConfig.hasAttribute("open-to") && (elDrivingConfig.hasAttribute("force-open-to") || this.selectable.lowerBound() === null) ? this.getOpenTo(elDrivingConfig) : this.selectable.lowerBound(() => DateValue.today());
this.viewState = new CalendarViewState(openToDate.getMonth(), openToDate.getYear(), this.config, this.observable);
this._disableable = new Disableable(this, {
disableWithParent: false
});
if (!this.hasAttribute("static")) {
let { enable: enableListeners, disable: disableListeners } = initializeEventListeners2(this, this.selectable, this.viewState, this.validator);
this._disableable.onInitAndChange((disabled) => {
disabled ? disableListeners() : enableListeners();
});
}
this._controllable = new Controllable(this, { bubbles: true });
this._submittable = new Submittable(this, {
name: this.getAttribute("name"),
value: this.selectable.getValue()
});
let detangled = detangle();
this._controllable.initial((initial) => initial && this.selectable.setValue(initial));
this._controllable.getter(() => this.selectable.getValue());
this._controllable.setter(detangled((value3) => {
this.selectable.setValue(value3);
}));
this.observable.subscribe(ObservableTrigger2.SELECTION, detangled(() => {
this.dispatchEvent(new Event("select", { bubbles: false, cancelable: true }));
this._controllable.dispatch();
}));
this.observable.subscribe(ObservableTrigger2.SELECTION, () => {
this._submittable.update(this.selectable.getValue());
});
this.observable.subscribe(ObservableTrigger2.SELECTION, () => {
this.anchorSelection();
});
this.observable.subscribe(ObservableTrigger2.VIEW_CHANGE, () => {
this.dispatchEvent(new Event("navigate", { bubbles: false, cancelable: true }));
});
queueMicrotask(() => {
this.closest("ui-date-picker")?.bootWithCalendar(this);
});
let observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if (!["unavailable", "max", "min"].includes(mutation.attributeName)) return;
this.config.unavailable = this.getUnavailableDates(elDrivingConfig);
this.config.min = this.getMinDate(elDrivingConfig);
this.config.max = this.getMaxDate(elDrivingConfig);
this.validator.unavailable = this.config.unavailable;
this.validator.min = this.config.min;
this.validator.max = this.config.max;
this.observable.notify(ObservableTrigger2.VIEW_CHANGE);
});
});
observer.observe(elDrivingConfig, { attributes: true });
}
getOpenTo(el) {
if (!el.hasAttribute("open-to")) return;
let openTo = el.getAttribute("open-to");
openTo = openTo === "today" ? DateValue.today() : DateValue.fromIsoDateString(openTo);
if (!this.validator.isBetweenMinMax(openTo)) {
return this.config.min;
}
return openTo;
}
navigateNext() {
this.viewState.nextMonth();
}
navigatePrevious() {
this.viewState.previousMonth();
}
anchorSelection() {
let focusedEl = document.activeElement;
let isFocusedOnADateButton = this.contains(focusedEl) && focusedEl.closest("[data-date]") !== null;
if (isFocusedOnADateButton) return;
this.viewState.setDate(
this.selectable.lowerBound(DateValue.today())
);
}
appendMetadata(object) {
this.metadata.append(object);
}
resetMetadata(object = {}) {
this.metadata.reset(object);
}
visibleDateRange() {
return [
DateValue.fromParts(this.viewState.year, this.viewState.month, 1).toIsoDateString(),
DateValue.fromParts(this.viewState.year, this.viewState.month + 1, 0).toIsoDateString()
];
}
getUnavailableDates(el) {
return el.hasAttribute("unavailable") ? el.getAttribute("unavailable").split(",").map((i) => DateValue.fromIsoDateString(i.trim())) : [];
}
getMinDate(el) {
return el.hasAttribute("min") ? el.getAttribute("min") === "today" ? DateValue.today() : DateValue.fromIsoDateString(el.getAttribute("min")) : null;
}
getMaxDate(el) {
return el.hasAttribute("max") ? el.getAttribute("max") === "today" ? DateValue.today() : DateValue.fromIsoDateString(el.getAttribute("max")) : null;
}
};
var UICalendarPrevious = class extends UIElement {
boot() {
let calendar = this.closest("ui-calendar");
this._disableable = calendar._disableable;
initFauxButton(this, () => this._disableable.isDisabled(), () => calendar.navigatePrevious());
let setDisabled = () => {
if (calendar.viewState.canNavigatePrevious() && !this._disableable.isDisabled()) {
removeAttribute(this, "disabled");
} else {
setAttribute2(this, "disabled", "");
}
};
calendar.observable.subscribe(ObservableTrigger2.VIEW_CHANGE, setDisabled);
this._disableable.onInitAndChange(() => {
setDisabled();
});
}
};
var UICalendarNext = class extends UIElement {
boot() {
let calendar = this.closest("ui-calendar");
this._disableable = calendar._disableable;
initFauxButton(this, () => this._disableable.isDisabled(), () => calendar.navigateNext());
let setDisabled = () => {
if (calendar.viewState.canNavigateNext() && !this._disableable.isDisabled()) {
removeAttribute(this, "disabled");
} else {
setAttribute2(this, "disabled", "");
}
};
calendar.observable.subscribe(ObservableTrigger2.VIEW_CHANGE, setDisabled);
this._disableable.onInitAndChange(() => {
setDisabled();
});
}
};
var UICalendarMonth = class extends UIElement {
boot() {
let calendar = this.closest("ui-calendar");
this._disableable = calendar._disableable;
this.offset = this.hasAttribute("offset") ? parseInt(this.getAttribute("offset")) : 0;
this.config = calendar.config;
this.viewState = calendar.viewState;
this.offsetState = this.viewState.generateOffsetState(this.offset);
this.validator = calendar.validator;
let select = this.querySelector("select");
let display = this.hasAttribute("display") ? this.getAttribute("display") : "long";
if (select) {
this.renderSelectOptions(select, display);
select.value = this.viewState.month;
select.addEventListener("change", this._disableable.enabled(() => {
this.viewState.setMonth(parseInt(select.value));
}));
calendar.observable.subscribe(ObservableTrigger2.VIEW_CHANGE, () => {
this.renderSelectOptions(select, display);
select.value = this.viewState.month;
});
this._disableable.onInitAndChange((disabled) => {
if (disabled) {
setAttribute2(select, "disabled", "");
} else {
removeAttribute(select, "disabled");
}
});
} else {
let update = () => this.textContent = new Intl.DateTimeFormat(this.config.locale, {
month: this.hasAttribute("display") ? this.getAttribute("display") : "long",
timeZone: "UTC"
}).format(new DateValue(this.offsetState.year, this.offsetState.month).getDate());
update();
this.viewState.observable.subscribe(ObservableTrigger2.VIEW_CHANGE, () => update());
}
}
renderSelectOptions(select, display) {
let months = Array.from({ length: 12 }, (_, idx) => idx + 1);
let renderableMonths = months.map((month) => {
let firstDayOfMonth = new DateValue(this.viewState.year, month);
let lastDayOfMonth = new DateValue(this.viewState.year, month + 1, 0);
if (!this.validator.isBetweenMinMax(firstDayOfMonth) && !this.validator.isBetweenMinMax(lastDayOfMonth)) {
return null;
}
return {
month,
label: new Intl.DateTimeFormat(this.config.locale, { month: display, timeZone: "UTC" }).format(new DateValue(2024, month).getDate())
};
}).filter(Boolean);
renderTemplate(select.querySelector("template"), (hydrate) => {
if (renderableMonths.length === 0) {
let month = this.viewState.month;
let label = new Intl.DateTimeFormat(this.config.locale, { month: display, timeZone: "UTC" }).format(new DateValue(2024, month).getDate());
let option = hydrate({ slots: { default: label } });
option.setAttribute("value", month);
return option;
}
return renderableMonths.map((month) => {
let option = hydrate({ slots: { default: month.label } });
option.setAttribute("value", month.month);
return option;
});
});
}
};
var UICalendarYear = class extends UIElement {
boot() {
let calendar = this.closest("ui-calendar");
this._disableable = calendar._disableable;
this.offset = this.hasAttribute("offset") ? parseInt(this.getAttribute("offset")) : 0;
this.config = calendar.config;
this.viewState = calendar.viewState;
this.offsetState = this.viewState.generateOffsetState(this.offset);
this.numberOfPastYears = 100;
this.numberOfFutureYears = 10;
this.validator = calendar.validator;
let select = this.querySelector("select");
if (select) {
if (this.config.min) this.numberOfPastYears = this.viewState.year - this.config.min.getYear();
if (this.config.max) this.numberOfFutureYears = this.config.max.getYear() - this.viewState.year;
this.renderSelectOptions(select);
select.value = this.viewState.year;
select.addEventListener("change", this._disableable.enabled(() => {
this.viewState.setYear(parseInt(select.value));
}));
calendar.observable.subscribe(ObservableTrigger2.VIEW_CHANGE, () => {
if (this.yearIsLessThanMinimum(this.viewState.year)) {
this.numberOfPastYears += 100;
this.renderSelectOptions(select);
}
if (this.yearIsGreaterThanMaximum(this.viewState.year)) {
this.numberOfFutureYears += 10;
this.renderSelectOptions(select);
}
select.value = this.viewState.year;
});
this._disableable.onInitAndChange((disabled) => {
if (disabled) {
setAttribute2(select, "disabled", "");
} else {
removeAttribute(select, "disabled");
}
});
} else {
let update = () => this.textContent = new Intl.DateTimeFormat(this.config.locale, {
year: this.hasAttribute("display") ? this.getAttribute("display") : "numeric",
timeZone: "UTC"
}).format(new DateValue(this.offsetState.year, this.offsetState.month).getDate());
update();
this.viewState.observable.subscribe(ObservableTrigger2.VIEW_CHANGE, () => update());
}
}
yearIsLessThanMinimum(year) {
return year < this.minimumYear();
}
yearIsGreaterThanMaximum(year) {
return year > this.maximumYear();
}
minimumYear() {
return (/* @__PURE__ */ new Date()).getFullYear() - this.numberOfPastYears;
}
maximumYear() {
return (/* @__PURE__ */ new Date()).getFullYear() + this.numberOfFutureYears;
}
renderSelectOptions(select) {
let currentYear = (/* @__PURE__ */ new Date()).getFullYear();
let years = Array.from(
{ length: this.numberOfPastYears + this.numberOfFutureYears + 1 },
(_, i) => currentYear - this.numberOfPastYears + i
);
let renderableYears = years.map((year) => {
let firstDayOfMonth = new DateValue(year, 1);
let lastDayOfMonth = new DateValue(year, 12, 31);
if (!this.validator.isBetweenMinMax(firstDayOfMonth) && !this.validator.isBetweenMinMax(lastDayOfMonth)) {
return null;
}
return year;
}).filter(Boolean);
renderTemplate(select.querySelector("template"), (hydrate) => {
if (renderableYears.length === 0) {
let year = this.viewState.year;
return hydrate({ slots: { default: year } });
}
return renderableYears.map((year) => hydrate({ slots: { default: year } }));
});
}
};
var UICalendarMonths = class extends UIElement {
boot() {
let calendar = this.closest("ui-calendar");
this._disableable = calendar._disableable;
this.offset = this.hasAttribute("offset") ? parseInt(this.getAttribute("offset")) : 0;
this.config = calendar.config;
this.selectable = calendar.selectable;
this.observable = calendar.observable;
this.metadata = calendar.metadata;
this.validator = calendar.validator;
this.viewState = calendar.viewState;
this.offsetState = this.viewState.generateOffsetState(this.offset);
this.monthEls = [];
this.renderMonths();
let render = () => this.monthEls.forEach((month) => renderMonth(month, this.config, month.offsetState, this.metadata));
let update = () => this.monthEls.forEach((month) => updateMonth(month, this._disableable.isDisabled(), this.config, month.offsetState, this.selectable, this.validator));
render();
update();
let months = this.config.months;
this.viewState.observable.subscribe(ObservableTrigger2.VIEW_CHANGE, () => {
if (months !== this.config.months) {
months = this.config.months;
this.renderMonths();
}
render();
update();
});
this.observable.subscribe([ObservableTrigger2.SELECTION, ObservableTrigger2.ACTIVATION], () => {
update();
});
this._disableable.onChange(() => update());
}
renderMonths() {
let template = this.querySelector('template:not([name]), template[name="month"]');
renderTemplate(template, (hydrate) => {
let monthOffsetTemplate = Array.from({ length: this.config.months }).map((_, idx) => idx);
this.monthEls = monthOffsetTemplate.map((offset3) => {
let offsetState = this.viewState.generateOffsetState(offset3);
let monthEl = hydrate({ attrs: { "data-month": "" } });
monthEl.offsetState = offsetState;
let head = monthEl.querySelector("thead")?.set;
setAttribute2(monthEl, "role", "grid");
head && setAttribute2(head, "aria-hidden", "true");
return monthEl;
});
return this.monthEls;
});
}
};
var UICalendarToday = class extends UIElement {
boot() {
let calendar = this.closest("ui-calendar, ui-date-picker");
this._disableable = calendar._disableable;
this.behavior = this.hasAttribute("behavior") ? this.getAttribute("behavior") : "auto";
if (calendar.hasAttribute("static")) {
this.behavior = "none";
}
initFauxButton(this, () => this._disableable.isDisabled(), () => this.navigateAndSelectToday());
this._disableable.onInitAndChange((disabled) => {
if (disabled) {
setAttribute2(this, "disabled", "");
} else {
removeAttribute(this, "disabled");
}
});
let template = this.querySelector("template");
template && renderTemplate(template, (hydrate) => {
return hydrate({ slots: { default: DateValue.today().getDay() } });
});
}
navigateAndSelectToday() {
let calendar = this.closest("ui-calendar, ui-date-picker");
let isViewingCurrentMonth = () => {
let viewState = calendar.viewState;
let today = DateValue.today();
return viewState.year === today.getYear() && viewState.month === today.getMonth();
};
let shouldSelect = this.behavior === "select" || this.behavior === "auto" && isViewingCurrentMonth();
if (shouldSelect) {
if (calendar.config.mode === CalendarModes.RANGE) {
calendar.selectable.setValue({ start: DateValue.today().toIsoDateString(), end: DateValue.today().toIsoDateString() });
} else if (calendar.config.mode === CalendarModes.MULTIPLE) {
calendar.selectable.setValue([DateValue.today().toIsoDateString()]);
} else {
calendar.selectable.setValue(DateValue.today().toIsoDateString());
}
}
calendar.viewState.setMonth(DateValue.today().getMonth());
calendar.viewState.setYear(DateValue.today().getYear());
}
};
var UICalendarPresets = class extends UIElement {
boot() {
let calendar = this.closest("ui-calendar");
this._disableable = calendar._disableable;
this.offset = this.hasAttribute("offset") ? parseInt(this.getAttribute("offset")) : 0;
this.selectable = calendar.selectable;
this.observable = calendar.observable;
this.config = calendar.config;
this.viewState = calendar.viewState;
this.offsetState = this.viewState.generateOffsetState(this.offset);
if (this.config.mode !== CalendarModes.RANGE) throw "Presets can only be used with range calendars";
let selectable = this.firstElementChild;
if (selectable) {
let getLabelFromPreset = (preset) => {
if (selectable._selectable instanceof SelectableGroup) {
let option = selectable._selectable.findByValue(preset);
if (!option) return null;
return option?.el?.textContent;
} else if (selectable instanceof HTMLSelectElement) {
return selectable.querySelector(`option[value="${preset}"]`)?.textContent;
}
return null;
};
this.selectable.setDisplayResolver((i) => {
let preset = this.selectable.getValue()?.preset || "";
if (preset) {
let label = getLabelFromPreset(preset);
if (label) return label;
}
return i;
});
selectable.value = this.selectable.getValue()?.preset || "custom";
selectable.addEventListener("change", this._disableable.enabled(() => {
if (["", "custom"].includes(selectable.value)) {
let { start, end } = this.selectable.getValue() || {};
if (start && end) this.selectable.setValue({ start, end });
} else {
this.selectable.setValue({ preset: selectable.value });
}
}));
this.observable.subscribe(ObservableTrigger2.SELECTION, () => {
let value3 = this.selectable.getValue();
selectable.value = value3?.preset || "custom";
});
this._disableable.onInitAndChange((disabled) => {
if (disabled) {
setAttribute2(selectable, "disabled", "");
} else {
removeAttribute(selectable, "disabled");
}
});
}
}
};
var UICalendarInputs = class extends UIElement {
boot() {
let calendar = this.closest("ui-calendar");
this._disableable = calendar._disableable;
this.offset = this.hasAttribute("offset") ? parseInt(this.getAttribute("offset")) : 0;
this.selectable = calendar.selectable;
this.observable = calendar.observable;
this.config = calendar.config;
this.viewState = calendar.viewState;
this.offsetState = this.viewState.generateOffsetState(this.offset);
let [firstInput, secondInput] = this.querySelectorAll("input");
if (this.config.mode === CalendarModes.RANGE) {
syncInputStateWithRangeSelectionState(firstInput, secondInput, calendar);
} else {
syncInputStateWithSingleSelectionState(firstInput, calendar);
}
}
};
inject(({ css }) => css`
ui-calendar-preset,
ui-calendar-previous,
ui-calendar-next {
display: block;
user-select: none;
}
`);
element("calendar", UICalendar);
element("calendar-today", UICalendarToday);
element("calendar-presets", UICalendarPresets);
element("calendar-previous", UICalendarPrevious);
element("calendar-inputs", UICalendarInputs);
element("calendar-next", UICalendarNext);
element("calendar-months", UICalendarMonths);
element("calendar-month", UICalendarMonth);
element("calendar-year", UICalendarYear);
function initializeEventListeners2(el, selectable, viewState, validator) {
let blocked = false;
let readonly = el.hasAttribute("readonly");
on(el, "click", (e) => {
if (blocked || readonly) return;
let cell = e.target.closest("[data-date]");
if (!cell) return;
let date = dateFromCell2(cell);
validator.isValid(date) && selectable.select(date);
});
on(el, "mouseover", (e) => {
if (blocked || readonly) return;
let cell = e.target.closest("[data-date]");
if (!cell) return;
let date = dateFromCell2(cell);
if (!validator.isValid(date)) return;
selectable.activate(date);
});
on(el, "mouseout", () => {
if (blocked || readonly) return;
selectable.activate(null);
});
on(el, "focusin", (e) => {
if (blocked || readonly) return;
let cell = e.target.closest("[data-date]");
if (!cell) return;
let date = dateFromCell2(cell);
if (!validator.isValid(date)) return;
selectable.activate(date);
});
on(el, "keydown", (e) => {
if (blocked) return;
let cell = e.target.closest("[data-date]");
if (!cell) return;
let handled = true;
let direction;
let focusedDate = dateFromCell2(cell);
let adjustActive = (adjustment) => {
let activeDate = focusedDate.getCopy();
let direction2 = Math.sign(adjustment);
let safetyCounter = 366;
activeDate.setDay(activeDate.getDay() + adjustment);
while (!validator.isValid(activeDate) && safetyCounter > 0) {
activeDate.setDay(activeDate.getDay() + direction2);
safetyCounter--;
}
focusedDate = activeDate;
};
switch (e.key) {
case "ArrowRight":
direction = "forward";
adjustActive(1);
break;
case "ArrowLeft":
direction = "backward";
adjustActive(-1);
break;
case "ArrowUp":
direction = "backward";
adjustActive(-7);
break;
case "ArrowDown":
direction = "forward";
adjustActive(7);
break;
case "Home":
viewState.previousMonth();
break;
case "End":
viewState.nextMonth();
break;
case "PageUp":
if (e.shiftKey) {
viewState.previousMonth();
} else {
viewState.previousMonth();
}
break;
case "PageDown":
if (e.shiftKey) {
viewState.nextMonth();
} else {
viewState.nextMonth();
}
break;
default:
handled = false;
}
if (handled) {
e.preventDefault();
e.stopPropagation();
let cell2 = Array.from(el.querySelectorAll("[data-date]")).find((cell3) => dateFromCell2(cell3).isSameDay(focusedDate));
if (!cell2 && direction) {
if (direction === "forward") {
viewState.nextMonth();
} else {
viewState.previousMonth();
}
cell2 = Array.from(el.querySelectorAll("[data-date]")).find((cell3) => dateFromCell2(cell3).isSameDay(focusedDate));
}
cell2?.querySelector("button,ui-button")?.focus();
}
});
return { enable() {
blocked = false;
}, disable() {
blocked = true;
} };
}
function dateFromCell2(cell) {
if (!cell) return null;
if (!cell.hasAttribute("data-date")) return null;
return DateValue.fromIsoDateString(cell.getAttribute("data-date"));
}
function syncInputStateWithSingleSelectionState(input, subject) {
preventInputEventsFromBubblingToSelectRoot2(input);
let detangled = detangle();
let sync = detangled(() => {
let selected = subject.selectable.getValue();
input.value = selected || "";
});
subject.observable.subscribe(ObservableTrigger2.SELECTION, sync);
sync();
input.addEventListener("change", detangled(() => {
let date = input.valueAsDate;
if (date) {
subject.selectable.setValue(
DateValue.fromLocalDate(date).toIsoDateString()
);
subject.viewState.setDate(DateValue.fromLocalDate(date));
} else {
subject.selectable.setValue("");
}
}));
}
function syncInputStateWithRangeSelectionState(input, secondInput, subject) {
preventInputEventsFromBubblingToSelectRoot2(input);
preventInputEventsFromBubblingToSelectRoot2(secondInput);
let detangled = detangle();
let setInputsFromValue = detangled(() => {
let { start, end } = subject.selectable.getValue() || {};
input.value = start || "";
secondInput.value = end || "";
});
let setValueFromInputs = detangled(() => {
let start = input.valueAsDate;
let end = secondInput.valueAsDate;
if (start && end) {
subject.selectable.setValue(
{ start: DateValue.fromLocalDate(start).toIsoDateString(), end: DateValue.fromLocalDate(end).toIsoDateString() }
);
} else if (start) {
subject.selectable.setValue(
{ start: DateValue.fromLocalDate(start).toIsoDateString(), end: null }
);
} else {
subject.selectable.setValue(
{ start: null, end: null }
);
}
});
subject.observable.subscribe(ObservableTrigger2.SELECTION, setInputsFromValue);
setInputsFromValue();
input.addEventListener("change", setValueFromInputs);
secondInput.addEventListener("change", setValueFromInputs);
}
function preventInputEventsFromBubblingToSelectRoot2(input) {
on(input, "change", (e) => e.stopPropagation());
on(input, "input", (e) => e.stopPropagation());
}
// js/calendar/picker.js
var UIDatePicker = class extends UIControl {
bootWithCalendar(calendar) {
let isRange = calendar.config.mode === CalendarModes.RANGE;
this.calendar = calendar;
this._disableable = new Disableable(this);
this._disableable.onInitAndChange((disabled) => {
this.calendar.disabled = disabled;
});
this.observable = new Observable2();
this.selectable = new DeferredSelectable(this.calendar.selectable, this.observable);
this.viewState = this.calendar.viewState;
this.querySelector("ui-selected-date")?.bootWithCalendar();
this.querySelector("ui-date-picker-select")?.bootWithCalendar();
let popoverEl = this.querySelector("dialog");
if (!popoverEl) return;
let inputEl = this.querySelector("input");
inputEl = popoverEl?.contains(inputEl) ? null : inputEl;
let secondInputEl = Array.from(this.querySelectorAll("input")).find((i) => i !== inputEl);
secondInputEl = popoverEl?.contains(secondInputEl) ? null : secondInputEl;
inputEl && inputEl.addEventListener("click", (e) => e.preventDefault());
secondInputEl && secondInputEl.addEventListener("click", (e) => e.preventDefault());
let buttonEl = this.querySelector("button,ui-button");
buttonEl = popoverEl?.contains(buttonEl) ? null : buttonEl;
let calendarId = assignId(this.calendar, "calendar");
this.triggerEl = inputEl || buttonEl;
if (!this.triggerEl) return;
setAttribute2(this.triggerEl, "role", "combobox");
setAttribute2(this.triggerEl, "aria-controls", calendarId);
this._disableable.onInitAndChange((disabled) => {
if (disabled) setAttribute2(this.triggerEl, "disabled", "");
else removeAttribute(this.triggerEl, "disabled");
});
this._dialogable = new Dialogable(popoverEl, {
clickOutside: !this.hasAttribute("disable-click-outside"),
triggers: [buttonEl, inputEl, secondInputEl].filter(Boolean)
});
this._closeable = new Closeable(this);
this._closeable.onClose(() => this._dialogable.hide());
this._anchorable = new Anchorable(popoverEl, {
reference: this.triggerEl,
position: this.hasAttribute("position") ? this.getAttribute("position") : void 0,
gap: this.hasAttribute("gap") ? this.getAttribute("gap") : void 0,
offset: this.hasAttribute("offset") ? this.getAttribute("offset") : void 0
});
if (isIOS()) {
inputEl && this.showIOSOverlay(inputEl);
secondInputEl && this.showIOSOverlay(secondInputEl);
}
this.querySelectorAll("button,ui-button").forEach((button) => {
if (button === this.triggerEl) return;
if (popoverEl.contains(button)) return;
setAttribute2(button, "aria-controls", calendarId);
setAttribute2(button, "aria-haspopup", "combobox");
linkExpandedStateToPopover3(button, this._dialogable);
on(button, "click", () => this._dialogable.toggle());
});
initPopover3(this, this.triggerEl, popoverEl, this._dialogable, this._anchorable);
linkExpandedStateToPopover3(this.triggerEl, this._dialogable);
preventScrollWhenPopoverIsOpen3(this, this._dialogable);
controlPopoverWithKeyboard2(this.triggerEl, this._dialogable);
handlePopoverClosing3(this, this.calendar.config.mode, this.observable, this.selectable, this._dialogable);
if (isRange && popoverEl && inputEl && secondInputEl) {
highlightInputContentsWhenFocused2(inputEl);
highlightInputContentsWhenFocused2(secondInputEl);
syncInputStateWithRangeSelectionState(inputEl, secondInputEl, this);
} else if (popoverEl && inputEl) {
let input = inputEl;
highlightInputContentsWhenFocused2(input);
syncInputStateWithSingleSelectionState(input, this);
} else if (popoverEl) {
let button = buttonEl;
togglePopoverWithMouse2(button, this._dialogable);
}
this._controllable = new Controllable(this, { bubbles: true });
this.calendar.addEventListener("change", (e) => e.stopPropagation());
this.calendar.addEventListener("input", (e) => e.stopPropagation());
this._submittable = new Submittable(this, {
name: this.getAttribute("name"),
value: this.selectable.getValue()
});
let detangled = detangle();
this._controllable.initial((initial) => initial && this.selectable.setValue(initial));
this._controllable.getter(() => this.selectable.getValue());
this._controllable.setter(detangled((value3) => this.selectable.setValue(value3)));
this.observable.subscribe(ObservableTrigger2.SELECTION, detangled(() => {
this.dispatchEvent(new Event("select", { bubbles: false, cancelable: true }));
this._controllable.dispatch();
}));
this.observable.subscribe(ObservableTrigger2.SELECTION, () => {
this._submittable.update(this.selectable.getValue());
});
this.observable.subscribe(ObservableTrigger2.VIEW_CHANGE, () => {
this.dispatchEvent(new Event("navigate", { bubbles: false, cancelable: true }));
});
}
unmount() {
if (this._dialogable?.getState()) {
let { unlock } = lockScroll();
unlock();
}
}
showIOSOverlay(inputEl) {
let overlay = document.createElement("button");
overlay.setAttribute("data-flux-ios-overlay", "");
overlay.setAttribute("data-appended", "");
overlay.classList.add("absolute", "inset-0");
inputEl.after(overlay);
}
input() {
return this.querySelector("input");
}
clear() {
this.selectable.setValue(null);
}
open() {
this._dialogable.setState(true);
}
close() {
this._dialogable.setState(false);
}
trigger() {
return this.triggerEl;
}
};
var UISelectedDate = class extends UIElement {
bootWithCalendar() {
this.picker = this.closest("ui-date-picker");
this.querySelectorAll("[data-appended]").forEach((el) => el.remove());
if (!this.querySelector('template[name="date"]')) {
let template = document.createElement("template");
template.setAttribute("name", "date");
template.innerHTML = "<div><slot></slot></div>";
this.appendChild(template);
}
this.templates = {
placeholder: this.querySelector('template[name="placeholder"]'),
date: this.querySelector('template[name="date"]')
};
this.picker.observable.subscribe(ObservableTrigger2.SELECTION, () => {
this.render(this.picker);
});
this.render(this.picker);
}
render(picker) {
this.templates.placeholder?.clearPlaceholder?.();
this.templates.date?.clearDate?.();
if (picker.selectable.hasSelection()) {
let { cleanup } = renderTemplate(this.templates.date, (hydrate) => {
return hydrate({ slots: { default: picker.selectable.display(this.picker.calendar.config.locale) } });
});
this.templates.date.clearDate = cleanup;
} else {
if (!this.templates.placeholder) return;
let { cleanup } = renderTemplate(this.templates.placeholder, (hydrate) => {
return hydrate({ slots: {} });
});
this.templates.placeholder.clearPlaceholder = cleanup;
}
}
};
var UIDatePickerSelect = class extends UIElement {
bootWithCalendar() {
this.picker = this.closest("ui-date-picker");
this.picker.selectable.blockSyncIf(() => {
return this.getBoundingClientRect().width > 0;
});
initFauxButton(this, () => this.picker._disableable.isDisabled(), () => {
this.picker.selectable.sync();
this.picker._dialogable.setState(false);
});
}
};
element("date-picker", UIDatePicker);
element("date-picker-select", UIDatePickerSelect);
element("selected-date", UISelectedDate);
inject(({ css }) => css`ui-date-picker { display: block; }`);
inject(({ css }) => css`
/* For Chrome, Safari, Edge */
ui-date-picker input[type="date"]::-webkit-calendar-picker-indicator {
display: none;
-webkit-appearance: none;
}
`);
function linkExpandedStateToPopover3(el, dialogable) {
setAttribute2(el, "aria-haspopup", "listbox");
let refreshPopover = () => {
setAttribute2(el, "aria-expanded", dialogable.getState() ? "true" : "false");
dialogable.getState() ? setAttribute2(el, "data-open", "") : removeAttribute(el, "data-open", "");
};
dialogable.onChange(() => {
refreshPopover();
});
refreshPopover();
}
function initPopover3(root, trigger, popover, dialogable, anchorable) {
let refreshPopover = () => {
Array.from([root, popover]).forEach((i) => {
dialogable.getState() ? setAttribute2(i, "data-open", "") : removeAttribute(i, "data-open", "");
});
dialogable.getState() && anchorable.reposition();
};
dialogable.onChange(() => refreshPopover());
refreshPopover();
dialogable.onChange(() => {
if (dialogable.getState()) {
root.dispatchEvent(new Event("open", {
bubbles: false,
cancelable: false
}));
} else {
root.dispatchEvent(new Event("close", {
bubbles: false,
cancelable: false
}));
}
});
}
function controlPopoverWithKeyboard2(button, dialogable) {
on(button, "keydown", (e) => {
if (!["ArrowDown", "ArrowUp", "Escape"].includes(e.key)) return;
if (e.key === "ArrowDown") {
if (!dialogable.getState()) {
dialogable.setState(true);
e.preventDefault();
e.stopImmediatePropagation();
}
} else if (e.key === "ArrowUp") {
if (!dialogable.getState()) {
dialogable.setState(true);
e.preventDefault();
e.stopImmediatePropagation();
}
} else if (e.key === "Escape") {
if (dialogable.getState()) {
dialogable.setState(false);
}
}
});
}
function togglePopoverWithMouse2(button, dialogable) {
on(button, "click", () => {
dialogable.setState(!dialogable.getState());
});
}
function highlightInputContentsWhenFocused2(input) {
on(input, "focus", () => input.select());
}
function preventScrollWhenPopoverIsOpen3(root, dialogable) {
let { lock, unlock } = lockScroll(dialogable.el);
dialogable.onChange(() => {
dialogable.getState() ? lock() : unlock();
});
}
function handlePopoverClosing3(root, mode, observable, selectable, dialogable) {
let closeOnSelect = mode !== CalendarModes.MULTIPLE;
if (root.hasAttribute("close")) {
let close = root.getAttribute("close");
closeOnSelect = close.split(" ").includes("auto");
if (close === "manual") closeOnSelect = false;
}
if (!closeOnSelect) return;
observable.subscribe(ObservableTrigger2.SELECTION, () => {
if (selectable.hasSelection()) {
dialogable.setState(false);
}
});
}
// js/composer.js
var UIComposer = class extends UIControl {
boot() {
setAttribute2(this, "role", "group");
this.config = {
submit: this.getAttribute("submit") || "cmd-enter",
rows: Number(this.getAttribute("rows")) || 2,
maxRows: Number(this.getAttribute("max-rows")) || 10
};
let textarea = this.querySelector("textarea");
let editor = this.querySelector("ui-editor");
if (textarea) {
this._inputEl = textarea;
this._initTextarea();
} else {
this._inputEl = editor;
this._initEditor();
}
this.state = {
onChanges: [],
getValue: () => {
return this._inputEl.value;
},
setValue: (value3) => {
this._inputEl.value = value3;
this.state.onChanges.forEach((i) => i(this.state.getValue()));
},
onChange: (callback) => {
this.state.onChanges.push(callback);
}
};
this._controllable = new Controllable(this);
this._disableable = new Disableable(this);
this._submittable = new Submittable(this, {
name: this.getAttribute("name"),
value: this.state.getValue()
});
this.state.onChange((value3) => {
this._submittable.update(value3);
});
this._controllable.initial((initial) => initial && this.state.setValue(initial));
this._controllable.getter(() => this.state.getValue());
this._controllable.setter((v) => this.state.setValue(v));
let undoDisableActions = () => {
};
this._disableable.onInitAndChange((disabled) => {
if (disabled) {
undoDisableActions = this._disableActions();
setAttribute2(this._inputEl, "disabled", "");
} else {
undoDisableActions();
undoDisableActions = () => {
};
removeAttribute(this._inputEl, "disabled");
}
});
on(this._inputEl, "input", (e) => {
this._controllable.dispatch();
e.stopPropagation();
});
}
_resizeTextarea() {
setAttribute2(this._inputEl, "style", "height: auto");
let style = window.getComputedStyle(this._inputEl);
let height = this._inputEl.scrollHeight;
let lineHeight = parseFloat(style.lineHeight);
if (isNaN(lineHeight)) {
lineHeight = parseFloat(style.fontSize) * 1.2;
}
let borderTop = parseFloat(style.borderTopWidth);
let borderBottom = parseFloat(style.borderBottomWidth);
let paddingTop = parseFloat(style.paddingTop);
let paddingBottom = parseFloat(style.paddingBottom);
let minHeight = this.config.rows * lineHeight;
let maxHeight = this.config.maxRows * lineHeight;
if (style.boxSizing === "border-box") {
height += borderTop + borderBottom;
minHeight += paddingTop + paddingBottom + borderTop + borderBottom;
maxHeight += paddingTop + paddingBottom + borderTop + borderBottom;
} else {
height -= paddingTop + paddingBottom;
}
if (height < minHeight) height = minHeight;
let overflow = "hidden";
if (height > maxHeight) {
height = maxHeight;
overflow = "auto";
}
setAttribute2(this._inputEl, "style", `height: ${height}px; overflow-y: ${overflow}`);
}
focusInput() {
this._inputEl.focus();
}
_resizeEditor() {
let contentEl = this._inputEl.querySelector('[data-slot="content"]');
if (!contentEl) return;
let style = window.getComputedStyle(contentEl);
let lineHeight = parseFloat(style.lineHeight);
if (isNaN(lineHeight)) {
lineHeight = parseFloat(style.fontSize) * 1.2;
}
let borderTop = parseFloat(style.borderTopWidth);
let borderBottom = parseFloat(style.borderBottomWidth);
let paddingTop = parseFloat(style.paddingTop);
let paddingBottom = parseFloat(style.paddingBottom);
let minHeight = this.config.rows * lineHeight;
let maxHeight = this.config.maxRows * lineHeight;
if (style.boxSizing === "border-box") {
minHeight += paddingTop + paddingBottom + borderTop + borderBottom;
maxHeight += paddingTop + paddingBottom + borderTop + borderBottom;
}
setAttribute2(contentEl, "style", `min-height: ${minHeight}px; max-height: ${maxHeight}px; height: auto; overflow-y: auto;`);
}
_initTextarea() {
if (!this._inputEl.hasAttribute("rows")) {
setAttribute2(this._inputEl, "rows", this.config.rows);
}
if (this.hasAttribute("placeholder")) {
setAttribute2(this._inputEl, "placeholder", this.getAttribute("placeholder"));
}
this._inputEl.addEventListener("input", () => this._resizeTextarea());
this._resizeTextarea();
on(this._inputEl, "keydown", (e) => this._handleSubmitKeydown(e));
}
_initEditor() {
if (this.hasAttribute("placeholder")) {
setAttribute2(this._inputEl, "placeholder", this.getAttribute("placeholder"));
}
this.addEventListener("flux:editor:ready", () => {
this._resizeEditor();
});
on(this._inputEl, "keydown", (e) => this._handleSubmitKeydown(e), { capture: true });
}
_handleSubmitKeydown(e) {
if (["cmd-enter", "super-enter", "ctrl-enter"].includes(this.config.submit) && (e.metaKey || e.ctrlKey) && e.key === "Enter") {
e.preventDefault();
e.stopPropagation();
this._submittable.submitEnclosingForm();
} else if (this.config.submit === "enter" && e.key === "Enter" && !e.shiftKey) {
e.preventDefault();
e.stopPropagation();
this._submittable.submitEnclosingForm();
} else if (this.config.submit === "shift-enter" && e.key === "Enter" && e.shiftKey) {
e.preventDefault();
e.stopPropagation();
this._submittable.submitEnclosingForm();
}
}
_disableActions() {
let undos = [];
let actionEls = this.querySelectorAll("button");
actionEls.forEach((el) => {
if (!el.hasAttribute("disabled")) {
setAttribute2(el, "disabled", "");
undos.push(() => {
removeAndReleaseAttribute(el, "disabled");
});
}
});
return () => {
undos.forEach((undo) => undo());
undos = [];
};
}
};
inject(({ css }) => css`ui-composer { display: block; }`);
element("composer", UIComposer);
// js/context.js
var UIContext = class extends UIElement {
boot() {
let trigger = this.trigger();
let overlay = this.overlay();
this._disabled = this.hasAttribute("disabled");
this._popoverable = new Popoverable(overlay);
this._anchorable = new Anchorable(overlay, {
reference: trigger,
auto: false,
position: this.hasAttribute("position") ? this.getAttribute("position") : void 0,
gap: this.hasAttribute("gap") ? this.getAttribute("gap") : void 0,
offset: this.hasAttribute("offset") ? this.getAttribute("offset") : void 0
});
let { lock, unlock } = lockScroll(this._popoverable.el);
this._popoverable.onChange(() => {
this._popoverable.getState() ? lock() : unlock();
});
on(trigger, "contextmenu", (e) => {
e.preventDefault();
this._anchorable.reposition(e.pageX, e.pageY);
this._popoverable.setState(true);
if (this.hasAttribute("detail")) {
setAttribute2(overlay, "data-detail", this.getAttribute("detail"));
}
});
if (this.hasAttribute("detail")) {
setAttribute2(overlay, "data-detail", "");
}
}
unmount() {
if (this.overlay()?._popoverable?.getState()) {
let { unlock } = lockScroll();
unlock();
}
}
trigger() {
return this.firstElementChild;
}
overlay() {
if (this.hasAttribute("target")) {
let target = this.getAttribute("target");
return document.getElementById(target);
} else {
return this.lastElementChild.matches("[popover]") && this.lastElementChild;
}
}
};
element("context", UIContext);
// js/mixins/focusable.js
var FocusableGroup = class extends MixinGroup {
groupOfType = Focusable;
boot({ options }) {
options({ wrap: false, ensureTabbable: true });
}
mount() {
this.options().ensureTabbable && this.ensureTabbable();
}
focusFirst() {
let target;
target = target || this.walker().find((i) => i.hasAttribute("autofocus"));
target = target || this.walker().find((i) => i.getAttribute("tabindex") === "0");
target = target || this.walker().find((i) => i.getAttribute("tabindex") === "-1");
target = target || this.walker().find((i) => isFocusable3(i));
target?.focus();
}
focusPrev() {
this.moveFocus((from) => {
return this.options().wrap ? this.walker().prevOrLast(from) : this.walker().prev(from);
});
}
focusNext() {
this.moveFocus((from) => {
return this.options().wrap ? this.walker().nextOrFirst(from) : this.walker().next(from);
});
}
focusBySearch(query) {
let found = this.walker().find((i) => i.textContent.toLowerCase().trim().startsWith(query.toLowerCase()));
found?.use(Focusable).tabbable();
found?.use(Focusable).focus();
}
moveFocus(callback) {
let tabbable = this.walker().find((i) => i.use(Focusable).isTabbable());
let to = callback(tabbable);
to?.use(Focusable).focus();
}
ensureTabbable() {
this.walker().findOrFirst((el) => {
el.use(Focusable).isTabbable();
})?.use(Focusable).tabbable();
}
wipeTabbables() {
this.walker().each((el) => {
el.use(Focusable).untabbable();
});
}
untabbleOthers(except) {
this.walker().each((el) => {
if (el === except) return;
el.use(Focusable).untabbable();
});
}
walker() {
return walker(this.el, (el, { skip, reject }) => {
if (el[this.constructor.name] && el !== this.el) return reject();
if (!el[this.groupOfType.name]) return skip();
if (el.hasAttribute("disabled")) return reject();
});
}
};
var Focusable = class extends Mixin {
groupedByType = FocusableGroup;
boot({ options }) {
options({ hover: false, disableable: null, tabbable: false, tabbableAttr: null });
}
mount() {
let disableable = this.options().disableable;
if (!disableable) throw "Focusable requires a Disableable instance...";
if (!this.el.hasAttribute("tabindex")) {
this.options().tabbable ? this.tabbable() : this.untabbable();
}
this.pauseFocusListener = this.on("focus", disableable.enabled(() => {
this.focus(false);
})).pause;
this.on("focus", disableable.enabled(() => {
isUsingKeyboard() && setAttribute2(this.el, "data-focus", "");
}));
this.on("blur", disableable.enabled(() => {
removeAttribute(this.el, "data-focus");
}));
this.options().hover && this.on("pointerenter", disableable.enabled(() => {
this.group()?.untabbleOthers(this.el);
this.tabbable();
}));
this.options().hover && this.on("pointerleave", disableable.enabled((e) => {
this.untabbable();
}));
}
focus(focusProgramatically = true) {
this.group()?.untabbleOthers(this.el);
this.tabbable();
focusProgramatically && this.pauseFocusListener(() => {
this.el.focus({ focusVisible: false });
});
}
tabbable() {
setAttribute2(this.el, "tabindex", "0");
this.options().tabbableAttr && setAttribute2(this.el, this.options().tabbableAttr, "");
}
untabbable() {
setAttribute2(this.el, "tabindex", "-1");
this.options().tabbableAttr && removeAttribute(this.el, this.options().tabbableAttr);
}
isTabbable() {
return this.el.getAttribute("tabindex") === "0";
}
};
// js/menu.js
var UIMenu = class _UIMenu extends UIElement {
boot() {
this._focusable = new FocusableGroup(this, { wrap: false, ensureTabbable: false });
on(this, "keydown", (e) => {
if (["ArrowDown"].includes(e.key)) {
e.target === this ? this._focusable.focusFirst() : this._focusable.focusNext();
e.preventDefault();
e.stopPropagation();
} else if (["ArrowUp"].includes(e.key)) {
e.target === this ? this._focusable.focusFirst() : this._focusable.focusPrev();
e.preventDefault();
e.stopPropagation();
}
});
search(this, (query) => this._focusable.focusBySearch(query));
if (this.hasAttribute("popover")) {
this.addEventListener("lofi-close-popovers", () => {
if (this.hasAttribute("keep-open")) return;
setTimeout(() => this.hidePopover(), 50);
});
}
if (this.parentElement.localName === "ui-dropdown") {
let dropdown = this.parentElement;
on(dropdown.trigger(), "keydown", (e) => {
if (e.key === "ArrowDown") {
this.fromArrowDown = true;
this.showPopover();
e.preventDefault();
e.stopPropagation();
}
});
}
setAttribute2(this, "role", "menu");
setAttribute2(this, "tabindex", "-1");
}
mount() {
this.initializeMenuItems();
let observer = new MutationObserver((mutations) => {
this.initializeMenuItems();
});
observer.observe(this, { childList: true, subtree: true });
}
onPopoverShow() {
queueMicrotask(() => {
if (this.fromArrowDown) {
this._focusable.focusFirst();
this.fromArrowDown = false;
} else {
this.focus();
}
});
}
onPopoverHide() {
this._focusable.wipeTabbables();
}
initializeMenuItems() {
this.walker().each((el) => {
if (el._disableable) return;
initializeMenuItem(el);
});
}
walker() {
return walker(this, (el, { skip, reject }) => {
if (el instanceof _UIMenu) return reject();
if (el instanceof UISelect) return reject();
if (!["a", "button"].includes(el.localName)) return skip();
});
}
};
var UISubmenu = class extends UIElement {
boot() {
}
};
var UIMenuCheckbox = class extends UIElement {
boot() {
this._disabled = this.hasAttribute("disabled");
this._disableable = new Disableable(this);
let button = this;
if (this._disabled) {
setAttribute2(button, "disabled", "");
setAttribute2(button, "aria-disabled", "true");
}
assignId(button, "menu-checkbox");
setAttribute2(button, "role", "menuitemcheckbox");
if (this._disabled) return;
button._focusable = new Focusable(button, { disableable: this._disableable, hover: true, tabbableAttr: "data-active" });
button._selectable = new Selectable(button, {
toggleable: true,
value: this.hasAttribute("value") ? this.getAttribute("value") : button.textContent.trim(),
label: this.hasAttribute("label") ? this.getAttribute("label") : button.textContent.trim(),
dataAttr: "data-checked",
ariaAttr: "aria-checked",
selectedInitially: this.hasAttribute("checked")
});
this._controllable = new Controllable(this);
this._controllable.initial((initial) => initial && button._selectable.setState(initial));
this._controllable.getter(() => button._selectable.getState());
let detangled = detangle();
this._controllable.setter(detangled((value3) => {
this._selectable.setState(value3);
}));
this._selectable.onChange(detangled(() => {
this._controllable.dispatch();
}));
on(button, "click", () => {
if (!this.hasAttribute("keep-open")) {
this.dispatchEvent(new CustomEvent("lofi-close-popovers", { bubbles: true }));
}
button._selectable.press();
});
respondToKeyboardClick(button);
}
};
var UIMenuRadio = class extends UIElement {
boot() {
this._disabled = this.hasAttribute("disabled");
this._disableable = new Disableable(this);
let button = this;
if (this._disabled) {
setAttribute2(button, "disabled", "");
setAttribute2(button, "aria-disabled", "true");
}
assignId(button, "menu-radio");
setAttribute2(button, "role", "menuitemradio");
if (this._disabled) return;
button._focusable = new Focusable(button, { disableable: this._disableable, hover: true, tabbableAttr: "data-active" });
button._selectable = new Selectable(button, {
toggleable: false,
value: this.hasAttribute("value") ? this.getAttribute("value") : button.textContent.trim(),
label: this.hasAttribute("label") ? this.getAttribute("label") : button.textContent.trim(),
dataAttr: "data-checked",
ariaAttr: "aria-checked",
selectedInitially: this.hasAttribute("checked")
});
on(button, "click", () => {
if (!this.hasAttribute("keep-open")) {
this.dispatchEvent(new CustomEvent("lofi-close-popovers", { bubbles: true }));
}
button._selectable.press();
});
respondToKeyboardClick(button);
}
};
var UIMenuRadioGroup = class extends UIElement {
boot() {
this._selectable = new SelectableGroup(this);
this._controllable = new Controllable(this);
setAttribute2(this, "role", "group");
this._controllable.initial((initial) => initial && this._selectable.setState(initial));
this._controllable.getter(() => this._selectable.getState());
let detangled = detangle();
this._controllable.setter(detangled((value3) => {
this._selectable.setState(value3);
}));
this._selectable.onChange(detangled(() => {
this._controllable.dispatch();
}));
on(this, "lofi-close-popovers", (e) => {
if (this.hasAttribute("keep-open")) {
e.preventDefault();
e.stopPropagation();
}
});
}
};
var UIMenuCheckboxGroup = class extends UIElement {
boot() {
this._selectable = new SelectableGroup(this, { multiple: true });
this._controllable = new Controllable(this);
setAttribute2(this, "role", "group");
this._controllable.initial((initial) => initial && this._selectable.setState(initial));
this._controllable.getter(() => this._selectable.getState());
let detangled = detangle();
this._controllable.setter(detangled((value3) => {
this._selectable.setState(value3);
}));
this._selectable.onChange(detangled(() => {
this._controllable.dispatch();
}));
}
};
inject(({ css }) => css`ui-menu[popover]:popover-open { display: block; }`);
inject(({ css }) => css`ui-menu[popover].\:popover-open { display: block; }`);
inject(({ css }) => css`ui-menu-checkbox, ui-menu-radio { cursor: default; display: contents; }`);
element("menu", UIMenu);
element("submenu", UISubmenu);
element("menu-checkbox", UIMenuCheckbox);
element("menu-radio", UIMenuRadio);
element("menu-radio-group", UIMenuRadioGroup);
element("menu-checkbox-group", UIMenuCheckboxGroup);
function respondToKeyboardClick(el) {
on(el, "keydown", (e) => {
if (e.key === "Enter") {
el.click();
e.preventDefault();
e.stopPropagation();
}
});
on(el, "keydown", (e) => {
if (e.key === " ") {
e.preventDefault();
e.stopPropagation();
}
});
on(el, "keyup", (e) => {
if (e.key === " ") {
el.click();
e.preventDefault();
e.stopPropagation();
}
});
}
function initializeMenuItem(el) {
el._disableable = new Disableable(el);
el._disabled = el.hasAttribute("disabled");
let link = el.querySelector("a");
let button = el;
let submenu = el.parentElement.matches("ui-submenu") && el.parentElement.querySelector("ui-menu[popover]");
let target = link || button;
if (el._disabled) {
setAttribute2(target, "disabled", "");
setAttribute2(target, "aria-disabled", "true");
}
assignId(target, "menu-item");
setAttribute2(target, "role", "menuitem");
if (el._disabled) return;
target._focusable = new Focusable(target, { disableable: el._disableable, hover: true, tabbableAttr: "data-active" });
if (!submenu) {
el.hasAttribute("disabled") || on(el, "click", () => {
if (!el.hasAttribute("keep-open")) {
el.dispatchEvent(new CustomEvent("lofi-close-popovers", { bubbles: true }));
}
});
respondToKeyboardClick(button);
} else {
submenu._popoverable = new Popoverable(submenu, { triggers: [button] });
submenu._anchorable = new Anchorable(submenu, {
reference: button,
position: submenu.hasAttribute("position") ? submenu.getAttribute("position") : isRTL() ? "left start" : "right start",
gap: submenu.hasAttribute("gap") ? submenu.getAttribute("gap") : "-5",
crossAxis: true
});
button.addEventListener("click", (e) => {
submenu._popoverable.setState(true);
});
let { clear } = interest(button, submenu, {
gain() {
submenu._popoverable.setState(true);
},
lose() {
submenu._popoverable.setState(false);
},
focusable: false,
useSafeArea: true
});
submenu._popoverable.onChange(() => {
if (!submenu._popoverable.getState()) {
clear();
submenu._focusable.wipeTabbables();
}
submenu._popoverable.getState() ? submenu._anchorable.reposition() : submenu._anchorable.cleanup();
});
on(button, "keydown", (e) => {
if (e.key === "Enter") {
submenu._popoverable.setState(true);
setTimeout(() => submenu._focusable.focusFirst());
}
});
on(button, "keydown", (e) => {
if (e.key === "ArrowRight") {
submenu._popoverable.setState(true);
setTimeout(() => submenu._focusable.focusFirst());
}
});
on(submenu, "keydown", (e) => {
if (e.key === "ArrowLeft") {
submenu._popoverable.setState(false);
button.focus();
e.stopPropagation();
}
});
}
}
// js/toolbar.js
var UIToolbar = class _UIToolbar extends UIElement {
mount() {
this._focusable = new FocusableGroup(this, { wrap: true });
this._disableable = new Disableable(this);
let undoDisableds = [];
this._disableable.onInitAndChange((disabled) => {
if (disabled) {
setAttribute2(this, "aria-disabled", "true");
this.walker().each((el) => {
if (!el.hasAttribute("disabled")) {
setAttribute2(el, "disabled", "true");
setAttribute2(el, "aria-disabled", "true");
undoDisableds.push(() => {
removeAndReleaseAttribute(el, "disabled");
removeAndReleaseAttribute(el, "aria-disabled");
});
}
});
} else {
removeAndReleaseAttribute(this, "aria-disabled");
undoDisableds.forEach((fn) => fn());
undoDisableds = [];
}
});
on(this, "keydown", (e) => {
if (["ArrowRight"].includes(e.key)) {
e.target === this ? this._focusable.focusFirst() : this._focusable.focusNext();
e.preventDefault();
e.stopPropagation();
} else if (["ArrowLeft"].includes(e.key)) {
e.target === this ? this._focusable.focusFirst() : this._focusable.focusPrev();
e.preventDefault();
e.stopPropagation();
}
});
setAttribute2(this, "role", "toolbar");
this.initializeToolbarItems();
}
initializeToolbarItems() {
this.walker().each((el) => {
if (el._disableable) return;
initializeToolbarItem(el);
});
}
walker() {
return walker(this, (el, { skip, reject }) => {
if (el instanceof _UIToolbar) return reject();
if (el.hasAttribute("popover")) return reject();
if (el instanceof UIMenu) return reject();
if (el instanceof UIOptions) return reject();
if (!["a", "button"].includes(el.localName)) return skip();
});
}
};
element("toolbar", UIToolbar);
function initializeToolbarItem(el) {
el._disableable = new Disableable(el);
el._disabled = el.hasAttribute("disabled");
let link = el.querySelector("a");
let button = el;
let target = link || button;
if (el._disabled) {
setAttribute2(target, "disabled", "");
setAttribute2(target, "aria-disabled", "true");
}
if (el._disabled) return;
target._focusable = new Focusable(target, { disableable: el._disableable });
}
// js/tooltip.js
var UITooltip = class extends UIElement {
boot() {
let type = this.hasAttribute("label") ? "label" : "description";
let button = this.button();
let overlay = this.overlay();
if (!button) {
return console.warn("ui-tooltip: no trigger element found", this);
} else if (!overlay) {
return;
}
overlay._popoverable = new Popoverable(overlay, { scope: "tooltip" });
overlay._anchorable = new Anchorable(overlay, {
reference: button,
position: this.hasAttribute("position") ? this.getAttribute("position") : void 0,
gap: this.hasAttribute("gap") ? this.getAttribute("gap") : void 0,
offset: this.hasAttribute("offset") ? this.getAttribute("offset") : void 0
});
overlay._popoverable.onChange(() => {
overlay._popoverable.getState() ? overlay._anchorable.reposition() : overlay._anchorable.cleanup();
});
this._disableable = new Disableable(this);
let removeInterest;
this._disableable.onInitAndChange((disabled) => {
if (removeInterest) {
removeInterest();
removeInterest = null;
}
if (!disabled) {
let result = interest(button, overlay, {
gain() {
overlay._popoverable.setState(true);
},
lose() {
overlay._popoverable.setState(false);
},
focusable: true,
useSafeArea: false
});
removeInterest = result.remove;
}
});
let id = assignId(overlay, "tooltip");
let interactive = this.hasAttribute("interactive");
let wantsLabel = this.hasAttribute("label") || button.textContent.trim() === "";
if (interactive) {
setAttribute2(button, "aria-controls", id);
setAttribute2(button, "aria-expanded", "false");
overlay._popoverable.onChange(() => {
overlay._popoverable.getState() ? setAttribute2(button, "aria-expanded", "true") : setAttribute2(button, "aria-expanded", "false");
});
} else {
if (wantsLabel) setAttribute2(button, "aria-labelledby", id);
else setAttribute2(button, "aria-describedby", id);
setAttribute2(overlay, "aria-hidden", "true");
}
setAttribute2(overlay, "role", "tooltip");
}
button() {
return this.firstElementChild;
}
overlay() {
return this.lastElementChild !== this.button() && this.lastElementChild.tagName !== "TEMPLATE" && this.lastElementChild;
}
};
element("tooltip", UITooltip);
// js/sidebar.js
var EVENTS = {
STATE_CHANGED: "stateChanged",
DESKTOP_COLLAPSED: "desktopCollapsed",
DESKTOP_EXPANDED: "desktopExpanded",
MOBILE_COLLAPSED: "mobileCollapsed",
MOBILE_EXPANDED: "mobileExpanded",
VIEWPORT_ENTER_MOBILE: "viewportEnterMobile",
VIEWPORT_ENTER_DESKTOP: "viewportEnterDesktop"
};
var UISidebar = class extends UIElement {
boot() {
this.config = {
breakpoint: this.hasAttribute("breakpoint") ? this.getAttribute("breakpoint") : 1024,
collapsible: false,
persist: this.hasAttribute("persist") ? ["false", "none"].includes(this.getAttribute("persist")) ? false : true : true,
sticky: this.hasAttribute("sticky") ? true : false
};
this.observable = new Observable();
this.state = {
active: false,
viewportDesktop: true,
viewportMobile: false,
collapsedMobile: true,
collapsedDesktop: false
};
if (this.config.sticky) {
this.setStickyPositionStyles();
}
if (this.hasAttribute("collapsible")) {
let value3 = this.getAttribute("collapsible");
if (value3 === "true") {
this.config.collapsible = true;
} else if (value3 === "false") {
this.config.collapsible = false;
} else if (value3 === "mobile") {
this.config.collapsible = "mobile";
}
}
if (this.config.persist && this.config.collapsible) {
this.state.collapsedDesktop = JSON.parse(localStorage.getItem("flux-sidebar-collapsed-desktop"));
}
this.removeAttribute("data-flux-sidebar-cloak");
this.observable.subscribe(EVENTS.VIEWPORT_ENTER_DESKTOP, () => {
let reapplyTransition = setStyle(this, "transition", "none");
setTimeout(reapplyTransition);
this.state.viewportDesktop = true;
this.state.viewportMobile = false;
this.observable.notify(EVENTS.STATE_CHANGED);
});
this.observable.subscribe(EVENTS.VIEWPORT_ENTER_MOBILE, () => {
let reapplyTransition = setStyle(this, "transition", "none");
setTimeout(reapplyTransition);
this.state.viewportDesktop = false;
this.state.viewportMobile = true;
this.observable.notify(EVENTS.STATE_CHANGED);
});
this.observable.subscribe(EVENTS.DESKTOP_COLLAPSED, () => {
this.state.collapsedDesktop = true;
this.observable.notify(EVENTS.STATE_CHANGED);
});
this.observable.subscribe(EVENTS.DESKTOP_EXPANDED, () => {
this.state.collapsedDesktop = false;
this.observable.notify(EVENTS.STATE_CHANGED);
});
this.observable.subscribe(EVENTS.MOBILE_COLLAPSED, () => {
this.state.collapsedMobile = true;
this.observable.notify(EVENTS.STATE_CHANGED);
});
this.observable.subscribe(EVENTS.MOBILE_EXPANDED, () => {
this.state.collapsedMobile = false;
this.observable.notify(EVENTS.STATE_CHANGED);
});
this.observable.subscribe(EVENTS.STATE_CHANGED, () => {
if (this.config.persist) {
localStorage.setItem("flux-sidebar-collapsed-desktop", JSON.stringify(this.state.collapsedDesktop));
}
this.updateDataAttributes(this);
});
new ViewportResizeObserver(this.observable, this.config);
document.addEventListener("flux-sidebar-toggle", () => {
if (this.state.viewportDesktop) {
this.state.collapsedDesktop ? this.observable.notify(EVENTS.DESKTOP_EXPANDED) : this.observable.notify(EVENTS.DESKTOP_COLLAPSED);
} else {
this.state.collapsedMobile ? this.observable.notify(EVENTS.MOBILE_EXPANDED) : this.observable.notify(EVENTS.MOBILE_COLLAPSED);
}
});
this.addEventListener("click", (e) => {
if (!(e.target === this)) return;
if (!this.state.collapsedDesktop) return;
this.observable.notify(EVENTS.DESKTOP_EXPANDED);
});
this.addEventListener("mouseenter", (e) => {
this.state.active = true;
this.observable.notify(EVENTS.STATE_CHANGED);
});
this.addEventListener("mouseleave", (e) => {
this.state.active = false;
this.observable.notify(EVENTS.STATE_CHANGED);
});
this.addEventListener("focusin", (e) => {
this.state.active = true;
this.observable.notify(EVENTS.STATE_CHANGED);
});
this.addEventListener("focusout", (e) => {
this.state.active = false;
this.observable.notify(EVENTS.STATE_CHANGED);
});
}
setStickyPositionStyles() {
let offsetTop = this.offsetTop;
let pageScrollYValue = window.pageYOffset;
if (pageScrollYValue > 0) {
window.scrollTo(window.scrollX, 0);
offsetTop = this.offsetTop;
window.scrollTo(window.scrollX, pageScrollYValue);
}
this.style.position = "sticky";
this.style.top = offsetTop + "px";
this.style.maxHeight = `calc(100dvh - ${offsetTop}px)`;
}
updateDataAttributes(el) {
let isFullCollapsible = this.config.collapsible === true;
if (isFullCollapsible) {
this.state.active ? setAttribute2(el, "data-flux-sidebar-active", "") : removeAndReleaseAttribute(el, "data-flux-sidebar-active");
}
if (this.state.viewportDesktop) {
removeAndReleaseAttribute(el, "data-flux-sidebar-on-mobile");
setAttribute2(el, "data-flux-sidebar-on-desktop", "");
removeAndReleaseAttribute(el, "data-flux-sidebar-collapsed-mobile");
if (this.state.collapsedDesktop) {
if (isFullCollapsible) {
setAttribute2(el, "data-flux-sidebar-collapsed-desktop", "");
}
} else {
removeAndReleaseAttribute(el, "data-flux-sidebar-collapsed-desktop");
}
} else {
removeAndReleaseAttribute(el, "data-flux-sidebar-on-desktop");
setAttribute2(el, "data-flux-sidebar-on-mobile", "");
removeAndReleaseAttribute(el, "data-flux-sidebar-collapsed-desktop");
if (this.state.collapsedMobile) {
setAttribute2(el, "data-flux-sidebar-collapsed-mobile", "");
} else {
removeAndReleaseAttribute(el, "data-flux-sidebar-collapsed-mobile");
}
}
}
};
var ViewportResizeObserver = class {
constructor(observable, { breakpoint }) {
this.observable = observable;
this.breakpoint = breakpoint;
this.watchForViewportChanges();
}
watchForViewportChanges() {
let breakpoint = typeof this.breakpoint === "number" ? `${this.breakpoint}px` : this.breakpoint;
let viewport = matchMedia(`(min-width: ${breakpoint})`);
viewport.matches ? this.observable.notify(EVENTS.VIEWPORT_ENTER_DESKTOP) : this.observable.notify(EVENTS.VIEWPORT_ENTER_MOBILE);
viewport.addEventListener("change", () => {
viewport.matches ? this.observable.notify(EVENTS.VIEWPORT_ENTER_DESKTOP) : this.observable.notify(EVENTS.VIEWPORT_ENTER_MOBILE);
});
}
};
var UISidebarToggle = class extends UIElement {
mount() {
let button = this.querySelector("button,ui-button");
on(button || this, "click", () => {
this.dispatchEvent(new CustomEvent("flux-sidebar-toggle", { bubbles: true }));
});
queueMicrotask(() => {
let sidebar = document.querySelector("ui-sidebar");
sidebar.updateDataAttributes(this);
sidebar.observable.subscribe(EVENTS.STATE_CHANGED, () => {
sidebar.updateDataAttributes(this);
});
});
}
};
element("sidebar", UISidebar);
element("sidebar-toggle", UISidebarToggle);
// js/slider.js
var UISlider = class extends UIControl {
boot() {
this.thumbs = this.querySelectorAll("[data-flux-slider-thumb]");
this.indicator = this.querySelector("[data-flux-slider-indicator]");
this.inputEls = this.querySelectorAll('input[type="range"]');
this.config = {
range: this.range(),
min: this.min(),
max: this.max(),
step: this.step(),
bigStep: this.bigStep(),
minStepsBetween: this.minStepsBetween(),
rangeStartString: this.rangeStartString(),
rangeEndString: this.rangeEndString()
};
this.state = {
onChanges: [],
getValue: () => {
return this.config.range ? [parseFloat(this.inputEls[0].value), parseFloat(this.inputEls[1].value)] : parseFloat(this.inputEls[0].value);
},
getValueAsArray: () => {
return this.config.range ? this.state.getValue() : [this.state.getValue()];
},
setValue: (value3) => {
if (this.config.range) {
this.inputEls[0].value = value3[0];
this.inputEls[1].value = value3[1];
} else {
this.inputEls[0].value = value3;
}
this.state.onChanges.forEach((i) => i(this.state.getValue()));
},
setValueInRange: (index, value3) => {
let newValues = [...this.state.getValue()];
newValues[index] = value3;
this.state.setValue(newValues);
},
setValueFromString: (value3) => {
if (this.config.range) {
this.state.setValue(value3.split(","));
} else {
this.state.setValue(value3);
}
},
increment: (index, increment) => {
let values = this.state.getValueAsArray();
if (this.config.range) {
values[index] = this.constrainRangeValue(index, values[index] + increment);
this.state.setValueInRange(index, values[index]);
} else {
this.state.setValue(clamp2(values[index] + increment, this.config.min, this.config.max));
}
},
onChange: (callback) => {
this.state.onChanges.push(callback);
}
};
this._controllable = new Controllable(this);
this._disableable = new Disableable(this);
this._submittable = new Submittable(this, {
name: this.getAttribute("name"),
value: this.state.getValue()
});
this.state.onChange((value3) => {
this.repositionThumbsAndIndicator();
this.updateTicks();
this._submittable.update(value3);
if (this.config.range) {
this.inputEls[0].ariaValueText = `${value3[0]} ${this.config.rangeStartString}`;
this.inputEls[1].ariaValueText = `${value3[1]} ${this.config.rangeEndString}`;
}
});
this._controllable.initial((initial) => initial && this.state.setValue(initial));
this._controllable.getter(() => this.state.getValue());
this._controllable.setter((v) => this.state.setValue(v));
this._disableable.onInitAndChange((disabled) => {
if (disabled) {
this.inputEls.forEach((el) => el.setAttribute("disabled", ""));
} else {
this.inputEls.forEach((el) => el.removeAttribute("disabled"));
}
});
this.setNativeInputAttributes();
this.setInitialValue();
this.setupExtraInputIfExists();
this.repositionTicks();
this.registerNativeInputListeners();
this.registerPointerListeners();
this.registerMutationObserver();
new ResizeObserver(() => {
this.repositionThumbsAndIndicator();
this.repositionTicks();
}).observe(this);
}
trigger() {
return this.inputEls[0];
}
setNativeInputAttributes() {
for (let i = 0; i < this.inputEls.length; i++) {
this.inputEls[i].setAttribute("min", this.config.min);
this.inputEls[i].setAttribute("max", this.config.max);
this.inputEls[i].setAttribute("step", this.config.step);
}
}
setInitialValue() {
if (this.hasAttribute("value")) {
this.state.setValueFromString(this.getAttribute("value"));
} else {
this.state.setValue(this.state.getValue());
}
}
setupExtraInputIfExists() {
let extraInput = this.closest("ui-field")?.querySelector("[data-flux-input] > input");
if (!extraInput) return;
this._disableable.onInitAndChange((disabled) => {
if (disabled) {
setAttribute2(extraInput, "disabled", "");
} else {
removeAttribute(extraInput, "disabled");
}
});
}
registerNativeInputListeners() {
for (let i = 0; i < this.inputEls.length; i++) {
on(this.inputEls[i], "input", (e) => {
e.stopPropagation();
});
on(this.inputEls[i], "change", (e) => {
let value3 = parseFloat(e.target.value);
if (this.config.range) {
value3 = this.constrainRangeValue(i, value3);
this.state.setValueInRange(i, value3);
} else {
this.state.setValue(value3);
}
this._controllable.dispatch();
e.stopPropagation();
});
on(this.inputEls[i], "keydown", (e) => {
if (!e.shiftKey) return;
switch (e.key) {
case "ArrowUp":
this.state.increment(i, this.config.bigStep);
break;
case "ArrowDown":
this.state.increment(i, this.config.bigStep * -1);
break;
case "ArrowRight":
this.state.increment(i, this.config.bigStep * (isRTL() ? -1 : 1));
break;
case "ArrowLeft":
this.state.increment(i, this.config.bigStep * (isRTL() ? 1 : -1));
break;
default:
return;
}
this._controllable.dispatch();
e.preventDefault();
});
on(this.inputEls[i], "focus", () => this.raiseThumb(i));
on(this.inputEls[i], "blur", () => this.lowerThumb(i));
}
}
registerPointerListeners() {
on(this, "pointerdown", (e) => {
if (this._disableable.isDisabled()) return;
if (e.button !== 0) return;
let index = this.getThumbIndexFromX(e.clientX);
let thumbRect = this.thumbs[index].getBoundingClientRect();
let thumbMidpoint = thumbRect.left + thumbRect.width / 2;
let pointerOffset = 0;
if (Math.abs(e.clientX - thumbMidpoint) < thumbRect.width / 2) {
pointerOffset = e.clientX - thumbMidpoint;
}
let initialValues = this.state.getValueAsArray();
let lastValues = this.state.getValueAsArray();
let setValue = (e2) => {
let value3 = this.getValueFromX(e2.clientX - pointerOffset);
if (this.config.range) {
value3 = this.constrainRangeValue(index, value3);
}
let newValues = [...lastValues];
newValues[index] = value3;
if (lastValues.toString() !== newValues.toString()) {
lastValues = newValues;
this.config.range ? this.state.setValueInRange(index, value3) : this.state.setValue(value3);
this.dispatchEvent(new Event("input", {
bubbles: false,
cancelable: true
}));
}
};
setValue(e);
this.setPointerCapture(e.pointerId);
requestAnimationFrame(() => {
this.inputEls[index].focus();
});
document.addEventListener("pointermove", setValue);
document.addEventListener("pointerup", (e2) => {
document.removeEventListener("pointermove", setValue);
this.releasePointerCapture(e2.pointerId);
requestAnimationFrame(() => {
this.lowerThumb(index);
});
if (initialValues.toString() !== lastValues.toString()) {
this.dispatchEvent(new Event("change", {
bubbles: false,
cancelable: true
}));
}
}, { once: true });
});
}
registerMutationObserver() {
let observer = new MutationObserver(() => {
this.config.min = this.min();
this.config.max = this.max();
this.config.step = this.step();
this.config.bigStep = this.bigStep();
this.config.minStepsBetween = this.minStepsBetween();
this.setNativeInputAttributes();
this.repositionThumbsAndIndicator();
this.repositionTicks();
});
observer.observe(this, {
attributes: true,
attributeFilter: ["min", "max", "step", "big-step", "min-steps-between"]
});
}
repositionThumbsAndIndicator() {
if (this.config.range) {
let value3 = this.state.getValue();
let startPercentage = this.getPercentageFromValue(value3[0]);
let endPercentage = this.getPercentageFromValue(value3[1]);
this.thumbs[0].style.insetInlineStart = startPercentage + "%";
this.thumbs[1].style.insetInlineStart = endPercentage + "%";
this.indicator.style.insetInlineStart = startPercentage + "%";
this.indicator.style.insetInlineEnd = 100 - endPercentage + "%";
} else {
let value3 = this.state.getValue();
let percentage = this.getPercentageFromValue(value3);
this.thumbs[0].style.insetInlineStart = percentage + "%";
this.indicator.style.insetInlineStart = 0;
this.indicator.style.insetInlineEnd = 100 - percentage + "%";
}
}
repositionTicks() {
this.querySelectorAll("[data-flux-slider-tick]").forEach((tick) => {
let tickValue = parseFloat(tick.getAttribute("data-value"));
if (isNaN(tickValue)) return;
let percentage = this.getPercentageFromValue(tickValue);
setAttribute2(tick, "style", `inset-inline-start: ${percentage}%`);
});
}
updateTicks() {
let values = this.state.getValueAsArray();
let activeRange = this.config.range ? values : [this.state.min, values[0]];
this.querySelectorAll("[data-flux-slider-tick]").forEach((tick) => {
let tickValue = parseFloat(tick.getAttribute("data-value"));
if (isNaN(tickValue)) return;
for (let i = 0; i < values.length; i++) {
if (values[i] == tickValue) {
setAttribute2(tick, "data-current", "");
} else {
removeAttribute(tick, "data-current");
}
}
if (tickValue >= activeRange[0] || tickValue <= activeRange[1]) {
setAttribute2(tick, "data-active", "");
} else {
removeAttribute(tick, "data-active");
}
});
}
raiseThumb(index) {
this.thumbs[index].style.zIndex = 10;
}
lowerThumb(index) {
this.thumbs[index].style.zIndex = null;
}
getThumbIndexFromX(x) {
let closestIndex;
let closestDistance;
for (let i = 0; i < this.thumbs.length; i++) {
let rect = this.thumbs[i].getBoundingClientRect();
let midpoint = (rect.left + rect.right) / 2;
let distance = Math.abs(midpoint - x);
if (closestDistance && Math.abs(closestDistance - distance) < rect.width / 2) {
let trackRect = this.getBoundingClientRect();
let distanceFromMax = trackRect.right - rect.right;
if (distanceFromMax < rect.width / 4) {
continue;
}
}
if (closestDistance === void 0 || distance <= closestDistance) {
closestDistance = distance;
closestIndex = i;
}
}
return closestIndex;
}
getPercentageFromValue(value3) {
let current = value3 - this.config.min;
let total = this.config.max - this.config.min;
if (total == 0) return 0;
let fraction = clamp2(current / total, 0, 100);
let trackRect = this.getBoundingClientRect();
let thumbRect = this.thumbs[0].getBoundingClientRect();
let trackPadding = thumbRect.width / 2;
let width = trackRect.width - trackPadding * 2;
let offset3 = width * fraction + trackPadding;
let adjustedPercentage = offset3 / trackRect.width * 100;
return adjustedPercentage;
}
getValueFromX(x) {
let min2 = this.config.min;
let max2 = this.config.max;
let step = this.config.step;
let trackRect = this.getBoundingClientRect();
let thumbRect = this.thumbs[0].getBoundingClientRect();
let trackPadding = thumbRect.width / 2;
let trackWidth = trackRect.width - trackPadding * 2;
let trackLeft = trackRect.left + trackPadding;
let relativeX = x - trackLeft;
let rescaled = clamp2(relativeX / trackWidth, 0, 1);
rescaled = isRTL() ? 1 - rescaled : rescaled;
let value3 = (max2 - min2) * rescaled + min2;
value3 = roundValueToStep(value3, step, min2);
value3 = clamp2(value3, min2, max2);
return value3;
}
constrainRangeValue(index, value3) {
let newValues = [...this.state.getValue()];
newValues[index] = value3;
let stepsBetween = (newValues[1] - newValues[0]) / this.config.step;
if (stepsBetween < this.config.minStepsBetween) {
let limits = [
newValues[1] - this.config.minStepsBetween * this.config.step,
newValues[0] + this.config.minStepsBetween * this.config.step
];
return limits[index];
}
return value3;
}
range() {
return this.hasAttribute("range");
}
min() {
return this.hasAttribute("min") ? parseFloat(this.getAttribute("min")) : 0;
}
max() {
return this.hasAttribute("max") ? parseFloat(this.getAttribute("max")) : 100;
}
step() {
if (!this.hasAttribute("step")) {
return 1;
}
let step = parseFloat(this.getAttribute("step"));
return step <= 0 || isNaN(step) ? 1 : step;
}
bigStep() {
if (!this.hasAttribute("big-step")) {
return this.step();
}
let bigStep = parseFloat(this.getAttribute("big-step"));
return bigStep <= 0 || isNaN(bigStep) ? this.step() : bigStep;
}
minStepsBetween() {
return this.hasAttribute("min-steps-between") ? parseFloat(this.getAttribute("min-steps-between")) : 0;
}
rangeStartString() {
return this.getAttribute("data-flux-aria-range-start") || "start range";
}
rangeEndString() {
return this.getAttribute("data-flux-aria-range-end") || "end range";
}
};
function clamp2(value3, min2, max2) {
return Math.min(Math.max(value3, min2), max2);
}
function roundValueToStep(value3, step, min2) {
let precision;
if (Math.abs(step) >= 1) {
precision = step.toString().split(".")[1]?.length || 0;
} else {
let parts = step.toExponential().split("e-");
let matissaDecimalPart = parts[0].split(".")[1];
precision = (matissaDecimalPart ? matissaDecimalPart.length : 0) + parseInt(parts[1], 10);
}
let nearest = Math.round((value3 - min2) / step) * step + min2;
return Number(nearest.toFixed(precision));
}
element("slider", UISlider);
// js/switch.js
var UISwitch = class extends UIControl {
boot() {
let button = this;
this._disableable = new Disableable(this);
this._selectable = new Selectable(button, {
toggleable: true,
dataAttr: "data-checked",
ariaAttr: "aria-checked",
value: this.hasAttribute("value") ? this.getAttribute("value") : null,
label: this.hasAttribute("label") ? this.getAttribute("label") : null,
selectedInitially: this.hasAttribute("checked")
});
this._submittable = new Submittable(this, {
name: this.getAttribute("name"),
value: this.getAttribute("value") ?? "on",
// Default value for checkboxes...
includeWhenEmpty: false,
shouldUpdateValue: false
});
this.value = this._selectable.getValue();
this._detangled = detangle();
this._selectable.onChange(this._detangled(() => {
this.dispatchEvent(new Event("input", { bubbles: false, cancelable: true }));
this.dispatchEvent(new Event("change", { bubbles: false, cancelable: true }));
}));
setAttribute2(button, "role", "switch");
this._selectable.onInitAndChange(() => {
this._submittable.update(this._selectable.getState());
});
this._disableable.onInitAndChange((disabled) => {
disabled ? removeAttribute(button, "tabindex", "0") : setAttribute2(button, "tabindex", "0");
});
on(button, "click", this._disableable.disabled((e) => {
e.preventDefault();
e.stopPropagation();
}), { capture: true });
on(button, "click", this._disableable.enabled((e) => {
this._selectable.press();
}));
on(button, "keydown", this._disableable.enabled((e) => {
if (e.key === "Enter") {
this._selectable.press();
e.preventDefault();
e.stopPropagation();
}
}));
on(button, "keydown", this._disableable.enabled((e) => {
if (e.key === " ") {
e.preventDefault();
e.stopPropagation();
}
}));
on(button, "keyup", this._disableable.enabled((e) => {
if (e.key === " ") {
this._selectable.press();
e.preventDefault();
e.stopPropagation();
}
}));
respondToLabelClick2(button);
}
get checked() {
return this._selectable.isSelected();
}
set checked(value3) {
this._detangled(() => {
value3 ? this._selectable.select() : this._selectable.deselect();
})();
}
};
function respondToLabelClick2(el) {
el.closest("label")?.addEventListener("click", (e) => {
if (!el.contains(e.target)) {
el.click();
}
});
}
inject(({ css }) => css`ui-switch { display: inline-block; user-select: none; }`);
element("switch", UISwitch);
// js/field.js
var UIField = class _UIField extends UIElement {
mount() {
this.control = this.fieldWalker().find((el) => this.isControl(el));
if (!this.control) return;
}
associateLabelWithControl(control) {
if (!control) return;
if (!this.label) return;
this.control = control;
if (this.control.hasAttribute("aria-labelledby")) return;
setAttribute2(this.elOrButton(this.control), "aria-labelledby", this.label.id);
if (this.control && !(this.control instanceof UIControl) && this.hasAttribute("disabled")) {
this.control.setAttribute("disabled", "");
}
}
associateDescriptionWithControl(control) {
if (!control) return;
if (!this.description) return;
this.control = control;
if (this.control.hasAttribute("aria-describedby")) return;
setAttribute2(this.elOrButton(this.control), "aria-describedby", this.description.id);
}
associateLabel(label) {
this.label = label;
on(label, "click", (e) => {
if (["a", "button", "ui-button"].includes(e.target.localName)) return;
this.focusOrTogggle(this.control);
});
this.control && this.associateLabelWithControl(this.control);
}
associateDescription(description) {
this.description = description;
this.control && this.associateDescriptionWithControl(this.control);
}
fieldWalker() {
return walker(this, (el, { skip, reject }) => {
if (el instanceof _UIField && el !== this) return reject();
if (el.parentElement.localName === "ui-editor" && el !== this) return reject();
});
}
isControl(el) {
if (el instanceof UIControl) return true;
if (el.matches("input, textarea, select")) return true;
return false;
}
focusOrTogggle(control) {
if (!control) return;
if (control.disabled || control.hasAttribute("disabled")) return;
let isCheckable = control.localName === "input" && ["checkbox", "radio"].includes(control.type) || ["ui-switch", "ui-radio", "ui-checkbox"].includes(control.localName);
if (isCheckable) {
control.click();
control.focus();
} else if (control.localName === "input" && ["file"].includes(control.type)) {
control.click();
} else if (["ui-select", "ui-date-picker", "ui-time-picker", "ui-otp", "ui-slider"].includes(control.localName)) {
control.trigger()?.focus();
} else if (["ui-editor"].includes(control.localName)) {
control.focus();
} else if (["ui-composer"].includes(control.localName)) {
control.focusInput();
} else {
control.focus();
}
}
elOrButton(el) {
if (el instanceof UIElement && el.firstElementChild instanceof HTMLButtonElement) return el.firstElementChild;
return el;
}
};
var UILabel = class extends UIElement {
mount() {
assignId(this, "label");
setAttribute2(this, "aria-hidden", "true");
this.closest("ui-field")?.associateLabel(this);
}
};
var UIDescription = class extends UIElement {
mount() {
assignId(this, "description");
setAttribute2(this, "aria-hidden", "true");
this.closest("ui-field")?.associateDescription(this);
}
};
inject(({ css }) => css`
ui-label { display: inline-block; cursor: default; }
ui-description { display: block; }
`);
element("field", UIField);
element("label", UILabel);
element("description", UIDescription);
// js/chart/chart.js
function generateChartObject(config) {
let scaleFns = {
"time": scaleTime,
"linear": scaleLinear,
"categorical": scaleCategorical
};
let dataMemoKey = Date.now();
let dimensionsMemoKey = Date.now();
let memoizedValues = {};
let memoize = (name, key, fn) => {
let memoKey = `${name}-${key}`;
for (let existingKey in memoizedValues) {
if (existingKey.startsWith(`${name}-`) && !existingKey.endsWith(String(key))) {
delete memoizedValues[existingKey];
}
}
if (!memoizedValues[memoKey]) {
memoizedValues[memoKey] = fn();
}
return memoizedValues[memoKey];
};
let chart = {
locale: config.locale,
data: [],
width: config.width,
height: config.height,
inset: config.inset,
axes: {
x: {
axis: "x",
key: config.axes.x.key,
format: config.axes.x.format,
inset: { start: 0, end: 0 },
position: config.axes.x.position || "bottom",
tickStart: config.axes.x.tickStart,
tickEnd: config.axes.x.tickEnd,
tickCount: config.axes.x.tickCount,
tickStep: config.axes.x.tickStep,
tickValues: config.axes.x.tickValues,
tickSuffix: config.axes.x.tickSuffix,
tickPrefix: config.axes.x.tickPrefix,
get rawValues() {
return memoize("x.rawValues", dataMemoKey, () => chart.data.map((d) => d[this.key]));
},
get type() {
return memoize("x.type", dataMemoKey, () => {
return config.axes.x.scale || (this.rawValues.every((v) => isDateish(v)) ? "time" : "categorical");
});
},
get interval() {
return memoize("x.interval", dataMemoKey, () => {
return config.axes.x.interval || "auto";
});
},
get values() {
return memoize("x.values", dataMemoKey, () => this.rawValues.map((v) => {
if (this.type === "time") {
return dateFromString(v);
} else if (this.type === "linear") {
return Number(v);
} else {
return v;
}
}));
},
get ticks() {
return memoize("x.ticks", dataMemoKey, () => {
let xTickValues = generateTickValues(chart.data, this, generateDomain(this.type, this.values));
let xTickLabels = generateTickLabels(xTickValues, this.type, this.format, this.tickSuffix, this.tickPrefix, this.interval, chart.locale);
return xTickValues.map((value3, index) => ({ value: value3, label: xTickLabels[index] }));
});
},
get domain() {
return memoize("x.domain", dataMemoKey, () => generateDomain(this.type, [...this.ticks.map((t) => t.value), ...this.values]));
},
get range() {
return memoize("x.range", dimensionsMemoKey, () => [chart.inset.left + this.inset.start, chart.width - chart.inset.right - this.inset.end]);
},
get scale() {
return memoize("x.scale", dimensionsMemoKey + dataMemoKey, () => scaleFns[this.type](this.domain, this.range, this.values));
}
},
y: {
axis: "y",
keys: config.axes.y.keys,
format: config.axes.y.format,
inset: { start: 0, end: 0 },
position: config.axes.y.position || "left",
tickStart: config.axes.y.tickStart,
tickEnd: config.axes.y.tickEnd,
tickCount: config.axes.y.tickCount,
tickStep: config.axes.y.tickStep,
tickValues: config.axes.y.tickValues,
tickSuffix: config.axes.y.tickSuffix,
tickPrefix: config.axes.y.tickPrefix,
get values() {
return memoize("y.values", dataMemoKey, () => chart.data.flatMap((d) => this.keys.reduce((acc, key) => {
if (d[key] === void 0) {
return acc;
}
acc.push(d[key]);
return acc;
}, [])));
},
get type() {
return memoize("y.type", dataMemoKey, () => {
return config.axes.y.scale || "linear";
});
},
get interval() {
return memoize("y.interval", dataMemoKey, () => {
return config.axes.y.interval || "auto";
});
},
get ticks() {
return memoize("y.ticks", dataMemoKey, () => {
let yTickValues = generateTickValues(chart.data, this, generateDomain(this.type, this.values));
let yTickLabels = generateTickLabels(yTickValues, this.type, this.format, this.tickSuffix, this.tickPrefix, this.interval, chart.locale);
return yTickValues.map((value3, index) => ({ value: value3, label: yTickLabels[index] }));
});
},
get domain() {
return memoize("y.domain", dataMemoKey, () => generateDomain(this.type, [...this.ticks.map((t) => t.value), ...this.values]));
},
get range() {
return memoize("y.range", dimensionsMemoKey, () => [chart.height - chart.inset.bottom - this.inset.end, chart.inset.top + this.inset.start]);
},
get scale() {
return memoize("y.scale", dimensionsMemoKey + dataMemoKey, () => scaleFns[this.type](this.domain, this.range, this.values));
}
}
},
get series() {
return memoize("series", dataMemoKey + dimensionsMemoKey, () => this.axes.y.keys.reduce((acc, key) => {
if (!chart.data[0].hasOwnProperty(key)) {
console.warn(`ui-chart: series field "${key}" does not exist`);
return acc;
}
let points = chart.data.map((datum) => ({
x: chart.axes.x.scale(datum[chart.axes.x.key]),
y: chart.axes.y.scale(datum[key]),
datum
}));
let series = {
field: key,
values: chart.data.map((d) => d[key]),
linePath(curve = "smooth") {
let points2 = this.points.map((p) => [p.x, p.y]);
return {
smooth: smoothX,
none: noCurve
}[curve](points2);
},
areaPath(curve = "smooth") {
let linePath = {
smooth: smoothX,
none: noCurve
}[curve](this.points.map((p) => [p.x, p.y]));
let areaPath = `${linePath} L${chart.axes.x.scale(chart.axes.x.domain[1])},${chart.axes.y.scale(chart.axes.y.domain[0])} L${chart.axes.x.scale(chart.axes.x.domain[0])},${chart.axes.y.scale(chart.axes.y.domain[0])} Z`;
return areaPath;
},
points
};
acc[key] = series;
return acc;
}, {}));
},
closestXPoint(xPosition) {
return this.closestXPoints(xPosition)[0];
},
closestXPoints(xPosition) {
return memoize("closestXPoints", dataMemoKey + dimensionsMemoKey + xPosition, () => {
let closestPoints = [];
let minDistance = Infinity;
Object.values(this.series).forEach((series) => {
let lastPoint = null;
series.points.forEach((point) => {
const distance = Math.abs(point.x - xPosition);
if (distance < minDistance) {
minDistance = distance;
lastPoint = point;
}
});
lastPoint && closestPoints.push(lastPoint);
});
return closestPoints;
});
},
updateDimensions(dimensions, inset) {
this.width = dimensions.width;
this.height = dimensions.height;
this.inset = inset;
dimensionsMemoKey = Date.now();
},
updateData(rawData) {
let data = JSON.parse(JSON.stringify(rawData));
if (data[0] !== void 0 && typeof data[0] !== "object") {
data = data.map((d, i) => {
return {
value: d
};
});
}
if (!data.every((d) => d.index)) {
data.forEach((d, i) => {
d.index = i;
});
}
this.data = data;
dataMemoKey = Date.now();
}
};
chart.updateData(config.data);
return chart;
}
function generateDomain(type, values) {
let deduplicatedValues = [...new Set(values)];
if (type === "time") {
return generateTimeDomain(deduplicatedValues);
} else if (type === "linear") {
deduplicatedValues.sort((a, b) => Number(a) - Number(b));
if (deduplicatedValues.length === 1) {
if (deduplicatedValues[0] === 0) {
return [
Number(deduplicatedValues[0]),
1
];
} else if (deduplicatedValues[0] > 0) {
return [
0,
Number(deduplicatedValues[0])
];
} else {
return [
Number(deduplicatedValues[0]),
0
];
}
}
return [Number(deduplicatedValues[0]), Number(deduplicatedValues[deduplicatedValues.length - 1])];
} else {
return [
deduplicatedValues[0],
deduplicatedValues[deduplicatedValues.length - 1]
];
}
}
function generateTickValues(data, axis, domain) {
let tickValues = [];
if (axis.type === "linear") {
if (axis.tickValues) {
return axis.tickValues;
}
let [minValue, maxValue] = domain;
let targetCount = axis.tickCount ? Number(axis.tickCount) : 5;
let tickStart = axis.tickStart === 0 || axis.tickStart === "0" ? 0 : axis.tickStart || "auto";
let tickEnd = axis.tickEnd === 0 || axis.tickEnd === "0" ? 0 : axis.tickEnd || "auto";
if (tickStart === "auto" && minValue > 0 && maxValue > 0) {
minValue = 0;
}
if (tickEnd !== "auto" && tickEnd !== "max" && !isNaN(Number(tickEnd))) {
maxValue = Number(tickEnd);
}
let interval = Number(axis.interval);
let niceStep;
if (axis.interval === "auto" || Number.isNaN(interval)) {
let range = maxValue - minValue;
let rawStep = range / (targetCount - 1);
let magnitude = Math.pow(10, Math.floor(Math.log10(rawStep)));
let normalizedStep = rawStep / magnitude;
if (normalizedStep < 1.5) niceStep = 1;
else if (normalizedStep < 3) niceStep = 2;
else if (normalizedStep < 7) niceStep = 5;
else niceStep = 10;
niceStep *= magnitude;
} else {
niceStep = interval;
}
let start;
if (tickStart === "auto") {
start = Math.floor(minValue / niceStep) * niceStep;
} else if (tickStart === "min") {
start = minValue;
} else {
start = Number(tickStart);
}
let currentTick = start;
while (currentTick <= maxValue + niceStep * 0.1) {
if (currentTick >= minValue - niceStep * 0.1) {
tickValues.push(currentTick);
}
currentTick += niceStep;
}
if (tickEnd === "max") {
if (Math.abs(tickValues[tickValues.length - 1] - domain[1]) > niceStep * 0.1) {
tickValues.push(domain[1]);
}
} else if (tickEnd !== "auto" && !isNaN(Number(tickEnd))) {
const end = Number(tickEnd);
const count = tickValues.length;
tickValues = Array.from(
{ length: count },
(_, i) => start + (end - start) * (i / (count - 1))
);
}
if (tickValues.length > targetCount * 2) {
let step = Math.ceil(tickValues.length / targetCount);
tickValues = tickValues.filter((_, i) => i % step === 0);
}
} else if (axis.type === "time") {
let [_, ticks] = generateDateFormatAndTicks(domain[0], domain[1], axis.tickCount, axis.interval);
return ticks;
} else if (axis.type === "categorical") {
data.forEach((datum) => {
let value3 = datum[axis.key];
tickValues.push(value3);
});
if (axis.tickCount && tickValues.length > axis.tickCount) {
const step = Math.ceil(tickValues.length / axis.tickCount);
tickValues = tickValues.filter((_, i) => i % step === 0);
}
}
return tickValues;
}
function generateTickLabels(tickValues, type, format, tickSuffix, tickPrefix, interval, locale) {
let labels = [];
if (type === "time") {
if (!format) {
[format] = generateDateFormatAndTicks(tickValues[0], tickValues[tickValues.length - 1], null, interval);
}
format = { ...format, timeZone: "UTC" };
labels = tickValues.map((value3) => new Date(value3).toLocaleString(locale, format));
} else if (type === "linear") {
if (format) labels = tickValues.map((value3) => value3.toLocaleString(locale, format));
else labels = tickValues.map((value3) => value3.toLocaleString(locale));
} else {
labels = tickValues.map((value3) => value3 + "");
}
if (tickPrefix) labels = labels.map((l) => tickPrefix + l);
if (tickSuffix) labels = labels.map((l) => l + tickSuffix);
return labels;
}
function scaleCategorical(domain, range, values) {
const uniqueValues = [...new Set(values)];
const step = (range[1] - range[0]) / (uniqueValues.length - 1);
const categoryMap = new Map(
uniqueValues.map((category, i) => [
category,
range[0] + i * step
])
);
return function(value3) {
if (value3 === null || value3 === void 0) {
return void 0;
}
return categoryMap.get(value3);
};
}
function scaleLinear(domain, range) {
const domainDiff = domain[1] - domain[0];
const rangeDiff = range[1] - range[0];
return function(value3) {
return range[0] + (value3 - domain[0]) * (rangeDiff / domainDiff);
};
}
function smoothX(points) {
if (points.length < 2) return "";
const sign = (x) => x < 0 ? -1 : 1;
const calculateSlope = (x0, y0, x1, y1, x2, y2) => {
const h0 = x1 - x0;
const h1 = x2 - x1;
const s0 = (y1 - y0) / (h0 || h1 < 0 && -0);
const s1 = (y2 - y1) / (h1 || h0 < 0 && -0);
const p = (s0 * h1 + s1 * h0) / (h0 + h1);
return (sign(s0) + sign(s1)) * Math.min(Math.abs(s0), Math.abs(s1), 0.5 * Math.abs(p)) || 0;
};
const endpointSlope = (x0, y0, x1, y1, t) => {
const h = x1 - x0;
return h ? (3 * (y1 - y0) / h - t) / 2 : t;
};
let path = `M${points[0][0]},${points[0][1]}`;
if (points.length === 2) {
return path + `L${points[1][0]},${points[1][1]}`;
}
for (let i = 0; i < points.length - 2; i++) {
const p0 = points[i];
const p1 = points[i + 1];
if (p0[0] === p1[0] && p0[1] === p1[1]) continue;
const p2 = points[i + 2];
const t1 = calculateSlope(p0[0], p0[1], p1[0], p1[1], p2[0], p2[1]);
const dx = (p1[0] - p0[0]) / 3;
const c1x = p0[0] + dx;
const c1y = p0[1] + dx * (i === 0 ? endpointSlope(p0[0], p0[1], p1[0], p1[1], t1) : points[i - 1] ? calculateSlope(points[i - 1][0], points[i - 1][1], p0[0], p0[1], p1[0], p1[1]) : t1);
const c2x = p1[0] - dx;
const c2y = p1[1] - dx * t1;
path += `C${c1x},${c1y} ${c2x},${c2y} ${p1[0]},${p1[1]}`;
}
const n = points.length;
const last = points[n - 1];
const secondLast = points[n - 2];
if (!(last[0] === secondLast[0] && last[1] === secondLast[1])) {
const t0 = calculateSlope(
points[n - 3][0],
points[n - 3][1],
secondLast[0],
secondLast[1],
last[0],
last[1]
);
const dx = (last[0] - secondLast[0]) / 3;
const c1x = secondLast[0] + dx;
const c1y = secondLast[1] + dx * t0;
const c2x = last[0] - dx;
const c2y = last[1] - dx * endpointSlope(secondLast[0], secondLast[1], last[0], last[1], t0);
path += `C${c1x},${c1y} ${c2x},${c2y} ${last[0]},${last[1]}`;
}
return path;
}
function simpleCurve(points, smoothing = 0.05) {
if (!points || points.length < 2) return "";
let path = `M ${points[0][0]} ${points[0][1]}`;
for (let i = 1; i < points.length; i++) {
const current = points[i];
const previous = points[i - 1];
const prevPoint = points[i - 2] || previous;
const nextPoint = points[i + 1] || current;
const cp1x = previous[0] + (nextPoint[0] - prevPoint[0]) * smoothing;
const cp1y = previous[1] + (nextPoint[1] - prevPoint[1]) * smoothing;
const cp2x = current[0] - (nextPoint[0] - prevPoint[0]) * smoothing;
const cp2y = current[1] - (nextPoint[1] - prevPoint[1]) * smoothing;
path += ` C ${cp1x} ${cp1y}, ${cp2x} ${cp2y}, ${current[0]} ${current[1]}`;
}
return path;
}
function noCurve(points) {
return simpleCurve(points, 0);
}
function isDateish(value3) {
return value3 instanceof Date || typeof value3 === "string" && value3.includes("-") && !isNaN(Date.parse(value3));
}
function generateTimeDomain(values) {
values.sort((a, b) => {
if (typeof a === "string") {
return a.localeCompare(b);
}
return a - b;
});
return [
dateFromString(values[0]),
dateFromString(values[values.length - 1])
];
}
function scaleTime(domain, range) {
let minValue = new Date(domain[0]).getTime();
let maxValue = new Date(domain[1]).getTime();
let domainDiff = maxValue - minValue;
let rangeDiff = range[1] - range[0];
return function(value3) {
if (!value3) return void 0;
const dateValue = dateFromString(value3);
if (isNaN(dateValue.getTime())) return void 0;
const percent = (dateValue.getTime() - minValue) / domainDiff;
return range[0] + percent * rangeDiff;
};
}
function generateDateFormatAndTicks(start, end, tickCount, interval) {
let startDate = start;
let endDate = end;
const diffMs = endDate - startDate;
const diffSeconds = diffMs / 1e3;
const diffMinutes = diffSeconds / 60;
const diffHours = diffMinutes / 60;
const diffDays = diffHours / 24;
const diffMonths = diffDays / 30;
const diffYears = diffDays / 365;
let format;
let incrementFn;
let firstTick;
switch (interval) {
case "second":
format = { hour: "numeric", minute: "numeric", second: "numeric" };
incrementFn = (date) => new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds() + 1));
firstTick = new Date(Date.UTC(startDate.getUTCFullYear(), startDate.getUTCMonth(), startDate.getUTCDate(), startDate.getUTCHours(), startDate.getUTCMinutes(), startDate.getUTCSeconds()));
break;
case "minute":
format = { hour: "numeric", minute: "numeric" };
incrementFn = (date) => new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours(), date.getUTCMinutes() + 1));
firstTick = new Date(Date.UTC(startDate.getUTCFullYear(), startDate.getUTCMonth(), startDate.getUTCDate(), startDate.getUTCHours(), startDate.getUTCMinutes()));
break;
case "hour":
format = { hour: "numeric", minute: "numeric" };
incrementFn = (date) => new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours() + 1));
firstTick = new Date(Date.UTC(startDate.getUTCFullYear(), startDate.getUTCMonth(), startDate.getUTCDate(), startDate.getUTCHours()));
break;
case "day":
format = { day: "numeric" };
incrementFn = (date) => new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate() + 1));
firstTick = new Date(Date.UTC(startDate.getUTCFullYear(), startDate.getUTCMonth(), startDate.getUTCDate()));
break;
case "week":
format = { day: "numeric", month: "short" };
incrementFn = (date) => new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate() + 7));
firstTick = new Date(Date.UTC(startDate.getUTCFullYear(), startDate.getUTCMonth(), startDate.getUTCDate()));
break;
case "month":
format = { month: "short", day: "numeric" };
incrementFn = (date) => new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth() + 1, 1));
firstTick = new Date(Date.UTC(startDate.getUTCFullYear(), startDate.getUTCMonth(), 1));
break;
case "year":
format = { year: "numeric" };
incrementFn = (date) => new Date(Date.UTC(date.getUTCFullYear() + 1, 0, 1));
firstTick = new Date(Date.UTC(startDate.getUTCFullYear(), 0, 1));
break;
default:
}
if (incrementFn) {
} else if (diffHours < 1) {
format = { hour: "numeric", minute: "numeric" };
let hourStep = tickCount ? Math.max(1, Math.floor(diffMinutes / (tickCount - 1))) : 1;
incrementFn = (date) => new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours(), date.getUTCMinutes() + hourStep));
firstTick = new Date(Date.UTC(startDate.getUTCFullYear(), startDate.getUTCMonth(), startDate.getUTCDate(), startDate.getUTCHours()));
} else if (diffDays < 1) {
format = { hour: "numeric" };
let hourStep = tickCount ? Math.max(1, Math.floor(diffHours / (tickCount - 1))) : 1;
incrementFn = (date) => new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours() + hourStep));
firstTick = new Date(Date.UTC(startDate.getUTCFullYear(), startDate.getUTCMonth(), startDate.getUTCDate(), 0));
} else if (diffDays <= 7) {
format = { weekday: "short", hour: "numeric" };
let hourStep = tickCount ? Math.max(1, Math.floor(diffHours / (tickCount - 1))) : 6;
incrementFn = (date) => new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours() + hourStep));
firstTick = new Date(Date.UTC(startDate.getUTCFullYear(), startDate.getUTCMonth(), startDate.getUTCDate(), 0));
} else if (diffDays <= 30) {
format = { month: "short", day: "numeric" };
let dateStep = tickCount ? Math.max(1, Math.floor(diffDays / (tickCount - 1))) : 1;
incrementFn = (date) => new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate() + dateStep));
firstTick = new Date(Date.UTC(startDate.getUTCFullYear(), startDate.getUTCMonth(), startDate.getUTCDate()));
} else if (diffMonths <= 6) {
format = { month: "short", day: "numeric" };
let dateStep = tickCount ? Math.max(1, Math.floor(diffDays / (tickCount - 1))) : 7;
incrementFn = (date) => new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate() + dateStep));
firstTick = new Date(Date.UTC(startDate.getUTCFullYear(), startDate.getUTCMonth(), startDate.getUTCDate()));
} else if (diffYears < 2) {
format = { month: "short" };
let monthStep = tickCount ? Math.max(1, Math.floor(diffMonths / (tickCount - 1))) : 1;
incrementFn = (date) => new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth() + monthStep, 1));
firstTick = new Date(Date.UTC(startDate.getUTCFullYear(), startDate.getUTCMonth()));
} else {
format = { year: "numeric" };
let yearStep = tickCount ? Math.max(1, Math.floor(diffYears / (tickCount - 1))) : 1;
incrementFn = (date) => new Date(Date.UTC(date.getUTCFullYear() + yearStep, 0, 1));
firstTick = new Date(Date.UTC(startDate.getUTCFullYear(), 0, 1));
}
let ticks = [startDate];
let currentTick = startDate;
while (currentTick <= endDate) {
currentTick = incrementFn(currentTick);
if (currentTick <= endDate) {
ticks.push(new Date(currentTick.getTime()));
}
}
return [format, ticks];
}
function dateFromString(value3) {
if (value3 instanceof Date) return value3;
let {
year,
month,
day,
hour,
minute,
second,
millisecond
} = parseDateString(value3);
return new Date(Date.UTC(year, month - 1, day, hour, minute, second, millisecond));
}
function parseDateString(dateStr) {
const match = dateStr.match(/^(\d{4})(?:-(\d{2}))?(?:-(\d{2}))?(?:T(\d{2}):(\d{2}):(\d{2})(?:\.(\d+))?(Z)?)?$/);
if (!match) {
throw new Error("Invalid date format");
}
return {
year: match[1] ? parseInt(match[1], 10) : null,
month: match[2] ? parseInt(match[2], 10) : null,
day: match[3] ? parseInt(match[3], 10) : null,
hour: match[4] ? parseInt(match[4], 10) : null,
minute: match[5] ? parseInt(match[5], 10) : null,
second: match[6] ? parseInt(match[6], 10) : null,
millisecond: match[7] ? parseInt(match[7].padEnd(3, "0"), 10) : null,
utc: !!match[8]
};
}
// js/chart/index.js
var UIChart = class extends HTMLElement {
constructor() {
super();
this.querySelectorAll("[data-appended]").forEach((el) => el.remove());
let svgTemplate = this.querySelector('template[name="svg"]');
let svg = hydrateTemplate(svgTemplate);
svgTemplate.after(svg);
this.init(svgTemplate, svg);
}
init(svgTemplate, svg) {
this._data = this.hasAttribute("value") ? JSON.parse(this.getAttribute("value")) : [];
let locale = this.hasAttribute("locale") ? this.getAttribute("locale") : getLocale();
this._observable = new Observable();
this._selectable = { getState: () => this._data, setState: (value3) => {
this._data = value3;
this._observable.notify("data", this._data);
} };
this._controllable = new Controllable(this);
this._controllable.initial((initial) => initial && this._selectable.setState(initial));
this._controllable.getter(() => this._selectable.getState());
this._controllable.setter((value3) => {
this._selectable.setState(value3);
});
let templates = {
svg: svgTemplate,
lines: {},
areas: {},
points: {},
cursor: svgTemplate.content.querySelector('template[name="cursor"]'),
zeroLine: svgTemplate.content.querySelector('template[name="zero-line"]'),
axes: {
x: {
template: svgTemplate.content.querySelector('template[name="axis"][axis="x"]'),
axisLine: svgTemplate.content.querySelector('template[name="axis"][axis="x"] template[name="axis-line"]'),
gridLine: svgTemplate.content.querySelector('template[name="axis"][axis="x"] template[name="grid-line"]'),
tickMark: svgTemplate.content.querySelector('template[name="axis"][axis="x"] template[name="tick-mark"]'),
tickLabel: svgTemplate.content.querySelector('template[name="axis"][axis="x"] template[name="tick-label"]')
},
y: {
template: svgTemplate.content.querySelector('template[name="axis"][axis="y"]'),
axisLine: svgTemplate.content.querySelector('template[name="axis"][axis="y"] template[name="axis-line"]'),
gridLine: svgTemplate.content.querySelector('template[name="axis"][axis="y"] template[name="grid-line"]'),
tickMark: svgTemplate.content.querySelector('template[name="axis"][axis="y"] template[name="tick-mark"]'),
tickLabel: svgTemplate.content.querySelector('template[name="axis"][axis="y"] template[name="tick-label"]')
}
},
tooltip: this.querySelector('template[name="tooltip"]'),
summary: this.querySelector('template[name="summary"]')
};
svgTemplate.content.querySelectorAll('template[name="line"]').forEach((template) => {
templates.lines[template.getAttribute("field")] = template;
});
svgTemplate.content.querySelectorAll('template[name="area"]').forEach((template) => {
templates.areas[template.getAttribute("field")] = template;
});
svgTemplate.content.querySelectorAll('template[name="point"]').forEach((template) => {
templates.points[template.getAttribute("field")] = template;
});
let repositionCursorLine = () => {
};
let repositionTooltip = () => {
};
let updateSummary = () => {
};
let activatePoint = () => {
};
let cursorLine = null;
let overlay = null;
let tooltip = null;
let summary = null;
overlay = document.createElementNS("http://www.w3.org/2000/svg", "rect");
overlay.setAttribute("data-overlay", "");
overlay.setAttribute("fill", "none");
overlay.setAttribute("pointer-events", "all");
overlay.addEventListener("mousemove", throttle(function(event) {
repositionCursorLine(event);
repositionTooltip(event);
updateSummary(event);
activatePoint(event);
}, 1));
overlay.addEventListener("mouseleave", () => {
repositionCursorLine(null);
repositionTooltip(null);
updateSummary(null);
activatePoint(null);
});
svg.appendChild(overlay);
if (templates.cursor) {
cursorLine = hydrateSvgTemplate(templates.cursor);
cursorLine.setAttribute("data-cursor", "");
svg.appendChild(cursorLine);
}
if (templates.tooltip) {
tooltip = hydrateTemplate(templates.tooltip);
templates.tooltip.after(tooltip);
}
if (templates.summary) {
summary = hydrateTemplate(templates.summary);
templates.summary.after(summary);
}
let gutter = { left: 8, right: 8, top: 8, bottom: 8 };
if (templates.svg?.hasAttribute("gutter")) {
let values = templates.svg?.getAttribute("gutter").split(" ").map((i) => i.replace("px", "")).map(Number);
if (values.length === 1) {
gutter.top = values[0];
gutter.right = values[0];
gutter.bottom = values[0];
gutter.left = values[0];
} else if (values.length === 2) {
gutter.top = values[0];
gutter.right = values[1];
gutter.bottom = values[0];
gutter.left = values[1];
} else if (values.length === 3) {
gutter.top = values[0];
gutter.right = values[1];
gutter.bottom = values[2];
gutter.left = values[1];
} else if (values.length === 4) {
gutter.top = values[0];
gutter.right = values[1];
gutter.bottom = values[2];
gutter.left = values[3];
}
}
let [xKey, yKeys] = discoverXandYKeys(svg);
let chart = generateChartObject({
locale,
data: this._data,
width: svg.parentElement.getBoundingClientRect().width,
height: svg.parentElement.getBoundingClientRect().height,
inset: {
left: 0,
right: 0,
top: 0,
bottom: 0
},
axes: {
x: {
key: xKey,
format: templates.axes.x.template?.hasAttribute("format") ? JSON.parse(templates.axes.x.template?.getAttribute("format")) : null,
scale: templates.axes.x.template?.getAttribute("scale"),
interval: templates.axes.x.template?.getAttribute("interval"),
position: templates.axes.x.template?.getAttribute("position"),
tickCount: templates.axes.x.template?.getAttribute("tick-count") || templates.axes.x.tickLabel?.getAttribute("target-tick-count"),
tickStart: templates.axes.x.template?.getAttribute("tick-start"),
tickEnd: templates.axes.x.template?.getAttribute("tick-end"),
tickStep: templates.axes.x.template?.getAttribute("tick-step") ? Number(templates.axes.x.template?.getAttribute("tick-step")) : null,
tickSuffix: templates.axes.x.template?.getAttribute("tick-suffix"),
tickPrefix: templates.axes.x.template?.getAttribute("tick-prefix"),
tickValues: templates.axes.x.template?.hasAttribute("tick-values") ? JSON.parse(templates.axes.x.template?.getAttribute("tick-values")) : null
},
y: {
keys: yKeys,
format: templates.axes.y.template?.hasAttribute("format") ? JSON.parse(templates.axes.y.template?.getAttribute("format")) : null,
scale: templates.axes.y.template?.getAttribute("scale"),
interval: templates.axes.y.template?.getAttribute("interval"),
position: templates.axes.y.template?.getAttribute("position"),
tickCount: templates.axes.y.template?.getAttribute("tick-count") || templates.axes.y.tickLabel?.getAttribute("target-tick-count"),
tickStart: templates.axes.y.template?.getAttribute("tick-start"),
tickEnd: templates.axes.y.template?.getAttribute("tick-end"),
tickStep: templates.axes.y.template?.getAttribute("tick-step") ? Number(templates.axes.y.template?.getAttribute("tick-step")) : null,
tickSuffix: templates.axes.y.template?.getAttribute("tick-suffix"),
tickPrefix: templates.axes.y.template?.getAttribute("tick-prefix"),
tickValues: templates.axes.y.template?.hasAttribute("tick-values") ? JSON.parse(templates.axes.y.template?.getAttribute("tick-values")) : null
}
}
});
let redraw = (checkOverflow = true) => {
setAttribute2(svg, "viewBox", `0 0 ${chart.width} ${chart.height}`);
if (chart.data.length === 0) {
return;
}
if (chart.data.length === 1) {
console.warn("ui-chart: chart only has one data point so it cannot be rendered.");
return;
}
if (chart.data[0][chart.axes.x.key] === void 0) {
console.warn(`ui-chart: axis field "${chart.axes.x.key}" does not exist`);
return;
}
Object.entries(chart.series).forEach(([field, series]) => {
let line = svg.querySelector(`[data-line][data-series="${field}"]`);
let template = templates.lines[field];
if (template) {
let curve = template.getAttribute("curve") || "smooth";
if (!line) {
let lineEl = hydrateSvgTemplate(template);
lineEl.setAttribute("data-line", "");
lineEl.setAttribute("data-series", field);
lineEl.setAttribute("d", series.linePath(curve));
svg.appendChild(lineEl);
} else {
line.setAttribute("d", series.linePath(curve));
}
}
});
Object.entries(chart.series).forEach(([field, series]) => {
let area = svg.querySelector(`[data-area][data-series="${field}"]`);
let template = templates.areas[field];
if (template) {
let curve = template.getAttribute("curve") || "smooth";
if (!area) {
let areaEl = hydrateSvgTemplate(template);
areaEl.setAttribute("data-area", "");
areaEl.setAttribute("data-series", field);
areaEl.setAttribute("d", series.areaPath(curve));
svg.appendChild(areaEl);
} else {
area.setAttribute("d", series.areaPath(curve));
}
}
});
Object.entries(chart.series).forEach(([field, series]) => {
let pointGroupEl = svg.querySelector(`[data-point-group][data-series="${field}"]`);
let template = templates.points[field];
if (template) {
svg.querySelector(`[data-point-group][data-series="${field}"]`)?.remove();
pointGroupEl = document.createElementNS("http://www.w3.org/2000/svg", "g");
pointGroupEl.setAttribute("data-point-group", "");
pointGroupEl.setAttribute("data-series", field);
series.points.forEach((point) => {
let pointEl = hydrateSvgTemplate(template);
pointEl.setAttribute("data-point", "");
pointEl.setAttribute("data-series", field);
pointEl.setAttribute("cx", point.x);
pointEl.setAttribute("cy", point.y);
pointGroupEl.appendChild(pointEl);
});
svg.appendChild(pointGroupEl);
}
});
activatePoint = (event) => {
svg.querySelectorAll("[data-point-group]").forEach((pointGroupEl) => {
pointGroupEl.querySelectorAll("[data-point]").forEach((i) => i.removeAttribute("data-active"));
if (event) {
let mouseX = event.clientX - svg.getBoundingClientRect().left;
let mouseY = event.clientY - svg.getBoundingClientRect().top;
if (mouseX >= chart.inset.left && mouseX <= chart.width - chart.inset.right && mouseY >= chart.inset.top && mouseY <= chart.height - chart.inset.bottom) {
let closestPoints = chart.closestXPoints(mouseX);
closestPoints.forEach((point) => {
pointGroupEl.querySelectorAll(`[data-point][cx="${point.x}"]`).forEach((i) => i.setAttribute("data-active", ""));
});
}
} else {
pointGroupEl.querySelectorAll("[data-point]").forEach((i) => i.removeAttribute("data-active"));
}
});
};
if (templates.axes.x.template) {
if (templates.axes.x.axisLine) {
svg.querySelector('[data-axis-line][data-axis="x"]')?.remove();
let axisLineEl = hydrateSvgTemplate(templates.axes.x.axisLine);
axisLineEl.setAttribute("data-axis-line", "");
axisLineEl.setAttribute("data-axis", "x");
axisLineEl.setAttribute("x1", chart.axes.x.scale(chart.axes.x.domain[0]));
axisLineEl.setAttribute("x2", chart.axes.x.scale(chart.axes.x.domain[1]));
axisLineEl.setAttribute("y1", chart.axes.y.scale(chart.axes.y.domain[chart.axes.x.position === "bottom" ? 0 : 1]));
axisLineEl.setAttribute("y2", chart.axes.y.scale(chart.axes.y.domain[chart.axes.x.position === "bottom" ? 0 : 1]));
svg.appendChild(axisLineEl);
}
if (templates.axes.x.gridLine) {
svg.querySelector('[data-grid-line-group][data-axis="x"]')?.remove();
let gridLineGroupEl = document.createElementNS("http://www.w3.org/2000/svg", "g");
gridLineGroupEl.setAttribute("data-grid-line-group", "");
gridLineGroupEl.setAttribute("data-axis", "x");
chart.axes.x.ticks.forEach(({ value: value3 }) => {
let gridLineEl = hydrateSvgTemplate(templates.axes.x.gridLine);
gridLineEl.setAttribute("data-grid-line", "");
gridLineEl.setAttribute("data-axis", "x");
gridLineEl.setAttribute("x1", chart.axes.x.scale(value3));
gridLineEl.setAttribute("x2", chart.axes.x.scale(value3));
gridLineEl.setAttribute("y1", chart.inset.top);
gridLineEl.setAttribute("y2", chart.height - chart.inset.bottom);
gridLineGroupEl.appendChild(gridLineEl);
});
svg.appendChild(gridLineGroupEl);
}
if (templates.axes.x.tickMark) {
svg.querySelector('[data-tick-mark-group][data-axis="x"]')?.remove();
let tickMarkGroupEl = document.createElementNS("http://www.w3.org/2000/svg", "g");
tickMarkGroupEl.setAttribute("data-tick-mark-group", "");
tickMarkGroupEl.setAttribute("data-axis", "x");
chart.axes.x.ticks.forEach(({ value: value3, label }) => {
let position = { x: chart.axes.x.scale(value3), y: chart.axes.y.scale(chart.axes.y.domain[chart.axes.x.position === "bottom" ? 0 : 1]) };
let tickMarkEl = hydrateSvgTemplate(templates.axes.x.tickMark);
tickMarkEl.setAttribute("data-tick-mark", "");
tickMarkEl.setAttribute("data-axis", "x");
tickMarkEl.setAttribute("transform", `translate(${position.x}, ${position.y})`);
tickMarkGroupEl.appendChild(tickMarkEl);
});
svg.appendChild(tickMarkGroupEl);
}
if (templates.axes.x.tickLabel) {
svg.querySelector('[data-tick-label-group][data-axis="x"]')?.remove();
let tickLabelGroupEl = document.createElementNS("http://www.w3.org/2000/svg", "g");
tickLabelGroupEl.setAttribute("data-tick-label-group", "");
tickLabelGroupEl.setAttribute("data-axis", "x");
chart.axes.x.ticks.forEach(({ value: value3, label }) => {
let position = { x: chart.axes.x.scale(value3), y: chart.axes.y.scale(chart.axes.y.domain[chart.axes.x.position === "bottom" ? 0 : 1]) };
let tickLabelEl = hydrateSvgTemplate(templates.axes.x.tickLabel);
tickLabelEl.querySelectorAll("slot").forEach((i) => i.replaceWith(document.createTextNode(label)));
tickLabelEl.setAttribute("data-tick-label", "");
tickLabelEl.setAttribute("data-axis", "x");
tickLabelEl.setAttribute("transform", `translate(${position.x}, ${position.y})`);
tickLabelGroupEl.appendChild(tickLabelEl);
});
svg.appendChild(tickLabelGroupEl);
handleTickOverflow(tickLabelGroupEl, chart.axes.x);
}
}
if (templates.axes.y.template) {
if (templates.axes.y.axisLine) {
svg.querySelector('[data-axis-line][data-axis="y"]')?.remove();
let axisLineEl = hydrateSvgTemplate(templates.axes.y.axisLine);
axisLineEl.setAttribute("data-axis-line", "");
axisLineEl.setAttribute("data-axis", "y");
axisLineEl.setAttribute("x1", chart.axes.x.scale(chart.axes.x.domain[chart.axes.y.position === "left" ? 0 : 1]));
axisLineEl.setAttribute("x2", chart.axes.x.scale(chart.axes.x.domain[chart.axes.y.position === "left" ? 0 : 1]));
axisLineEl.setAttribute("y1", chart.axes.y.scale(chart.axes.y.domain[0]));
axisLineEl.setAttribute("y2", chart.axes.y.scale(chart.axes.y.domain[1]));
svg.appendChild(axisLineEl);
}
if (templates.axes.y.gridLine) {
svg.querySelector('[data-grid-line-group][data-axis="y"]')?.remove();
let gridLineGroupEl = document.createElementNS("http://www.w3.org/2000/svg", "g");
gridLineGroupEl.setAttribute("data-grid-line-group", "");
gridLineGroupEl.setAttribute("data-axis", "y");
chart.axes.y.ticks.forEach(({ value: value3, label }) => {
let position = { x: chart.axes.x.scale(chart.axes.x.domain[0]), y: chart.axes.y.scale(value3) };
let gridLineEl = hydrateSvgTemplate(templates.axes.y.gridLine);
gridLineEl.setAttribute("data-grid-line", "");
gridLineEl.setAttribute("data-axis", "y");
gridLineEl.setAttribute("x1", chart.inset.left);
gridLineEl.setAttribute("x2", chart.width - chart.inset.right);
gridLineEl.setAttribute("y1", position.y);
gridLineEl.setAttribute("y2", position.y);
gridLineGroupEl.appendChild(gridLineEl);
});
svg.appendChild(gridLineGroupEl);
}
if (templates.axes.y.tickMark) {
svg.querySelector('[data-tick-mark-group][data-axis="y"]')?.remove();
let tickMarkGroupEl = document.createElementNS("http://www.w3.org/2000/svg", "g");
tickMarkGroupEl.setAttribute("data-tick-mark-group", "");
tickMarkGroupEl.setAttribute("data-axis", "y");
chart.axes.y.ticks.forEach(({ value: value3, label }) => {
let position = { x: chart.axes.x.scale(chart.axes.x.domain[chart.axes.y.position === "left" ? 0 : 1]), y: chart.axes.y.scale(value3) };
let tickMarkEl = hydrateSvgTemplate(templates.axes.y.tickMark);
tickMarkEl.setAttribute("data-tick-mark", "");
tickMarkEl.setAttribute("data-axis", "y");
tickMarkEl.setAttribute("transform", `translate(${position.x}, ${position.y})`);
tickMarkGroupEl.appendChild(tickMarkEl);
});
svg.appendChild(tickMarkGroupEl);
}
if (templates.axes.y.tickLabel) {
svg.querySelector('[data-tick-label-group][data-axis="y"]')?.remove();
let tickLabelGroupEl = document.createElementNS("http://www.w3.org/2000/svg", "g");
tickLabelGroupEl.setAttribute("data-tick-label-group", "");
tickLabelGroupEl.setAttribute("data-axis", "y");
chart.axes.y.ticks.forEach(({ value: value3, label }) => {
let position = { x: chart.axes.x.scale(chart.axes.x.domain[chart.axes.y.position === "left" ? 0 : 1]), y: chart.axes.y.scale(value3) };
let tickLabelEl = hydrateSvgTemplate(templates.axes.y.tickLabel);
tickLabelEl.querySelectorAll("slot").forEach((i) => i.replaceWith(document.createTextNode(label)));
tickLabelEl.setAttribute("data-tick-label", "");
tickLabelEl.setAttribute("data-axis", "y");
tickLabelEl.setAttribute("transform", `translate(${position.x}, ${position.y})`);
tickLabelGroupEl.appendChild(tickLabelEl);
});
svg.appendChild(tickLabelGroupEl);
handleTickOverflow(tickLabelGroupEl, chart.axes.y);
}
}
if (templates.zeroLine && chart.axes.y.domain[0] < 0 && chart.axes.y.domain[1] > 0) {
svg.querySelector('[data-zero-line][data-axis="y"]')?.remove();
let zeroLineEl = hydrateSvgTemplate(templates.zeroLine);
zeroLineEl.setAttribute("data-zero-line", "");
zeroLineEl.setAttribute("data-axis", "y");
zeroLineEl.setAttribute("x1", chart.axes.x.scale(chart.axes.x.domain[0]));
zeroLineEl.setAttribute("x2", chart.axes.x.scale(chart.axes.x.domain[1]));
zeroLineEl.setAttribute("y1", chart.axes.y.scale(0));
zeroLineEl.setAttribute("y2", chart.axes.y.scale(0));
svg.appendChild(zeroLineEl);
}
if (overlay) {
overlay.setAttribute("width", chart.width);
overlay.setAttribute("height", chart.height);
overlay.setAttribute("x", 0);
overlay.setAttribute("y", 0);
}
if (cursorLine) {
repositionCursorLine = (event) => {
if (event) {
let mouseX = event.clientX - svg.getBoundingClientRect().left;
let mouseY = event.clientY - svg.getBoundingClientRect().top;
if (mouseX >= chart.inset.left && mouseX <= chart.width - chart.inset.right && mouseY >= chart.inset.top && mouseY <= chart.height - chart.inset.bottom) {
let closestXPoint = chart.closestXPoint(mouseX);
cursorLine.setAttribute("opacity", "1");
cursorLine.setAttribute("x1", closestXPoint.x);
cursorLine.setAttribute("x2", closestXPoint.x);
cursorLine.setAttribute("y1", chart.axes.y.scale(chart.axes.y.domain[0]));
cursorLine.setAttribute("y2", chart.axes.y.scale(chart.axes.y.domain[1]));
} else {
cursorLine.setAttribute("opacity", "0");
}
} else {
cursorLine.setAttribute("opacity", "0");
}
};
}
if (tooltip) {
repositionTooltip = (event) => {
if (event === null) {
removeAttribute(tooltip, "data-active");
} else {
let mouseX = event.clientX - svg.getBoundingClientRect().left;
let mouseY = event.clientY - svg.getBoundingClientRect().top;
if (mouseX >= chart.inset.left && mouseX <= chart.width - chart.inset.right && mouseY >= chart.inset.top && mouseY <= chart.height - chart.inset.bottom) {
let closestXPoint = chart.closestXPoint(mouseX);
if (closestXPoint) {
setAttribute2(tooltip, "data-active", "");
let tooltipRect = tooltip.getBoundingClientRect();
let svgRect = svg.getBoundingClientRect();
let rightSpace = svgRect.width - (closestXPoint.x + tooltipRect.width + 15);
let bottomSpace = svgRect.height - (mouseY + tooltipRect.height + 15);
let xOffset = rightSpace < 0 ? closestXPoint.x - tooltipRect.width - 15 : closestXPoint.x + 15;
let yOffset = bottomSpace < 0 ? mouseY - tooltipRect.height - 15 : mouseY + 15;
tooltip.style.transform = `translate(${xOffset}px, ${yOffset}px)`;
let tooltipClone = templates.tooltip.content.cloneNode(true).firstElementChild;
tooltipClone.querySelectorAll("slot").forEach((slot) => {
let field = slot.getAttribute("field");
if (field) {
let format = slot.hasAttribute("format") ? JSON.parse(slot.getAttribute("format")) : null;
let value3 = closestXPoint.datum[field];
if (format === null) return slot.textContent = value3;
format = { ...format, timeZone: "UTC" };
if (isNumeric(value3)) {
value3 = Number(value3).toLocaleString(chart.locale, format);
} else if (isDateish2(value3)) {
value3 = new Date(value3).toLocaleDateString(chart.locale, format);
}
slot.textContent = value3;
}
});
tooltip.innerHTML = tooltipClone.innerHTML;
} else {
removeAttribute(tooltip, "data-active");
}
} else {
removeAttribute(tooltip, "data-active");
}
}
};
}
if (summary) {
updateSummary = (event) => {
let closestXPoint = null;
if (event !== null) {
let mouseX = event.clientX - svg.getBoundingClientRect().left;
let mouseY = event.clientY - svg.getBoundingClientRect().top;
if (mouseX >= chart.inset.left && mouseX <= chart.width - chart.inset.right && mouseY >= chart.inset.top && mouseY <= chart.height - chart.inset.bottom) {
closestXPoint = chart.closestXPoint(mouseX);
}
}
closestXPoint = closestXPoint || chart.closestXPoint(chart.axes.x.range[1]);
if (closestXPoint) {
let summaryClone = templates.summary.content.cloneNode(true).firstElementChild;
summaryClone.querySelectorAll("slot").forEach((slot) => {
let field = slot.getAttribute("field");
if (field) {
let format = slot.hasAttribute("format") ? JSON.parse(slot.getAttribute("format")) : {};
format = { ...format, timeZone: "UTC" };
let value3 = slot.hasAttribute("fallback") && event === null ? slot.getAttribute("fallback") : closestXPoint.datum[field];
if (isNumeric(value3)) {
value3 = Number(value3).toLocaleString(chart.locale, format);
} else if (isDateish2(value3)) {
value3 = new Date(value3).toLocaleString(chart.locale, format);
}
slot.textContent = value3;
}
});
summary.innerHTML = summaryClone.innerHTML;
}
};
updateSummary(null);
}
svg.appendChild(overlay);
svg.querySelectorAll("[data-grid-line-group]").forEach((i) => overlay.before(i));
svg.querySelectorAll("[data-axis-line]").forEach((i) => overlay.before(i));
svg.querySelectorAll("[data-zero-line]").forEach((i) => overlay.before(i));
svg.querySelectorAll("[data-area]").forEach((i) => overlay.before(i));
svg.querySelectorAll("[data-line]").forEach((i) => overlay.before(i));
svg.querySelectorAll("[data-cursor]").forEach((i) => overlay.before(i));
svg.querySelectorAll("[data-point-group]").forEach((i) => overlay.before(i));
if (checkOverflow) {
let overflow = getSvgOverflow(svg);
chart.updateDimensions({ width: chart.width, height: chart.height }, {
left: gutter.left + overflow.left,
right: gutter.right + overflow.right,
top: gutter.top + overflow.top,
bottom: gutter.bottom + overflow.bottom
});
redraw(false);
}
};
this._observable.subscribe("resize", () => {
chart.updateDimensions({
width: svg.parentElement.getBoundingClientRect().width,
height: svg.parentElement.getBoundingClientRect().height
}, {
left: 0,
right: 0,
top: 0,
bottom: 0
});
redraw();
});
this._observable.subscribe("data", () => {
chart.updateData(this._data);
chart.updateDimensions({ width: chart.width, height: chart.height }, {
left: 0,
right: 0,
top: 0,
bottom: 0
});
redraw();
});
new ResizeObserver(() => {
this._observable.notify("resize");
}).observe(this);
new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if (mutation.attributeName !== "value") return;
this._selectable.setState(this.hasAttribute("value") ? JSON.parse(this.getAttribute("value")) : []);
});
}).observe(this, { attributes: true, attributeFilter: ["value"] });
}
};
customElements.define("ui-chart", UIChart);
function discoverXandYKeys(svg) {
let xKey = null;
let yKeys = [];
svg.querySelectorAll('template[name="line"], template[name="area"], template[name="point"]').forEach((template) => {
yKeys.push(template.getAttribute("field") || "value");
});
svg.querySelectorAll('template[name="axis"][axis="x"]').forEach((template) => {
xKey = template.getAttribute("field") || "index";
});
yKeys = Array.from(new Set(yKeys));
if (xKey === null) xKey = "index";
if (yKeys.length === 0) yKeys = ["value"];
return [xKey, yKeys];
}
function hydrateSvgTemplate(template) {
let svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
svg.setAttribute("xmlns", "http://www.w3.org/2000/svg");
svg.setAttribute("version", "1.1");
svg.innerHTML = template.innerHTML;
return svg.firstElementChild;
}
function handleTickOverflow(tickLabelGroupEl, axis) {
if (!hasOverlappingTicks(tickLabelGroupEl, axis)) return;
if (axis.axis === "x" && axis.type === "categorical") {
rotateTickLabels(tickLabelGroupEl);
} else if (axis.axis === "x" && axis.type === "time") {
let undo = hideEveryOtherTickLabel(tickLabelGroupEl);
if (!hasOverlappingTicks(tickLabelGroupEl, axis)) return;
undo();
onlyShowFirstAndLastTickLabel(tickLabelGroupEl);
}
}
function hasOverlappingTicks(tickLabelGroupEl, axis) {
let children = Array.from(tickLabelGroupEl.children);
children = children.filter((child) => {
return child.style.display != "none";
});
for (let i = 0; i < children.length; i++) {
let tickLabelEl = children[i];
let nextTickLabelEl = children[i + 1];
if (!nextTickLabelEl) break;
let tickLabelRect = tickLabelEl.getBoundingClientRect();
let nextTickLabelRect = nextTickLabelEl.getBoundingClientRect();
let overlapMargin = 20;
if (axis.axis === "y") {
if (tickLabelRect.bottom + overlapMargin < nextTickLabelRect.top) {
return true;
}
} else {
if (tickLabelRect.right + overlapMargin > nextTickLabelRect.left) {
return true;
}
}
}
return false;
}
function rotateTickLabels(tickLabelGroupEl) {
let undos = [];
Array.from(tickLabelGroupEl.children).forEach((child, index) => {
let textNode = child.matches("text") ? child : child.querySelector("text");
Array.from(tickLabelGroupEl.children).forEach((child2, index2) => {
let textNode2 = child2.matches("text") ? child2 : child2.querySelector("text");
if (textNode2) {
textNode2.style.transform = "rotate(-45deg)";
textNode2.style.textAnchor = "end";
undos.push(() => {
textNode2.style.transform = null;
textNode2.style.textAnchor = null;
});
}
});
});
return () => undos.forEach((undo) => undo());
}
function hideEveryOtherTickLabel(tickLabelGroupEl) {
let children = Array.from(tickLabelGroupEl.children);
children.forEach((child, index) => {
if (index % 2 === 1) child.style.display = "none";
});
return () => children.forEach((child, index) => {
child.style.display = "inline";
});
}
function onlyShowFirstAndLastTickLabel(tickLabelGroupEl) {
let children = Array.from(tickLabelGroupEl.children);
children.forEach((child, index) => {
child.style.display = "none";
});
let firstChild = children[0];
let lastChild = children[children.length - 1];
let firstTextNode = firstChild.matches("text") ? firstChild : firstChild.querySelector("text");
let lastTextNode = lastChild.matches("text") ? lastChild : lastChild.querySelector("text");
firstChild.style.display = "inline";
firstTextNode.style.textAnchor = "start";
lastChild.style.display = "inline";
lastTextNode.style.textAnchor = "end";
return () => children.forEach((child, index) => {
child.style.display = "inline";
});
}
function isNumeric(value3) {
return typeof value3 === "number" || typeof value3 === "string" && !isNaN(Number(value3));
}
function isDateish2(value3) {
return value3 instanceof Date || typeof value3 === "string" && !isNaN(Date.parse(value3));
}
function getSvgOverflow(svg) {
let svgRect = svg.getBoundingClientRect();
let contentRect = { top: Infinity, right: -Infinity, bottom: -Infinity, left: Infinity };
Array.from(svg.children).forEach((el) => {
if (el.hasAttribute("data-overlay")) return;
if (el.style.display === "none") return;
let rect = el.getBoundingClientRect();
if (!rect.width && !rect.height) return;
contentRect.top = Math.min(contentRect.top, rect.top);
contentRect.right = Math.max(contentRect.right, rect.right);
contentRect.bottom = Math.max(contentRect.bottom, rect.bottom);
contentRect.left = Math.min(contentRect.left, rect.left);
});
return {
top: Math.max(0, svgRect.top - contentRect.top),
right: Math.max(0, contentRect.right - svgRect.right),
bottom: Math.max(0, contentRect.bottom - svgRect.bottom),
left: Math.max(0, svgRect.left - contentRect.left)
};
}
// js/button.js
var UIButton = class extends UIElement {
boot() {
setAttribute2(this, "role", "button");
this._disableable = new Disableable(this);
this._disableable.onInitAndChange((disabled) => {
disabled ? removeAttribute(this, "tabindex", "0") : setAttribute2(this, "tabindex", "0");
});
this._buttonType = this.getAttribute("type") || "button";
}
mount() {
on(this, "keydown", (e) => {
if (e.key === "Enter") {
e.preventDefault();
this.disabled || this.click();
}
if (e.key === " ") {
e.preventDefault();
}
});
on(this, "keyup", (e) => {
if (e.key === " ") {
e.preventDefault();
e.stopPropagation();
this.disabled || this.click();
}
});
on(this, "click", () => {
if (this.disabled) return;
if (this._buttonType === "submit") {
this._handleSubmit();
} else if (this._buttonType === "reset") {
this._handleReset();
}
});
}
_handleSubmit() {
let form = this.closest("form");
if (form) {
form.requestSubmit();
}
}
_handleReset() {
let form = this.closest("form");
if (form) {
form.reset();
}
}
};
inject(({ css }) => css`ui-button { display: block; }`);
element("button", UIButton);
// js/close.js
var UIClose = class extends UIElement {
mount() {
let button = this.querySelector("button,ui-button");
on(button, "click", () => {
let closeable = closest(this, (el) => !!el._closeable)?._closeable;
closeable?.close();
});
}
};
element("close", UIClose);
// js/toast.js
var UIToastGroup = class extends UIElement {
toasts = [];
initiallyExpanded = false;
expanded = false;
mount() {
this.initiallyExpanded = this.hasAttribute("expanded");
let position = this.getAttribute("position") || "bottom right";
this.verticalPosition = position.match(/\b(top|bottom)\b/)?.[0] || "bottom";
this.horizontalPosition = position.match(/\b(left|start|center|right|end)\b/)?.[0] || "right";
if (this.horizontalPosition === "left") {
this.horizontalPosition = "start";
} else if (this.horizontalPosition === "right") {
this.horizontalPosition = "end";
}
setAttribute2(this, "role", "status");
}
showToast(options = {}) {
let toastContainer = this.querySelector("ui-toast");
if (!toastContainer) {
return console.warn("ui-toast-group: no ui-toast element found", this);
}
if (this.matches(":popover-open")) {
this.hidePopover();
}
this.showPopover();
let duration = Number(options.duration === void 0 ? 5e3 : options.duration);
let template = toastContainer.prepareToastTemplate(options);
let toastEl = template.firstElementChild;
let toast = {
timeout: null,
el: template,
height: null,
contentEl: toastEl,
contentHeight: null
};
let show = () => {
this.animateIn(toast);
this.updateList();
};
let hide2 = () => {
this.animateOut(toast);
this.updateList();
};
this.toasts.unshift(toast);
this.appendChild(template);
show();
template.hideToast = hide2;
let toastTimeout = duration !== 0 && timeout(() => {
toast.timeout = null;
hide2();
}, duration);
if (toastTimeout) {
toast.timeout = toastTimeout;
}
template.destroyToast = () => {
if (toast.timeout) {
toast.timeout.cancel();
toast.timeout = null;
}
let index = this.toasts.indexOf(toast);
if (index > -1) {
this.toasts.splice(index, 1);
}
template.remove();
this.updateList();
};
template.addEventListener("mouseenter", () => {
this.pauseTimeouts();
if (!this.initiallyExpanded) {
this.expanded = true;
this.updateList();
}
});
template.addEventListener("mouseleave", () => {
this.resumeTimeouts();
if (!this.initiallyExpanded) {
this.expanded = false;
this.updateList();
}
});
template._closeable = new Closeable(template);
template._closeable.onClose(() => template.destroyToast());
}
pauseTimeouts() {
for (let toast of this.toasts) {
toast.timeout?.pause();
}
}
resumeTimeouts() {
for (let toast of this.toasts) {
toast.timeout?.resume();
}
}
animateIn(toast) {
let reverseVerticalPosition = this.verticalPosition === "top" ? "bottom" : "top";
let verticalPositionInt = reverseVerticalPosition === "top" ? 1 : -1;
let translateY = 1.5 * verticalPositionInt;
toast.contentEl.style.opacity = 0;
toast.contentEl.style.transform = `translateY(${translateY}rem)`;
toast.el.style.zIndex = 5001;
toast.contentEl.offsetHeight;
toast.contentHeight = toast.contentEl.offsetHeight;
toast.height = toast.el.offsetHeight;
toast.contentEl.style.opacity = 100;
toast.contentEl.style.transform = `translateY(0)`;
}
animateOut(toast) {
let verticalPositionInt = this.verticalPosition === "top" ? 1 : -1;
let translateY = 0.5 * verticalPositionInt;
toast.contentEl.style.transform = `translateY(${translateY}rem)`;
toast.contentEl.style.opacity = 0;
let index = this.toasts.indexOf(toast);
if (index > -1) {
this.toasts.splice(index, 1);
}
let cleanup = () => {
toast.el.remove();
if (this.toasts.length === 0) {
this.expanded = false;
}
};
if (toast.contentEl.getAnimations().length) {
toast.contentEl.addEventListener("transitionend", () => {
cleanup();
}, { once: true });
} else {
cleanup();
}
}
updateList() {
this.initiallyExpanded || this.expanded ? this.expand() : this.collapse();
}
expand() {
let runningHeight = 0;
for (let toast of this.toasts) {
let verticalPositionInt = this.verticalPosition === "top" ? 1 : -1;
toast.el.style.transform = `translateY(${verticalPositionInt * runningHeight}px)`;
toast.el.style.opacity = 100;
toast.contentEl.style.height = `${toast.contentHeight}px`;
toast.contentEl.style.overflow = "auto";
runningHeight += toast.height;
}
}
collapse() {
let i = 0;
let frontToast = this.toasts[0];
let frontToastHeight = frontToast?.contentHeight || 0;
for (let toast of this.toasts) {
let numberOfToastsToShow = 3;
let scale = 0;
let verticalPositionInt = this.verticalPosition === "top" ? 1 : -1;
let translateY = 10 * verticalPositionInt * i;
toast.el.style.zIndex = 5e3 - i;
if (i >= numberOfToastsToShow) {
scale = 1 - 0.05 * (numberOfToastsToShow - 1);
toast.el.style.opacity = 0;
} else {
scale = 1 - 0.05 * i;
toast.el.style.opacity = 100;
}
toast.contentEl.style.height = `${frontToastHeight}px`;
toast.contentEl.style.overflow = "hidden";
toast.el.style.transform = `scaleX(${scale}) translateY(${translateY}px)`;
i++;
}
}
};
var UIToast = class extends UIElement {
mount() {
if (!this.closest("ui-toast-group")) {
setAttribute2(this, "role", "status");
document.addEventListener("keydown", (e) => {
if (e.key === "Escape") {
this.hideToast();
}
});
this.defaultPosition = this.getAttribute("position") || "bottom end";
}
}
showToast(options = {}) {
let existingToast = this.template().nextElementSibling;
if (existingToast) existingToast.destroyToast();
let duration = Number(options.duration === void 0 ? 5e3 : options.duration);
let position = options.dataset?.position ?? this.defaultPosition;
if (options.dataset?.position !== void 0) {
delete options.dataset.position;
}
this.setAttribute("position", position);
let template = this.prepareToastTemplate(options);
let show = () => {
this.showPopover();
template.classList.add("showing");
};
let hide2 = () => {
template._hiding = true;
template.classList.remove("showing");
if (template.getAnimations().length) {
template.addEventListener("transitionend", () => {
template.remove();
this.hidePopover();
}, { once: true });
} else {
template.remove();
this.hidePopover();
}
};
this.appendChild(template);
show();
template.hideToast = hide2;
let toastTimeout = duration !== 0 && timeout(() => {
hide2();
}, duration);
template.destroyToast = () => {
toastTimeout && toastTimeout.cancel();
template.remove();
this.hidePopover();
};
template.addEventListener("mouseenter", () => {
toastTimeout && toastTimeout.pause();
});
template.addEventListener("mouseleave", () => {
toastTimeout && toastTimeout.resume();
});
template._closeable = new Closeable(template);
template._closeable.onClose(() => template.destroyToast());
}
hideToast() {
let toast = this.template().nextElementSibling;
toast && toast.destroyToast();
}
template() {
return this.querySelector("template");
}
prepareToastTemplate(options) {
let slots = options.slots || {};
let dataset = options.dataset || {};
let templateEl = this.template();
if (!templateEl) {
return console.warn("ui-toast: no template element found", this);
}
let template = templateEl.content.cloneNode(true).firstElementChild;
template.setAttribute("aria-atomic", "true");
Object.entries(slots).forEach(([key, value3]) => {
if ([null, void 0, false].includes(value3)) return;
template.querySelectorAll(`slot[name="${key}"]`).forEach((i) => {
i.replaceWith(document.createTextNode(value3));
});
});
Object.entries(dataset).forEach(([key, value3]) => {
template.dataset[key] = value3;
});
template.querySelectorAll("slot").forEach((slot) => slot.remove());
return template;
}
};
element("toast-group", UIToastGroup);
element("toast", UIToast);
// js/radio.js
var UIRadioGroup = class _UIRadioGroup extends UIControl {
boot() {
this._disableable = new Disableable(this);
this._disableable.onInitAndChange((disabled) => {
this.walker().each((el) => {
el.disabled = disabled;
});
});
this._selectable = new SelectableGroup(this);
this._controllable = new Controllable(this, { disabled: this._disabled, bubbles: true });
this._focusable = new FocusableGroup(this, { wrap: true });
this._submittable = new Submittable(this, {
name: this.getAttribute("name"),
value: this._selectable.getState(),
includeWhenEmpty: false
});
this._controllable.initial((initial) => initial && this._selectable.setState(initial));
this._controllable.getter(() => this._selectable.getState());
this._detangled = detangle();
this._controllable.setter(this._detangled((value3) => {
this._selectable.setState(value3);
}));
this._selectable.onChange(this._detangled(() => {
this._controllable.dispatch();
}));
this._selectable.onInitAndChange(() => {
this._submittable.update(this._selectable.getState());
});
on(this, "keydown", (e) => {
if (["ArrowDown", "ArrowRight"].includes(e.key)) {
this._focusable.focusNext();
e.preventDefault();
e.stopPropagation();
} else if (["ArrowUp", "ArrowLeft"].includes(e.key)) {
this._focusable.focusPrev();
e.preventDefault();
e.stopPropagation();
}
});
setAttribute2(this, "role", "radiogroup");
queueMicrotask(() => {
this._submittable.update(this._selectable.getState());
});
}
walker() {
return walker(this, (el, { skip, reject }) => {
if (el instanceof _UIRadioGroup) return reject();
if (!(el.localName === "ui-radio")) return skip();
});
}
};
var UIRadio = class extends UIControl {
boot() {
let button = this;
this._disableable = new Disableable(this);
this._selectable = new Selectable(button, {
value: this.hasAttribute("value") ? this.getAttribute("value") : Math.random().toString(36).substring(2, 10),
label: this.hasAttribute("label") ? this.getAttribute("label") : null,
selectedInitially: this.hasAttribute("checked"),
dataAttr: "data-checked",
ariaAttr: "aria-checked"
});
this.value = this._selectable.getValue();
this._selectable.onChange(() => {
if (this._selectable.isSelected()) this._focusable.focus(false);
});
this._disableable.onChange((disabled) => {
if (disabled) {
this._focusable.untabbable();
} else {
this._selectable.isSelected() && this._focusable.tabbable();
}
});
setAttribute2(button, "role", "radio");
this._focusable = new Focusable(button, { disableable: this._disableable, tabbableAttr: "data-active" });
on(button, "click", this._disableable.disabled((e) => {
e.preventDefault();
e.stopPropagation();
}), { capture: true });
on(button, "click", this._disableable.enabled((e) => {
this._selectable.press();
}));
on(button, "keydown", this._disableable.enabled((e) => {
if (e.key === "Enter") {
this.closest("form")?.requestSubmit();
}
}));
on(button, "keydown", this._disableable.enabled((e) => {
if (e.key === " ") {
e.preventDefault();
e.stopPropagation();
}
}));
on(button, "keyup", this._disableable.enabled((e) => {
if (e.key === " ") {
this._selectable.press();
e.preventDefault();
e.stopPropagation();
}
}));
respondToLabelClick3(button);
on(button, "focus", (e) => {
isUsingKeyboard() && this._selectable.select();
});
}
get checked() {
return this._selectable.isSelected();
}
set checked(value3) {
let detangled = this.closest("ui-radio-group")?._detangled || (() => {
});
detangled(() => {
value3 && this._selectable.select();
})();
}
};
function respondToLabelClick3(el) {
el.closest("label")?.addEventListener("click", (e) => {
if (!el.contains(e.target)) {
el.click();
}
});
}
inject(({ css }) => css`ui-radio-group { display: block; }`);
inject(({ css }) => css`ui-radio { display: inline-block; user-select: none; }`);
element("radio-group", UIRadioGroup);
element("radio", UIRadio);
// js/table.js
var UITableScrollArea = class extends UIElement {
boot() {
on(this, "scroll", (e) => {
this.updateAttributes();
}, { passive: true });
new ResizeObserver(() => {
this.updateAttributes();
}).observe(this);
}
mount() {
queueMicrotask(() => {
this.updateAttributes();
});
}
updateAttributes() {
if (this.scrollLeft > 12) {
setAttribute2(this, "data-scrolled-right", "");
} else {
removeAttribute(this, "data-scrolled-right");
}
if (this.scrollWidth - this.clientWidth - this.scrollLeft > 12) {
setAttribute2(this, "data-scrolled-left", "");
} else {
removeAttribute(this, "data-scrolled-left");
}
}
};
element("table-scroll-area", UITableScrollArea);
// js/tabs.js
var UITabGroup = class _UITabGroup extends UIElement {
boot() {
this._disabled = this.hasAttribute("disabled");
}
mount() {
this.walkPanels((el) => initializePanel(el));
new MutationObserver((mutations) => {
this.walkPanels((el) => initializePanel(el));
}).observe(this, { childList: true });
}
showPanel(name) {
this.walkPanels((el) => {
if (el.getAttribute("name") === name) el.show();
else el.hide();
});
}
getPanel(name) {
return this.walkPanels((el, bail) => {
if (el.getAttribute("name") === name) {
bail(el);
}
});
}
walkPanels(callback) {
let bailed = false;
let bailedReturn;
for (let child of this.children) {
if (child instanceof _UITabGroup) continue;
if (child instanceof UITabs) continue;
callback(child, (forward) => {
bailed = true;
bailedReturn = forward;
});
if (bailed) break;
}
return bailedReturn;
}
};
var UITabsScrollArea = class extends UIElement {
boot() {
on(this, "scroll", (e) => {
this.updateScrollVariable();
}, { passive: true });
new ResizeObserver(() => {
this.updateScrollVariable();
}).observe(this);
}
updateScrollVariable() {
let percentage = Math.abs(this.scrollLeft) / (this.scrollWidth - this.clientWidth) * 100;
this.style.setProperty("--flux-scroll-percentage", percentage + "%");
}
};
var UITabs = class _UITabs extends UIControl {
boot() {
this._focusable = new FocusableGroup(this, { wrap: true });
this._selectableGroup = new SelectableGroup(this);
this._controllable = new Controllable(this, { disabled: this._disabled });
this._controllable.initial((initial) => initial && this._selectableGroup.setState(initial));
this._controllable.getter(() => this._selectableGroup.getState());
let detangled = detangle();
this._controllable.setter(detangled((value3) => {
this._selectableGroup.setState(value3);
}));
this._selectableGroup.onChange(detangled(() => {
this._controllable.dispatch();
}));
on(this, "keydown", (e) => {
if (["ArrowDown", "ArrowRight"].includes(e.key)) {
this._focusable.focusNext();
e.preventDefault();
e.stopPropagation();
} else if (["ArrowUp", "ArrowLeft"].includes(e.key)) {
this._focusable.focusPrev();
e.preventDefault();
e.stopPropagation();
}
});
setAttribute2(this, "role", "tablist");
}
mount() {
this.initializeTabs();
this._focusable.ensureTabbable();
if (!this._selectableGroup.getState()) {
this._selectableGroup.selectFirst();
}
new MutationObserver((mutations) => {
this.initializeTabs();
let selected = this._selectableGroup.selected();
selected.el.closest("ui-tab-group").showPanel(selected.value);
}).observe(this, { childList: true });
}
initializeTabs() {
this.walker().each((el) => {
if (el._initialized) return;
if (el._disableable) return;
if (el.hasAttribute("action")) return;
initializeTab(el);
el._initialized = true;
});
}
walker() {
return walker(this, (el, { skip, reject }) => {
if (el instanceof UITabGroup) return reject();
if (el instanceof _UITabs) return reject();
if (!["a", "button"].includes(el.localName)) return skip();
});
}
};
function initializeTab(el) {
el._disableable = new Disableable(el);
let link = el.matches("a") ? el : null;
let target = link || el;
el._disableable.onInitAndChange((disabled) => {
if (disabled) {
setAttribute2(target, "aria-disabled", "true");
} else {
removeAttribute(target, "aria-disabled");
}
});
let id = assignId(target, "tab");
setAttribute2(target, "role", "tab");
target._focusable = new Focusable(target, { disableable: el._disableable, tabbableAttr: "data-active" });
if (!link) {
let panel = el.getAttribute("name");
el._selectable = new Selectable(el, {
value: panel || Math.random().toString(36).substring(2, 10),
label: el.hasAttribute("label") ? el.getAttribute("label") : el.textContent.trim(),
selectedInitially: el.hasAttribute("selected"),
toggleable: false
});
on(el, "click", () => el._selectable.press());
el._selectable.onInitAndChange(() => {
let panelEl = el.closest("ui-tab-group")?.getPanel(panel);
el._selectable.getState() ? panelEl?.show() : panelEl?.hide();
if (el._selectable.getState()) {
el._focusable.focus(false);
}
});
let pointerdownTimeout = null;
if (!el.closest("ui-tab-group")?.hasAttribute("manual")) {
on(el, "pointerdown", () => {
clearTimeout(pointerdownTimeout);
pointerdownTimeout = setTimeout(() => pointerdownTimeout = null);
});
on(el, "focus", () => {
if (!pointerdownTimeout) {
el._selectable.select();
}
});
}
queueMicrotask(() => {
let container = el.closest("ui-tab-group");
if (!container) return;
let panelEl = container.getPanel(panel);
if (!panelEl) throw new Error("Could not find panel...");
setAttribute2(el, "aria-controls", panelEl.id);
setAttribute2(panelEl, "aria-labelledby", el.id);
});
}
}
function initializePanel(el) {
if (el._initialized) return;
assignId(el, "tab-panel");
setAttribute2(el, "role", "tabpanel");
el.hasAttribute("tabindex") || setAttribute2(el, "tabindex", "-1");
el.show = () => {
setAttribute2(el, "data-selected", "");
setAttribute2(el, "tabindex", "0");
};
el.hide = () => {
removeAttribute(el, "data-selected");
setAttribute2(el, "tabindex", "-1");
};
el._initialized = true;
}
inject(({ css }) => css`ui-tab-group, ui-tabs { display: block; cursor: default; }`);
element("tab-group", UITabGroup);
element("tabs-scroll-area", UITabsScrollArea);
element("tabs", UITabs);
// js/otp.js
var UIOTP = class extends UIControl {
mount() {
this.inputEls = this.querySelectorAll("[data-flux-otp-input]");
this.length = this.inputEls.length;
this.config = {
mode: this.getAttribute("mode") || "numeric",
autocomplete: this.getAttribute("autocomplete") || "one-time-code",
autoSubmit: this.getAttribute("submit") === "auto",
inputAriaLabelTemplate: this.getAttribute("data-flux-input-aria-label") || "Character {current} of {total}"
};
this.state = {
length: 0,
onChanges: [],
getValue: () => {
return Array.from(this.inputEls).map((input) => input.value).join("");
},
setValue: (value3) => {
let cleaned = (value3 ?? "").replace(/\s/g, "").replace(this.invalidCharacters(), "").toUpperCase();
for (let i = 0; i < this.length; i++) {
this.inputEls[i].value = cleaned[i] || "";
}
this.state.length = cleaned.length;
this.state.onChanges.forEach((i) => i(cleaned));
},
notify: () => {
let value3 = this.state.getValue();
this.state.length = value3.length;
this.state.onChanges.forEach((i) => i(value3));
},
reapply: () => {
let value3 = this.state.getValue();
this.state.setValue(value3);
},
onChange: (callback) => {
this.state.onChanges.push(callback);
}
};
if (this.hasAttribute("value")) {
this.state.setValue(this.getAttribute("value"));
}
this._controllable = new Controllable(this);
this._controllable.initial((initial) => initial && this.state.setValue(initial));
this._controllable.getter(() => this.state.getValue());
let detangled = detangle();
this._controllable.setter(detangled((value3) => this.state.setValue(value3)));
this.state.onChange(detangled(() => this._controllable.dispatch()));
this._submittable = new Submittable(this, {
name: this.getAttribute("name"),
value: this.state.getValue()
});
this.state.onChange((value3) => {
this._submittable.update(value3);
if (value3.length === this.length && this.config.autoSubmit) {
this.closest("form")?.requestSubmit();
}
let activeIndex = Array.from(this.inputEls).findIndex((input) => input === document.activeElement);
if (activeIndex > this.nextIndex()) {
this.focusIndex(this.nextIndex());
}
});
this._disableable = new Disableable(this);
this._disableable.onInitAndChange((disabled) => {
for (let inputEl of this.inputEls) {
if (disabled) {
setAttribute2(inputEl, "disabled", disabled);
} else {
removeAttribute(inputEl, "disabled");
}
}
});
this.updateTabIndexes(this.nextIndex());
for (let i = 0; i < this.length; i++) {
setAttribute2(this.inputEls[i], "autocomplete", i === 0 ? this.config.autocomplete : "off");
setAttribute2(this.inputEls[i], "aria-label", this.config.inputAriaLabelTemplate.replace("{current}", i + 1).replace("{total}", this.length));
let prevValue;
on(this.inputEls[i], "beforeinput", (e) => {
prevValue = e.target.value;
});
on(this.inputEls[i], "input", (e) => {
e.stopPropagation();
let value3 = e.target.value;
if (value3.length > 1) {
this.state.setValue(value3);
this.focusIndex(this.nextIndex());
e.preventDefault();
return;
}
if (value3 == "") {
this.state.reapply();
if (i < this.nextIndex()) {
this.focusIndex(i);
} else {
this.focusPrev(i);
}
return;
}
if (this.invalidCharacters().test(value3)) {
e.target.value = prevValue;
this.focusIndex(i);
return;
}
if (this.config.mode !== "numeric") {
e.target.value = value3.toUpperCase();
}
this.inputEls[i].blur();
this.state.notify();
this.focusNext(i);
});
on(this.inputEls[i], "keydown", (e) => {
if (["Backspace", "Delete", "Clear"].includes(e.key)) {
if (e.target.value === "") {
requestAnimationFrame(() => this.focusPrev(i));
}
} else if (e.key === "ArrowRight") {
isRTL() ? this.focusPrev(i) : this.focusNext(i);
e.preventDefault();
} else if (e.key === "ArrowLeft") {
isRTL() ? this.focusNext(i) : this.focusPrev(i);
e.preventDefault();
}
});
on(this.inputEls[i], "pointerdown", (e) => {
this.focusIndex(Math.min(i, this.nextIndex()));
e.preventDefault();
});
on(this.inputEls[i], "focus", (e) => {
e.target.setSelectionRange(0, 1);
this.updateTabIndexes(i);
});
}
}
trigger() {
return this.inputEls[this.nextIndex()];
}
focusIndex(index) {
let input = this.inputEls[index];
if (document.activeElement === input) {
input.blur();
}
input.focus();
}
focusPrev(i) {
this.focusIndex(Math.max(0, i - 1));
}
focusNext(i) {
this.focusIndex(Math.min(i + 1, this.nextIndex()));
}
nextIndex() {
return Math.min(this.state.length, this.length - 1);
}
updateTabIndexes(active) {
for (let i = 0; i < this.length; i++) {
if (i === active) {
setAttribute2(this.inputEls[i], "tabindex", "0");
} else {
setAttribute2(this.inputEls[i], "tabindex", "-1");
}
}
}
invalidCharacters() {
switch (this.config.mode) {
case "numeric":
return /[^\d]/g;
case "alpha":
return /[^a-zA-Z]/g;
case "alphanumeric":
return /[^a-zA-Z0-9]/g;
default:
throw new Error(`Unknown OTP input mode "${this.config.mode}"`);
}
}
};
element("otp", UIOTP);
// js/store.js
document.addEventListener("alpine:init", () => {
let applyAppearance = window.Flux?.applyAppearance;
if (!applyAppearance) {
applyAppearance = () => {
window.Flux.appearance = null;
window.localStorage.removeItem("flux.appearance");
};
}
let flux = Alpine.reactive({
toast(...params) {
let detail = { slots: {}, dataset: {} };
if (typeof params[0] === "string") {
detail.slots.text = params.shift();
}
if (typeof params[0] === "string") {
detail.slots.heading = detail.slots.text;
detail.slots.text = params.shift();
}
let options = params.shift() || {};
if (options.text) detail.slots.text = options.text;
if (options.heading) detail.slots.heading = options.heading;
if (options.variant) detail.dataset.variant = options.variant;
if (options.position) detail.dataset.position = options.position;
if (options.duration !== void 0) detail.duration = options.duration;
document.dispatchEvent(new CustomEvent("toast-show", { detail }));
},
modal(name) {
return {
show() {
document.dispatchEvent(new CustomEvent("modal-show", { detail: { name } }));
},
close() {
document.dispatchEvent(new CustomEvent("modal-close", { detail: { name } }));
}
};
},
modals() {
return { close() {
document.dispatchEvent(new CustomEvent("modal-close", { detail: {} }));
} };
},
appearance: window.localStorage.getItem("flux.appearance") || "system",
systemAppearanceChanged: 1,
// A counter to trigger reactivity when the system appearance changes...
get dark() {
JSON.stringify(flux.systemAppearanceChanged);
if (flux.appearance === "system") {
let media2 = window.matchMedia("(prefers-color-scheme: dark)");
return media2.matches;
} else {
return flux.appearance === "dark";
}
},
set dark(value3) {
let current = this.dark;
if (value3 === current) return;
if (value3) {
flux.appearance = "dark";
} else {
flux.appearance = "light";
}
}
});
window.Flux = flux;
Alpine.magic("flux", () => flux);
Alpine.effect(() => {
applyAppearance(flux.appearance);
});
document.addEventListener("livewire:navigated", () => {
applyAppearance(flux.appearance);
});
let media = window.matchMedia("(prefers-color-scheme: dark)");
media.addEventListener("change", () => {
flux.systemAppearanceChanged++;
applyAppearance(flux.appearance);
});
});
// js/index.js
if (!isSupported2() && !isPolyfilled()) {
apply2();
}
})();