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){
|
||||
if(isSignal(event)) return event.listeners.add(listener);
|
||||
if(isSignal(event)) return addSignalListener(event, listener);
|
||||
return element=> element.addEventListener(event, listener, options);
|
||||
}
|
||||
export function dispatch(event, detail){
|
||||
|
@ -3,15 +3,41 @@ export function isSignal(candidate){
|
||||
try{ return Reflect.has(candidate, mark); }
|
||||
catch(e){ return false; }
|
||||
}
|
||||
export function S(signal){
|
||||
if(typeof signal!=="function")
|
||||
return create(signal);
|
||||
if(isSignal(signal)) return signal;
|
||||
export function addSignalListener(signal, listener){
|
||||
return signal[mark].listeners.add(listener);
|
||||
}
|
||||
export function S(value){
|
||||
if(typeof value!=="function")
|
||||
return create(value);
|
||||
if(isSignal(value)) return value;
|
||||
|
||||
const out= create();
|
||||
watch(()=> out(signal()));
|
||||
watch(()=> out(value()));
|
||||
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= [];
|
||||
export function watch(context){
|
||||
stack.push(context);
|
||||
@ -24,28 +50,57 @@ function currentContext(){
|
||||
}
|
||||
function create(value){
|
||||
if(isSignal(value)) return value;
|
||||
|
||||
if(typeof value==="object" && value!==null)
|
||||
//TODO Array?
|
||||
return Object.fromEntries(
|
||||
Object.entries(value)
|
||||
.map(([ key, value ])=> [ key, create(value) ])
|
||||
);
|
||||
const signal= (...value)=>
|
||||
value.length ? write(signal, value[0]) : read(signal);
|
||||
Object.assign(signal, {
|
||||
[mark]: true,
|
||||
value.length ? write(signal, value[0]) : read(signal[mark]);
|
||||
return toSignal(signal, value);
|
||||
}
|
||||
function toSignal(signal, value){
|
||||
signal[mark]= {
|
||||
value,
|
||||
listeners: new Set()
|
||||
});
|
||||
};
|
||||
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 }){
|
||||
const context= currentContext();
|
||||
if(context) listeners.add(context);
|
||||
return value;
|
||||
}
|
||||
function write(signal, value){
|
||||
signal.value= value;
|
||||
signal.listeners.forEach(fn=> fn(value))
|
||||
signal[mark].value= value;
|
||||
signal[mark].listeners.forEach(fn=> fn(value))
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { S, watch, el, namespace, assign, on, dispatch } from "../index.js";
|
||||
Object.assign(globalThis, { S, watch, el, namespace, assign, on, dispatch });
|
||||
import { S, reactive, watch, el, namespace, assign, on, dispatch } from "../index.js";
|
||||
Object.assign(globalThis, { S, reactive, watch, el, namespace, assign, on, dispatch });
|
||||
|
||||
const { style, css }= createStyle();
|
||||
globalThis.test= console.log;
|
||||
@ -21,7 +21,7 @@ function component({ name= "World", surname= "" }= {}){
|
||||
margin-inline-start: .5em;
|
||||
}
|
||||
`;
|
||||
const store= S({ name, surname });
|
||||
const store= reactive({ name, surname });
|
||||
const full_name= S(()=> store.name()+" "+store.surname());
|
||||
on(full_name, console.log);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user