@github/catalyst
Version:
Helpers for creating HTML Elements as Controllers
93 lines • 3.29 kB
JavaScript
import { registerTag, observeElementForTags } from './tag-observer.js';
import { createMark } from './mark.js';
import { attach } from './controllable.js';
import { dasherize } from './dasherize.js';
const targetChangedCallback = Symbol();
const targetsChangedCallback = Symbol();
const [target, getTarget, initializeTarget] = createMark(({ name, kind }) => {
if (kind === 'getter')
throw new Error(`@target cannot decorate get ${String(name)}`);
}, (instance, { name, access }) => {
const selector = [
`[data-target~="${instance.tagName.toLowerCase()}.${dasherize(name)}"]`,
`[data-target~="${instance.tagName.toLowerCase()}.${String(name)}"]`
];
const find = findTarget(instance, selector.join(', '), false);
return {
get: find,
set: () => {
if (access?.set)
access.set.call(instance, find());
}
};
});
const [targets, getTargets, initializeTargets] = createMark(({ name, kind }) => {
if (kind === 'getter')
throw new Error(`@target cannot decorate get ${String(name)}`);
}, (instance, { name, access }) => {
const selector = [
`[data-targets~="${instance.tagName.toLowerCase()}.${dasherize(name)}"]`,
`[data-targets~="${instance.tagName.toLowerCase()}.${String(name)}"]`
];
const find = findTarget(instance, selector.join(', '), true);
return {
get: find,
set: () => {
if (access?.set)
access.set.call(instance, find());
}
};
});
function setTarget(el, controller, tag, key) {
const get = tag === 'data-targets' ? getTargets : getTarget;
if (controller instanceof ShadowRoot) {
controller = controllers.get(controller);
}
if (controller && get(controller)?.has(key)) {
;
controller.requestUpdate(key);
}
}
registerTag('data-target', (str) => str.split('.'), setTarget);
registerTag('data-targets', (str) => str.split('.'), setTarget);
const shadows = new WeakMap();
const controllers = new WeakMap();
const findTarget = (controller, selector, many) => () => {
const nodes = [];
const shadow = shadows.get(controller);
if (shadow) {
for (const el of shadow.querySelectorAll(selector)) {
if (!el.closest(controller.tagName)) {
nodes.push(el);
if (!many)
break;
}
}
}
if (many || !nodes.length) {
for (const el of controller.querySelectorAll(selector)) {
if (el.closest(controller.tagName) === controller) {
nodes.push(el);
if (!many)
break;
}
}
}
return many ? nodes : nodes[0];
};
export { target, getTarget, targets, getTargets, targetChangedCallback, targetsChangedCallback };
export class TargetableController {
constructor(host) {
this.host = host;
observeElementForTags(this.host);
initializeTarget(this.host);
initializeTargets(this.host);
}
hostShadowCreated(root) {
shadows.set(this.host, root);
controllers.set(root, this.host);
observeElementForTags(root);
}
}
export const targetable = attach(TargetableController);
//# sourceMappingURL=targetable.js.map