If con on-off
This commit is contained in:
@@ -127,12 +127,13 @@ export const onUnmount = (fn) => context?.u.push(fn);
|
|||||||
export const provide = (key, value) => context && (context.p[key] = value);
|
export const provide = (key, value) => context && (context.p[key] = value);
|
||||||
export const inject = (key, dft) => context && (key in context.p ? context.p[key] : dft);
|
export const inject = (key, dft) => context && (key in context.p ? context.p[key] : dft);
|
||||||
|
|
||||||
const remove = (node) => {
|
const remove = async (node) => {
|
||||||
if (Array.isArray(node)) return node.forEach(remove);
|
if (Array.isArray(node)) return Promise.all(node.map(remove));
|
||||||
|
if (node.$off) await node.$off(node);
|
||||||
|
else if (node.$l) await new Promise(res => node.$l(res));
|
||||||
node.$s?.();
|
node.$s?.();
|
||||||
if (node.$c) node.$c.u.forEach(f => f());
|
if (node.$c) node.$c.u.forEach(f => f());
|
||||||
const done = () => node.remove();
|
node.remove();
|
||||||
node.$l ? node.$l(done) : done();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const render = (fn, ...data) => {
|
const render = (fn, ...data) => {
|
||||||
@@ -159,6 +160,8 @@ export const h = (tag, props = {}, ...children) => {
|
|||||||
const out = isNode(el) ? el : document.createTextNode(String(el));
|
const out = isNode(el) ? el : document.createTextNode(String(el));
|
||||||
out.$c = ctx;
|
out.$c = ctx;
|
||||||
out.$s = stop;
|
out.$s = stop;
|
||||||
|
if (props.on) out.$on = props.on;
|
||||||
|
if (props.off) out.$off = props.off;
|
||||||
context = prev;
|
context = prev;
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
@@ -166,10 +169,13 @@ export const h = (tag, props = {}, ...children) => {
|
|||||||
const isSvg = tag === 'svg' || tag === 'path' || tag === 'circle';
|
const isSvg = tag === 'svg' || tag === 'path' || tag === 'circle';
|
||||||
const el = isSvg ? document.createElementNS("http://www.w3.org/2000/svg", tag) : document.createElement(tag);
|
const el = isSvg ? document.createElementNS("http://www.w3.org/2000/svg", tag) : document.createElement(tag);
|
||||||
for (const key in props) {
|
for (const key in props) {
|
||||||
if (key.startsWith('on')) el.addEventListener(key.slice(2).toLowerCase(), props[key]);
|
const val = props[key];
|
||||||
else if (key === "ref") isFn(props[key]) ? props[key](el) : props[key].value = el;
|
if (key.startsWith('on') && key !== 'on' && key !== 'off') el.addEventListener(key.slice(2).toLowerCase(), val);
|
||||||
else if (isFn(props[key])) effect(() => el[key] = props[key]());
|
else if (key === "ref") isFn(val) ? val(el) : val.value = el;
|
||||||
else el[key] = props[key];
|
else if (key === "on") el.$on = val;
|
||||||
|
else if (key === "off") el.$off = val;
|
||||||
|
else if (isFn(val)) effect(() => el[key] = val());
|
||||||
|
else el[key] = val;
|
||||||
}
|
}
|
||||||
children.forEach(child => append(el, child));
|
children.forEach(child => append(el, child));
|
||||||
return el;
|
return el;
|
||||||
@@ -181,31 +187,41 @@ const append = (parent, child) => {
|
|||||||
const anchor = document.createTextNode('');
|
const anchor = document.createTextNode('');
|
||||||
parent.appendChild(anchor);
|
parent.appendChild(anchor);
|
||||||
let nodes = [];
|
let nodes = [];
|
||||||
effect(() => {
|
effect(async () => {
|
||||||
const raw = [child()].flat(Infinity).filter(n => n != null);
|
const raw = [child()].flat(Infinity).filter(n => n != null);
|
||||||
const newNodes = raw.map(n => isNode(n) ? n : document.createTextNode(String(n)));
|
const newNodes = raw.map(n => isNode(n) ? n : document.createTextNode(String(n)));
|
||||||
nodes.forEach(n => { if (!newNodes.includes(n)) remove(n); });
|
for (const n of nodes) { if (!newNodes.includes(n)) await remove(n); }
|
||||||
newNodes.forEach((n, i) => {
|
newNodes.forEach((n, i) => {
|
||||||
if (!nodes.includes(n)) {
|
if (!nodes.includes(n)) {
|
||||||
parent.insertBefore(n, newNodes[i+1] || anchor);
|
parent.insertBefore(n, newNodes[i+1] || anchor);
|
||||||
|
if (n.$on) n.$on(n);
|
||||||
if (n.$c) n.$c.m.forEach(f => f());
|
if (n.$c) n.$c.m.forEach(f => f());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
nodes = newNodes;
|
nodes = newNodes;
|
||||||
}, true);
|
}, true);
|
||||||
} else {
|
} else {
|
||||||
parent.appendChild(isNode(child) ? child : document.createTextNode(String(child)));
|
const n = isNode(child) ? child : document.createTextNode(String(child));
|
||||||
|
parent.appendChild(n);
|
||||||
|
if (n.$on) n.$on(n);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const If = (cond, renderFn, fallback = null) => {
|
export const If = (cond, renderFn, fallback = null, transitions = {}) => {
|
||||||
let cached, current;
|
let cached, current;
|
||||||
return () => {
|
return () => {
|
||||||
const show = !!cond();
|
const show = !!cond();
|
||||||
if (show !== current) {
|
if (show !== current) {
|
||||||
if (cached) remove(cached);
|
const update = async () => {
|
||||||
cached = show ? render(renderFn) : (isFn(fallback) ? render(fallback) : fallback);
|
if (cached) await remove(cached);
|
||||||
current = show;
|
cached = show ? render(renderFn) : (isFn(fallback) ? render(fallback) : fallback);
|
||||||
|
if (isNode(cached)) {
|
||||||
|
if (transitions.on) cached.$on = transitions.on;
|
||||||
|
if (transitions.off) cached.$off = transitions.off;
|
||||||
|
}
|
||||||
|
current = show;
|
||||||
|
};
|
||||||
|
update();
|
||||||
}
|
}
|
||||||
return cached;
|
return cached;
|
||||||
}
|
}
|
||||||
@@ -223,7 +239,7 @@ export const For = (list, key, renderFn) => {
|
|||||||
next.set(id, node);
|
next.set(id, node);
|
||||||
return node;
|
return node;
|
||||||
});
|
});
|
||||||
cache.forEach((node, id) => { if (!next.has(id)) remove(node); });
|
cache.forEach(async (node, id) => { if (!next.has(id)) await remove(node); });
|
||||||
cache = next;
|
cache = next;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@@ -236,7 +252,8 @@ export const Transition = ({ enter: e, idle, leave: l }, { children: [c] }) => {
|
|||||||
if (!isNode(el)) return el;
|
if (!isNode(el)) return el;
|
||||||
const addClass = c => c && el.classList.add(...c.split(' '));
|
const addClass = c => c && el.classList.add(...c.split(' '));
|
||||||
const removeClass = c => c && el.classList.remove(...c.split(' '));
|
const removeClass = c => c && el.classList.remove(...c.split(' '));
|
||||||
if (e) {
|
el.$on = () => {
|
||||||
|
if (!e) return;
|
||||||
requestAnimationFrame(() => {
|
requestAnimationFrame(() => {
|
||||||
addClass(e[1]);
|
addClass(e[1]);
|
||||||
requestAnimationFrame(() => {
|
requestAnimationFrame(() => {
|
||||||
@@ -246,18 +263,19 @@ export const Transition = ({ enter: e, idle, leave: l }, { children: [c] }) => {
|
|||||||
}, { once: true });
|
}, { once: true });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
if (l) {
|
el.$off = (node) => {
|
||||||
el.$l = (done) => {
|
if (!l) return node.remove();
|
||||||
|
return new Promise(res => {
|
||||||
removeClass(idle); addClass(l[1]);
|
removeClass(idle); addClass(l[1]);
|
||||||
requestAnimationFrame(() => {
|
requestAnimationFrame(() => {
|
||||||
addClass(l[0]); removeClass(l[1]); addClass(l[2]);
|
addClass(l[0]); removeClass(l[1]); addClass(l[2]);
|
||||||
el.addEventListener('transitionend', () => {
|
el.addEventListener('transitionend', () => {
|
||||||
removeClass(l[2]); removeClass(l[0]); done();
|
removeClass(l[2]); removeClass(l[0]); res();
|
||||||
}, { once: true });
|
}, { once: true });
|
||||||
});
|
});
|
||||||
}
|
});
|
||||||
}
|
};
|
||||||
return el;
|
return el;
|
||||||
}
|
}
|
||||||
return isFn(c) ? () => decorate(c()) : decorate(c);
|
return isFn(c) ? () => decorate(c()) : decorate(c);
|
||||||
@@ -266,6 +284,7 @@ export const Transition = ({ enter: e, idle, leave: l }, { children: [c] }) => {
|
|||||||
export default (target, root, props) => {
|
export default (target, root, props) => {
|
||||||
const el = h(root, props);
|
const el = h(root, props);
|
||||||
target.appendChild(el);
|
target.appendChild(el);
|
||||||
|
if (el.$on) el.$on(el);
|
||||||
if (el.$c) el.$c.m.forEach(f => f());
|
if (el.$c) el.$c.m.forEach(f => f());
|
||||||
return () => remove(el);
|
return () => remove(el);
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user