You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

89 lines
2.1 KiB

2 weeks ago
export function scope(node) {
return mergeProxies(closestDataStack(node))
}
export function addScopeToNode(node, data, referenceNode) {
node._x_dataStack = [data, ...closestDataStack(referenceNode || node)]
return () => {
node._x_dataStack = node._x_dataStack.filter(i => i !== data)
}
}
export function hasScope(node) {
return !! node._x_dataStack
}
export function closestDataStack(node) {
if (node._x_dataStack) return node._x_dataStack
if (typeof ShadowRoot === 'function' && node instanceof ShadowRoot) {
return closestDataStack(node.host)
}
if (! node.parentNode) {
return []
}
return closestDataStack(node.parentNode)
}
export function closestDataProxy(el) {
return mergeProxies(closestDataStack(el))
}
export function mergeProxies (objects) {
return new Proxy({ objects }, mergeProxyTrap);
}
let mergeProxyTrap = {
ownKeys({ objects }) {
return Array.from(
new Set(objects.flatMap((i) => Object.keys(i)))
)
},
has({ objects }, name) {
if (name == Symbol.unscopables) return false;
return objects.some((obj) =>
Object.prototype.hasOwnProperty.call(obj, name) ||
Reflect.has(obj, name)
);
},
get({ objects }, name, thisProxy) {
if (name == "toJSON") return collapseProxies
return Reflect.get(
objects.find((obj) =>
Reflect.has(obj, name)
) || {},
name,
thisProxy
)
},
set({ objects }, name, value, thisProxy) {
const target =
objects.find((obj) =>
Object.prototype.hasOwnProperty.call(obj, name)
) || objects[objects.length - 1];
const descriptor = Object.getOwnPropertyDescriptor(target, name);
if (descriptor?.set && descriptor?.get)
return Reflect.set(target, name, value, thisProxy);
return Reflect.set(target, name, value);
},
}
function collapseProxies() {
let keys = Reflect.ownKeys(this)
return keys.reduce((acc, key) => {
acc[key] = Reflect.get(this, key)
return acc;
}, {})
}