@sandlada/vue-mdc
Version:

175 lines (174 loc) • 4.89 kB
JavaScript
/**
* @license
* Copyright 2025 Sandlada & Kai Orion
* SPDX-License-Identifier: MIT
*/
import { onMounted, nextTick } from "vue";
import { isServer } from "../../utils/is-server.js";
const SNavigableController = Symbol("navigableController");
function useNavigable(hostRef, options) {
const getTabElements = () => {
if (isServer() || !hostRef.value) {
return [];
}
const elements = [];
const treewalker = document.createTreeWalker(hostRef.value, NodeFilter.SHOW_ELEMENT);
while (treewalker.nextNode()) {
if (treewalker.currentNode.hasAttribute("navigation-tab")) {
elements.push(treewalker.currentNode);
}
}
return elements;
};
const getActiveTabElement = () => {
if (isServer() || !hostRef.value) {
return null;
}
const treewalker = document.createTreeWalker(hostRef.value, NodeFilter.SHOW_ELEMENT);
while (treewalker.nextNode()) {
const node = treewalker.currentNode;
if (node.hasAttribute("active-navigation-tab") && node.hasAttribute("navigation-tab")) {
return node;
}
}
return null;
};
const _isTab = (tabLike) => {
return tabLike.hasAttribute("navigation-tab");
};
const _resetTabElementAttribute = () => {
if (!hostRef.value) {
return;
}
const treewalker = document.createTreeWalker(hostRef.value, NodeFilter.SHOW_ELEMENT);
while (treewalker.nextNode()) {
const node = treewalker.currentNode;
if (!node.hasAttribute("navigation-tab")) {
continue;
}
if (node.hasAttribute("active-navigation-tab")) {
node.removeAttribute("active-navigation-tab");
}
}
};
const setActiveTabByLabel = (label) => {
if (isServer() || !hostRef.value) {
return;
}
_resetTabElementAttribute();
const treewalker = document.createTreeWalker(hostRef.value, NodeFilter.SHOW_ELEMENT);
while (treewalker.nextNode()) {
const node = treewalker.currentNode;
if (!_isTab(node)) {
continue;
}
if (node.hasAttribute("label") && node.getAttribute("label") === label) {
if (_dispatchTabChangeEvent(node)) {
break;
}
node.setAttribute("active-navigation-tab", ``);
break;
}
}
};
const setActiveTabByOrder = (order) => {
if (isServer() || !hostRef.value) {
return;
}
_resetTabElementAttribute();
const treewalker = document.createTreeWalker(hostRef.value, NodeFilter.SHOW_ELEMENT);
while (treewalker.nextNode()) {
const node = treewalker.currentNode;
if (!_isTab(node)) {
continue;
}
if (node.hasAttribute("order") && Number(node.getAttribute("order")) === order) {
if (!_dispatchTabChangeEvent(node)) {
break;
}
node.setAttribute("active-navigation-tab", ``);
break;
}
}
};
const setActiveTabByElement = (element) => {
if (isServer() || !hostRef.value) {
return;
}
_resetTabElementAttribute();
const treewalker = document.createTreeWalker(hostRef.value, NodeFilter.SHOW_ELEMENT);
while (treewalker.nextNode()) {
const node = treewalker.currentNode;
if (!_isTab(node)) {
continue;
}
if (node.isSameNode(element)) {
if (!_dispatchTabChangeEvent(node)) {
break;
}
node.setAttribute("active-navigation-tab", ``);
break;
}
}
};
const _handleTabClick = (e) => {
e.preventDefault();
e.stopPropagation();
const tab = e.currentTarget;
setActiveTabByElement(tab);
};
const _handleTabChange = (e) => {
if (isServer() || !hostRef.value) {
return;
}
e.stopImmediatePropagation();
if (options.handleChange) {
options.handleChange(e);
}
hostRef.value.removeEventListener("change", _handleTabChange);
};
const _dispatchTabChangeEvent = (element) => {
if (isServer() || !hostRef.value) {
return;
}
const event = new CustomEvent("change", {
cancelable: true,
bubbles: true
});
hostRef.value.addEventListener("change", _handleTabChange);
return element.dispatchEvent(event);
};
onMounted(() => {
if (isServer()) {
return;
}
nextTick(() => {
if (!hostRef.value) {
return;
}
const host = hostRef.value;
getTabElements().forEach((tab) => {
tab.addEventListener("click", _handleTabClick);
});
host[SNavigableController] = {
getTabElements,
getActiveTabElement,
setActiveTabByLabel,
setActiveTabByOrder,
setActiveTabByElement
};
});
});
return {
getTabElements,
getActiveTabElement,
setActiveTabByLabel,
setActiveTabByOrder,
setActiveTabByElement
};
}
export {
SNavigableController,
useNavigable
};
//# sourceMappingURL=use-navigable.js.map