mirror of
https://github.com/jaandrle/deka-dom-el
synced 2025-04-03 04:25:53 +02:00
⚡ wip
This commit is contained in:
parent
b53f3926b3
commit
3168f452ae
@ -20,7 +20,7 @@ export const enviroment= {
|
||||
M: globalThis.MutationObserver,
|
||||
q: p=> p || Promise.resolve(),
|
||||
};
|
||||
import { isUndef } from './helpers.js';
|
||||
import { isInstance, isUndef } from './helpers.js';
|
||||
|
||||
/**
|
||||
* Handles attribute setting with special undefined handling
|
||||
@ -43,7 +43,7 @@ function setDeleteAttr(obj, prop, val){
|
||||
Reflect.set(obj, prop, val);
|
||||
if(!isUndef(val)) return;
|
||||
Reflect.deleteProperty(obj, prop);
|
||||
if(obj instanceof enviroment.H && obj.getAttribute(prop)==="undefined")
|
||||
if(isInstance(obj, enviroment.H) && obj.getAttribute(prop)==="undefined")
|
||||
return obj.removeAttribute(prop);
|
||||
if(Reflect.get(obj, prop)==="undefined")
|
||||
return Reflect.set(obj, prop, "");
|
||||
|
@ -90,6 +90,7 @@ export function chainableAppend(el){
|
||||
/** Current namespace for element creation */
|
||||
let namespace;
|
||||
|
||||
import { isInstance, isUndef } from "./helpers.js";
|
||||
/**
|
||||
* Creates a DOM element with specified tag, attributes and addons
|
||||
*
|
||||
@ -112,7 +113,7 @@ export function createElement(tag, attributes, ...addons){
|
||||
(scoped===1 ? addons.unshift(...c) : c.forEach(c=> c(el_host)), undefined);
|
||||
scope.push({ scope: tag, host });
|
||||
el= tag(attributes || undefined);
|
||||
const is_fragment= el instanceof env.F;
|
||||
const is_fragment= isInstance(el, env.F);
|
||||
if(el.nodeName==="#comment") break;
|
||||
const el_mark= createElement.mark({
|
||||
type: "component",
|
||||
@ -283,7 +284,7 @@ export function assignAttribute(element, key, value){
|
||||
*/
|
||||
function assignContext(element, _this){
|
||||
if(assign_context.has(element)) return assign_context.get(element);
|
||||
const is_svg= element instanceof env.S;
|
||||
const is_svg= isInstance(element, env.S);
|
||||
const setRemoveAttr= (is_svg ? setRemoveNS : setRemove).bind(null, element, "Attribute");
|
||||
const s= signals(_this);
|
||||
return { setRemoveAttr, s };
|
||||
@ -313,11 +314,10 @@ export function classListDeclarative(element, toggle){
|
||||
* @returns {void}
|
||||
*/
|
||||
export function elementAttribute(element, op, key, value){
|
||||
if(element instanceof env.H)
|
||||
if(isInstance(element, env.H))
|
||||
return element[op+"Attribute"](key, value);
|
||||
return element[op+"AttributeNS"](null, key, value);
|
||||
}
|
||||
import { isUndef } from "./helpers.js";
|
||||
|
||||
//TODO: add cache? `(Map/Set)<el.tagName+key,isUndef>`
|
||||
/**
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { enviroment as env, evc, evd } from './dom-common.js';
|
||||
import { isInstance } from "./helpers.js";
|
||||
|
||||
/**
|
||||
* Connection changes observer for tracking element connection/disconnection
|
||||
@ -167,9 +168,9 @@ function connectionsChangesObserverConstructor(){
|
||||
if(store.size > 30)//TODO?: limit
|
||||
await requestIdle();
|
||||
const out= [];
|
||||
if(!(element instanceof Node)) return out;
|
||||
if(!isInstance(element, Node)) return out;
|
||||
for(const el of store.keys()){
|
||||
if(el===element || !(el instanceof Node)) continue;
|
||||
if(el===element || !isInstance(el, Node)) continue;
|
||||
if(element.contains(el))
|
||||
out.push(el);
|
||||
}
|
||||
|
@ -24,6 +24,11 @@ export function typeOf(v){
|
||||
return Object.prototype.toString.call(v);
|
||||
}
|
||||
|
||||
export function isInstance(obj, cls){ return obj instanceof cls; }
|
||||
/** @type {typeof Object.prototype.isPrototypeOf.call} */
|
||||
export function isProtoFrom(obj, cls){ return Object.prototype.isPrototypeOf.call(cls, obj); }
|
||||
export function oCreate(proto= null){ return Object.create(proto); }
|
||||
|
||||
/**
|
||||
* Handles AbortSignal registration and cleanup
|
||||
* @param {AbortSignal} signal - The AbortSignal to listen to
|
||||
@ -31,7 +36,7 @@ export function typeOf(v){
|
||||
* @returns {Function|undefined|boolean} Cleanup function or undefined if already aborted
|
||||
*/
|
||||
export function onAbort(signal, listener){
|
||||
if(!signal || !(signal instanceof AbortSignal))
|
||||
if(!signal || !isInstance(signal, AbortSignal))
|
||||
return true;
|
||||
if(signal.aborted)
|
||||
return;
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { isProtoFrom } from "../helpers.js";
|
||||
/**
|
||||
* Global signals object with default implementation
|
||||
* @type {Object}
|
||||
@ -39,5 +40,5 @@ export function registerReactivity(def, global= true){
|
||||
* @returns {typeof signals_global} Signals implementation
|
||||
*/
|
||||
export function signals(_this){
|
||||
return signals_global.isPrototypeOf(_this) && _this!==signals_global ? _this : signals_global;
|
||||
return isProtoFrom(_this, signals_global) && _this!==signals_global ? _this : signals_global;
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { queueSignalWrite, mark } from "./helpers.js";
|
||||
export { mark };
|
||||
import { hasOwn, Defined } from "../helpers.js";
|
||||
import { hasOwn, Defined, oCreate, isProtoFrom } from "../helpers.js";
|
||||
|
||||
/**
|
||||
* Checks if a value is a signal
|
||||
@ -155,22 +155,8 @@ import { el } from "../dom.js";
|
||||
import { scope } from "../dom.js";
|
||||
import { on } from "../events.js";
|
||||
|
||||
/** Store for memoized values */
|
||||
const storeMemo= new WeakMap();
|
||||
|
||||
/**
|
||||
* Memoizes a function result
|
||||
*
|
||||
* @param {string|unknown} key - Cache key (non-strings will be stringified)
|
||||
* @param {Function} fun - Function to compute value
|
||||
* @param {keyof storeMemo} [host= fun]
|
||||
* @returns {unknown} Cached or computed result
|
||||
*/
|
||||
export function memo(key, fun, host= fun){
|
||||
if(typeof key!=="string") key= JSON.stringify(key);
|
||||
if (!storeMemo.has(host)) storeMemo.set(host, {});
|
||||
const cache= storeMemo.get(host);
|
||||
return hasOwn(cache, key) ? cache[key] : (cache[key]= fun());
|
||||
export function cache(store= oCreate()){
|
||||
return (key, fun)=> hasOwn(store, key) ? store[key] : (store[key]= fun());
|
||||
}
|
||||
/**
|
||||
* Creates a reactive DOM element that re-renders when signal changes
|
||||
@ -186,15 +172,16 @@ signal.el= function(s, map){
|
||||
const out= env.D.createDocumentFragment();
|
||||
out.append(mark_start, mark_end);
|
||||
const { current }= scope;
|
||||
let cache_shared= oCreate();
|
||||
const reRenderReactiveElement= v=> {
|
||||
if(!mark_start.parentNode || !mark_end.parentNode) // === `isConnected` or wasn’t yet rendered
|
||||
return removeSignalListener(s, reRenderReactiveElement);
|
||||
const cache= {}; // remove unused els from cache
|
||||
const memo= cache(cache_shared);
|
||||
cache_shared= oCreate();
|
||||
scope.push(current);
|
||||
let els= map(v, function useCache(key, fun){
|
||||
return (cache[key]= memo(key, fun, reRenderReactiveElement));
|
||||
return (cache_shared[key]= memo(key, fun));
|
||||
});
|
||||
storeMemo.set(reRenderReactiveElement, cache);
|
||||
scope.pop();
|
||||
if(!Array.isArray(els))
|
||||
els= [ els ];
|
||||
@ -211,6 +198,10 @@ signal.el= function(s, map){
|
||||
addSignalListener(s, reRenderReactiveElement);
|
||||
removeSignalsFromElements(s, reRenderReactiveElement, mark_start, map);
|
||||
reRenderReactiveElement(s());
|
||||
current.host(on.disconnected(()=>
|
||||
/*! Clears cached elements for reactive element `S.el` */
|
||||
cache_shared= {}
|
||||
));
|
||||
return out;
|
||||
};
|
||||
/**
|
||||
@ -363,7 +354,7 @@ function create(is_readonly, value, actions){
|
||||
* Prototype for signal internal objects
|
||||
* @private
|
||||
*/
|
||||
const protoSigal= Object.assign(Object.create(null), {
|
||||
const protoSigal= Object.assign(oCreate(), {
|
||||
/**
|
||||
* Prevents signal propagation
|
||||
*/
|
||||
|
Loading…
x
Reference in New Issue
Block a user