@ramstack/alpinegear-fragment
Version:
@ramstack/alpinegear-fragment provides 'x-format' Alpine.js directive, allowing for fragment-like behavior similar to what's available in frameworks like 'Vue.js' or 'React', where multiple root elements can be grouped together.
71 lines (60 loc) • 2.07 kB
JavaScript
const warn = (...args) => console.warn("alpinegear.js:", ...args);
const is_template = el => el instanceof HTMLTemplateElement;
const is_element = el => el.nodeType === Node.ELEMENT_NODE;
function anchor_block(el, template, { addScopeToNode, cleanup, initTree, mutateDom, scope = {} }) {
if (el._r_block) {
return;
}
initialize();
let nodes = is_template(template)
? [...template.content.cloneNode(true).childNodes]
: [template.cloneNode(true)];
mutateDom(() => {
for (let node of nodes) {
is_element(node) && addScopeToNode(node, scope, el);
el.parentElement.insertBefore(node, el);
is_element(node) && initTree(node);
}
});
el._r_block = {
template,
update() {
mutateDom(() => {
for (let node of nodes ?? []) {
el.parentElement.insertBefore(node, el);
}
});
},
delete() {
el._r_block = null;
for (let node of nodes ?? []) {
node.remove();
}
nodes = null;
}
};
cleanup(() => el._r_block?.delete());
}
function initialize() {
document.body._r_block ??= (() => {
const observer = new MutationObserver(mutations => {
for (let mutation of mutations) {
for (let node of mutation.addedNodes) {
node._r_block?.update();
}
}
});
observer.observe(document.body, { childList: true, subtree: true });
return observer;
})();
}
function plugin({ addScopeToNode, directive, initTree, mutateDom }) {
directive("fragment", (el, {}, { cleanup }) => {
if (!is_template(el)) {
warn("x-fragment can only be used on a 'template' tag");
return;
}
anchor_block(el, el, { addScopeToNode, cleanup, initTree, mutateDom });
});
}
export { plugin as fragment };