mirror of
https://github.com/jaandrle/deka-dom-el
synced 2024-11-24 17:39:36 +01:00
✨ Add signal listener, reactive and wrap object functions
This commit is contained in:
parent
5417ecea19
commit
77cb9cf626
@ -1,6 +1,6 @@
|
|||||||
import { isSignal } from './signals.js';
|
import { isSignal, addSignalListener } from './signals.js';
|
||||||
export function on(event, listener, options){
|
export function on(event, listener, options){
|
||||||
if(isSignal(event)) return event.listeners.add(listener);
|
if(isSignal(event)) return addSignalListener(event, listener);
|
||||||
return element=> element.addEventListener(event, listener, options);
|
return element=> element.addEventListener(event, listener, options);
|
||||||
}
|
}
|
||||||
export function dispatch(event, detail){
|
export function dispatch(event, detail){
|
||||||
|
@ -3,15 +3,41 @@ export function isSignal(candidate){
|
|||||||
try{ return Reflect.has(candidate, mark); }
|
try{ return Reflect.has(candidate, mark); }
|
||||||
catch(e){ return false; }
|
catch(e){ return false; }
|
||||||
}
|
}
|
||||||
export function S(signal){
|
export function addSignalListener(signal, listener){
|
||||||
if(typeof signal!=="function")
|
return signal[mark].listeners.add(listener);
|
||||||
return create(signal);
|
}
|
||||||
if(isSignal(signal)) return signal;
|
export function S(value){
|
||||||
|
if(typeof value!=="function")
|
||||||
|
return create(value);
|
||||||
|
if(isSignal(value)) return value;
|
||||||
|
|
||||||
const out= create();
|
const out= create();
|
||||||
watch(()=> out(signal()));
|
watch(()=> out(value()));
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
export function reactive(data){
|
||||||
|
if(isSignal(data))
|
||||||
|
return data;
|
||||||
|
if(typeof data!=="object" || data===null)
|
||||||
|
return create(data);
|
||||||
|
|
||||||
|
let type;
|
||||||
|
if(Array.isArray(data)){
|
||||||
|
type= "array";
|
||||||
|
data= data.map(v=> reactive(v));
|
||||||
|
} else if(data.toString()!=="[object Object]"){
|
||||||
|
return create(data);
|
||||||
|
} else {
|
||||||
|
type= "object";
|
||||||
|
data= Object.fromEntries(
|
||||||
|
Object.entries(data)
|
||||||
|
.map(([ key, value ])=> [ key, reactive(value) ])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const signal= (...value)=>
|
||||||
|
value.length ? write(signal, reactive(value[0])) : read(signal[mark]);
|
||||||
|
return createWrapObject(type, toSignal(signal, data));
|
||||||
|
}
|
||||||
const stack= [];
|
const stack= [];
|
||||||
export function watch(context){
|
export function watch(context){
|
||||||
stack.push(context);
|
stack.push(context);
|
||||||
@ -24,28 +50,57 @@ function currentContext(){
|
|||||||
}
|
}
|
||||||
function create(value){
|
function create(value){
|
||||||
if(isSignal(value)) return value;
|
if(isSignal(value)) return value;
|
||||||
|
const signal= (...value)=>
|
||||||
if(typeof value==="object" && value!==null)
|
value.length ? write(signal, value[0]) : read(signal[mark]);
|
||||||
//TODO Array?
|
return toSignal(signal, value);
|
||||||
return Object.fromEntries(
|
}
|
||||||
Object.entries(value)
|
function toSignal(signal, value){
|
||||||
.map(([ key, value ])=> [ key, create(value) ])
|
signal[mark]= {
|
||||||
);
|
|
||||||
const signal= (...value)=>
|
|
||||||
value.length ? write(signal, value[0]) : read(signal);
|
|
||||||
Object.assign(signal, {
|
|
||||||
[mark]: true,
|
|
||||||
value,
|
value,
|
||||||
listeners: new Set()
|
listeners: new Set()
|
||||||
});
|
};
|
||||||
return signal;
|
return signal;
|
||||||
}
|
}
|
||||||
|
function createWrapObject(type, signal){
|
||||||
|
return new Proxy(signal, {
|
||||||
|
set(_, p, newValue){
|
||||||
|
const s= signal[mark];
|
||||||
|
if(p in s.value){
|
||||||
|
const v= s.value[p];
|
||||||
|
if(isSignal(v)) return v(newValue);
|
||||||
|
return (s.value[p]= newValue);
|
||||||
|
}
|
||||||
|
const v= reactive(newValue);
|
||||||
|
s.value[p]= v;
|
||||||
|
s.listeners.forEach(fn=> fn(s.value));
|
||||||
|
return v;
|
||||||
|
},
|
||||||
|
deleteProperty(_, p){
|
||||||
|
const s= signal[mark];
|
||||||
|
Reflect.deleteProperty(s.value, p);
|
||||||
|
s.listeners.forEach(fn=> fn(s.value));
|
||||||
|
},
|
||||||
|
get(_, p){
|
||||||
|
if(mark===p) return signal[mark];
|
||||||
|
if("array"!==type || !(p in Array.prototype) || p==="length")
|
||||||
|
return Reflect.get(signal[mark].value, p);
|
||||||
|
return (...a)=> {
|
||||||
|
const s= signal[mark];
|
||||||
|
const result= Array.prototype[p].call(s.value, ...a);
|
||||||
|
//TODO optimize!
|
||||||
|
s.value.forEach((v, i)=> Reflect.set(s.value, i, reactive(v)));
|
||||||
|
s.listeners.forEach(fn=> fn(s.value));
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
function read({ value, listeners }){
|
function read({ value, listeners }){
|
||||||
const context= currentContext();
|
const context= currentContext();
|
||||||
if(context) listeners.add(context);
|
if(context) listeners.add(context);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
function write(signal, value){
|
function write(signal, value){
|
||||||
signal.value= value;
|
signal[mark].value= value;
|
||||||
signal.listeners.forEach(fn=> fn(value))
|
signal[mark].listeners.forEach(fn=> fn(value))
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { S, watch, el, namespace, assign, on, dispatch } from "../index.js";
|
import { S, reactive, watch, el, namespace, assign, on, dispatch } from "../index.js";
|
||||||
Object.assign(globalThis, { S, watch, el, namespace, assign, on, dispatch });
|
Object.assign(globalThis, { S, reactive, watch, el, namespace, assign, on, dispatch });
|
||||||
|
|
||||||
const { style, css }= createStyle();
|
const { style, css }= createStyle();
|
||||||
globalThis.test= console.log;
|
globalThis.test= console.log;
|
||||||
@ -21,7 +21,7 @@ function component({ name= "World", surname= "" }= {}){
|
|||||||
margin-inline-start: .5em;
|
margin-inline-start: .5em;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
const store= S({ name, surname });
|
const store= reactive({ name, surname });
|
||||||
const full_name= S(()=> store.name()+" "+store.surname());
|
const full_name= S(()=> store.name()+" "+store.surname());
|
||||||
on(full_name, console.log);
|
on(full_name, console.log);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user