haiku-atelier-2024/web/app/themes/haiku-atelier-2024/assets/js/scripts-menu-mobile.js
gcch b50f437ea0 2025-11-03 (bis)
- ajoute un .dockerignore.
- met à jour les dépendances.
- utilise bun comme gestionnaire de paquets npm.
- utilise une configuration Vite en TypeScript.
- ajoute les fichiers compilés JavaScript aux fichiers pris en charge par Git.
2025-11-03 14:14:24 +01:00

325 lines
No EOL
12 KiB
JavaScript

import { r as _defineProperty } from "./journalisation.CEgm28xa.js";
import { dt as pipe } from "./exports.CurVqjr0.js";
import { _t as ATTRIBUT_MENU_MOBILE_ACTIVE, a as mustGetEleInDocument, dn as Ra, kt as DOM_BOUTON_MENU_MOBILE, tn as DOM_MENU_MOBILE } from "./dom.emspS_OW.js";
import "./belt_Option-91f3b350.CMbgtZ-W.js";
import { t as P } from "./index-c1cc4c86.D2nZEikK.js";
//#region node_modules/a11y-dialog/dist/a11y-dialog.esm.js
var not = {
inert: ":not([inert]):not([inert] *)",
negTabIndex: ":not([tabindex^=\"-\"])",
disabled: ":not(:disabled)"
};
var focusableSelectors = [
`a[href]${not.inert}${not.negTabIndex}`,
`area[href]${not.inert}${not.negTabIndex}`,
`input:not([type="hidden"]):not([type="radio"])${not.inert}${not.negTabIndex}${not.disabled}`,
`input[type="radio"]${not.inert}${not.negTabIndex}${not.disabled}`,
`select${not.inert}${not.negTabIndex}${not.disabled}`,
`textarea${not.inert}${not.negTabIndex}${not.disabled}`,
`button${not.inert}${not.negTabIndex}${not.disabled}`,
`details${not.inert} > summary:first-of-type${not.negTabIndex}`,
`iframe${not.inert}${not.negTabIndex}`,
`audio[controls]${not.inert}${not.negTabIndex}`,
`video[controls]${not.inert}${not.negTabIndex}`,
`[contenteditable]${not.inert}${not.negTabIndex}`,
`[tabindex]${not.inert}${not.negTabIndex}`
];
/**
* Set the focus to the first element with `autofocus` with the element or the
* element itself.
*/
function focus(el) {
(el.querySelector("[autofocus]") || el).focus();
}
/**
* Get the first and last focusable elements within a given element.
*/
function getFocusableEdges(el) {
const firstEl = findFocusableEl(el, true);
return [firstEl, firstEl ? findFocusableEl(el, false) || firstEl : null];
}
/**
* Find the first focusable element inside the given element if `forward` is
* truthy or the last focusable element otherwise.
*/
function findFocusableEl(el, forward) {
if (forward && isFocusable(el)) return el;
if (canHaveFocusableChildren(el)) if (el.shadowRoot) {
let next = getNextChildEl(el.shadowRoot, forward);
while (next) {
const focusableEl = findFocusableEl(next, forward);
if (focusableEl) return focusableEl;
next = getNextSiblingEl(next, forward);
}
} else if (el.localName === "slot") {
const assignedElements = el.assignedElements({ flatten: true });
if (!forward) assignedElements.reverse();
for (const assignedElement of assignedElements) {
const focusableEl = findFocusableEl(assignedElement, forward);
if (focusableEl) return focusableEl;
}
} else {
let next = getNextChildEl(el, forward);
while (next) {
const focusableEl = findFocusableEl(next, forward);
if (focusableEl) return focusableEl;
next = getNextSiblingEl(next, forward);
}
}
if (!forward && isFocusable(el)) return el;
return null;
}
function getNextChildEl(el, forward) {
return forward ? el.firstElementChild : el.lastElementChild;
}
function getNextSiblingEl(el, forward) {
return forward ? el.nextElementSibling : el.previousElementSibling;
}
/**
* Determine if an element is hidden from the user.
*/
var isHidden = (el) => {
if (el.matches("details:not([open]) *") && !el.matches("details>summary:first-of-type")) return true;
return !(el.offsetWidth || el.offsetHeight || el.getClientRects().length);
};
/**
* Determine if an element is focusable and has user-visible painted dimensions.
*/
var isFocusable = (el) => {
if (el.shadowRoot?.delegatesFocus) return false;
return el.matches(focusableSelectors.join(",")) && !isHidden(el);
};
/**
* Determine if an element can have focusable children. Useful for bailing out
* early when walking the DOM tree.
* @example
* This div is inert, so none of its children can be focused, even though they
* meet our criteria for what is focusable. Once we check the div, we can skip
* the rest of the subtree.
* ```html
* <div inert>
* <button>Button</button>
* <a href="#">Link</a>
* </div>
* ```
*/
function canHaveFocusableChildren(el) {
if (el.shadowRoot && el.getAttribute("tabindex") === "-1") return false;
return !el.matches(":disabled,[hidden],[inert]");
}
/**
* Get the active element, accounting for Shadow DOM subtrees.
* @author Cory LaViska
* @see: https://www.abeautifulsite.net/posts/finding-the-active-element-in-a-shadow-root/
*/
function getActiveEl(root = document) {
const activeEl = root.activeElement;
if (!activeEl) return null;
if (activeEl.shadowRoot) return getActiveEl(activeEl.shadowRoot) || document.activeElement;
return activeEl;
}
/**
* Trap the focus inside the given element
*/
function trapTabKey(el, event) {
const [firstFocusableEl, lastFocusableEl] = getFocusableEdges(el);
if (!firstFocusableEl) return event.preventDefault();
const activeEl = getActiveEl();
if (event.shiftKey && activeEl === firstFocusableEl) {
lastFocusableEl.focus();
event.preventDefault();
} else if (!event.shiftKey && activeEl === lastFocusableEl) {
firstFocusableEl.focus();
event.preventDefault();
}
}
/**
* Find the closest element to the given element matching the given selector,
* accounting for Shadow DOM subtrees.
* @author Louis St-Amour
* @see: https://stackoverflow.com/a/56105394
*/
function closest(selector, base) {
function from(el) {
if (!el || el === document || el === window) return null;
const slot = findAssignedSlot(el);
if (slot) el = slot;
return el.closest(selector) || from(el.getRootNode().host);
}
return from(base);
}
function findAssignedSlot(node) {
return node.assignedSlot || (node.parentNode ? findAssignedSlot(node.parentNode) : null);
}
var SCOPE = "data-a11y-dialog";
var A11yDialog = class {
constructor(element) {
_defineProperty(this, "$el", void 0);
_defineProperty(this, "id", void 0);
_defineProperty(this, "previouslyFocused", void 0);
_defineProperty(this, "shown", void 0);
this.$el = element;
this.id = this.$el.getAttribute(SCOPE) || this.$el.id;
this.previouslyFocused = null;
this.shown = false;
this.maintainFocus = this.maintainFocus.bind(this);
this.bindKeypress = this.bindKeypress.bind(this);
this.handleTriggerClicks = this.handleTriggerClicks.bind(this);
this.show = this.show.bind(this);
this.hide = this.hide.bind(this);
this.$el.setAttribute("aria-hidden", "true");
this.$el.setAttribute("aria-modal", "true");
this.$el.setAttribute("tabindex", "-1");
if (!this.$el.hasAttribute("role")) this.$el.setAttribute("role", "dialog");
document.addEventListener("click", this.handleTriggerClicks, true);
}
/**
* Destroy the current instance (after making sure the dialog has been hidden)
* and remove all associated listeners from dialog openers and closers
*/
destroy() {
if (this.fire("destroy").defaultPrevented) return this;
this.hide();
document.removeEventListener("click", this.handleTriggerClicks, true);
this.$el.replaceWith(this.$el.cloneNode(true));
return this;
}
/**
* Show the dialog element, trap the current focus within it, listen for some
* specific key presses and fire all registered callbacks for `show` event
*/
show(event) {
if (this.shown) return this;
if (this.fire("show", event).defaultPrevented) return this;
this.shown = true;
this.$el.removeAttribute("aria-hidden");
this.previouslyFocused = getActiveEl();
if (this.previouslyFocused?.tagName === "BODY" && event?.target) this.previouslyFocused = event.target;
if (event?.type === "focus") this.maintainFocus();
else focus(this.$el);
document.body.addEventListener("focus", this.maintainFocus, true);
this.$el.addEventListener("keydown", this.bindKeypress, true);
return this;
}
/**
* Hide the dialog element, restore the focus to the previously active
* element, stop listening for some specific key presses and fire all
* registered callbacks for `hide` event
*/
hide(event) {
if (!this.shown) return this;
if (this.fire("hide", event).defaultPrevented) return this;
this.shown = false;
this.$el.setAttribute("aria-hidden", "true");
document.body.removeEventListener("focus", this.maintainFocus, true);
this.$el.removeEventListener("keydown", this.bindKeypress, true);
this.previouslyFocused?.focus?.();
return this;
}
/**
* Register a new callback for the given event type
*/
on(type, handler, options) {
this.$el.addEventListener(type, handler, options);
return this;
}
/**
* Unregister an existing callback for the given event type
*/
off(type, handler, options) {
this.$el.removeEventListener(type, handler, options);
return this;
}
/**
* Dispatch and return a custom event from the DOM element associated with
* this dialog; this allows authors to listen for and respond to the events
* in their own code
*/
fire(type, event) {
const customEvent = new CustomEvent(type, {
detail: event,
cancelable: true
});
this.$el.dispatchEvent(customEvent);
return customEvent;
}
/**
* Add a delegated event listener for when elememts that open or close the
* dialog are clicked, and call `show` or `hide`, respectively
*/
handleTriggerClicks(event) {
const target = event.composedPath()[0];
const opener = closest(`[${SCOPE}-show="${this.id}"]`, target);
const explicitCloser = closest(`[${SCOPE}-hide="${this.id}"]`, target);
const implicitCloser = closest(`[${SCOPE}-hide]`, target) && closest("[aria-modal=\"true\"]", target) === this.$el;
if (opener) this.show(event);
if (explicitCloser || implicitCloser) this.hide(event);
}
/**
* Private event handler used when listening to some specific key presses
* (namely ESC and TAB)
*/
bindKeypress(event) {
if (closest("[aria-modal=\"true\"]", getActiveEl()) !== this.$el) return;
let hasOpenPopover = false;
try {
hasOpenPopover = !!this.$el.querySelector("[popover]:not([popover=\"manual\"]):popover-open");
} catch {}
if (event.key === "Escape" && this.$el.getAttribute("role") !== "alertdialog" && !hasOpenPopover) {
event.preventDefault();
this.hide(event);
}
if (event.key === "Tab") trapTabKey(this.$el, event);
}
/**
* If the dialog is shown and the focus is not within a dialog element (either
* this one or another one in case of nested dialogs) or an element with the
* ignore attribute, move it back to the dialog container
* See: https://github.com/KittyGiraudel/a11y-dialog/issues/177
*/
maintainFocus() {
const target = getActiveEl();
if (!closest(`[aria-modal="true"], [${SCOPE}-ignore-focus-trap]`, target)) focus(this.$el);
}
};
function instantiateDialogs() {
for (const el of document.querySelectorAll("[data-a11y-dialog]")) new A11yDialog(el);
}
if (typeof document !== "undefined") if (document.readyState === "loading") document.addEventListener("DOMContentLoaded", instantiateDialogs);
else instantiateDialogs();
//#endregion
//#region web/app/themes/haiku-atelier-2024/src/scripts/scripts-menu-mobile.ts
var E = {
BOUTON_MENU_MOBILE: mustGetEleInDocument(DOM_BOUTON_MENU_MOBILE),
CORPS_HTML: mustGetEleInDocument("body"),
MENU_MOBILE: mustGetEleInDocument(DOM_MENU_MOBILE)
};
var initialiseBoutonMenuMobile = () => {
const menuMobile = new A11yDialog(E.MENU_MOBILE);
new ResizeObserver((entrees) => pipe(Ra.head(entrees), P.filter((entree) => entree.borderBoxSize[0].inlineSize > 1e3), P.tap((_) => menuMobile.hide()))).observe(E.CORPS_HTML);
E.BOUTON_MENU_MOBILE.addEventListener("click", () => {
if (window.innerWidth > 1e3) {
window.location.href = "/";
return;
}
if (E.BOUTON_MENU_MOBILE.hasAttribute("data-menu-mobile-active")) {
menuMobile.hide();
return;
}
menuMobile.show();
});
menuMobile.on("show", () => {
E.BOUTON_MENU_MOBILE.setAttribute(ATTRIBUT_MENU_MOBILE_ACTIVE, "");
});
menuMobile.on("hide", () => {
E.BOUTON_MENU_MOBILE.removeAttribute(ATTRIBUT_MENU_MOBILE_ACTIVE);
});
};
document.addEventListener("DOMContentLoaded", () => {
initialiseBoutonMenuMobile();
});
//#endregion
//# sourceMappingURL=scripts-menu-mobile.js.map