From a36786042b608993deebd15b052d25dea47d8965 Mon Sep 17 00:00:00 2001 From: Jan Andrle Date: Sat, 26 Aug 2023 12:20:01 +0200 Subject: [PATCH] :recycle: Refactore, add abort option --- src/dom.js | 6 ++++-- src/events.js | 18 +++++++++++++++--- src/helpers.js | 6 ++++++ src/signals-common.js | 23 +++++++++++++++++++++++ src/signals.js | 18 +++--------------- test/index.js | 8 +++----- 6 files changed, 54 insertions(+), 25 deletions(-) create mode 100644 src/helpers.js create mode 100644 src/signals-common.js diff --git a/src/dom.js b/src/dom.js index 5ca0a8a..1916463 100644 --- a/src/dom.js +++ b/src/dom.js @@ -1,4 +1,3 @@ -import { addSignalListener, isSignal } from './signals.js'; let namespace_curr= "html"; export function namespace(namespace){ namespace_curr= namespace==="svg" ? "http://www.w3.org/2000/svg" : namespace; @@ -6,8 +5,10 @@ export function namespace(namespace){ append(el){ namespace_curr= "html"; return el; } }; } +import { typeOf } from './helpers.js'; +import { isSignal, valueOfSignal } from './signals-common.js'; export function createElement(tag, attributes, ...connect){ - if(typeof attributes==="string" || ( isSignal(attributes) /* TODO && isText*/ )) + if(typeOf(attributes)!=="[object Object]" || ( isSignal(attributes) && typeOf(valueOfSignal(attributes))!=="[object Object]" )) attributes= { textContent: attributes }; let el; switch(true){ @@ -22,6 +23,7 @@ export function createElement(tag, attributes, ...connect){ } export { createElement as el }; +import { addSignalListener } from './signals-common.js'; export function assign(element, ...attributes){ if(!attributes.length) return element; const is_svg= element instanceof SVGElement; diff --git a/src/events.js b/src/events.js index 3511114..fe76e0a 100644 --- a/src/events.js +++ b/src/events.js @@ -1,7 +1,18 @@ -import { isSignal, addSignalListener } from './signals.js'; +import { isSignal, addSignalListener, removeSignalListener } from './signals-common.js'; export function on(event, listener, options){ - if(isSignal(event)) return addSignalListener(event, listener); - return element=> element.addEventListener(event, listener, options); + if(!isSignal(event)) + return element=> element.addEventListener(event, listener, options); + //TODO cleanup when signal removed (also TODO) + if(options && options.signal) + options.signal.addEventListener("abort", ()=> removeSignalListener(event, listener)); + return addSignalListener(event, listener); +} +export function off(){//TODO is needed? + const abort= new AbortController(); + return new Proxy(()=> abort.abort(), { + get(_, p){ return Reflect.get(abort, p); }, + ownKeys(){ return [ "signal" ]; } + }) } export function dispatch(event, detail){ if(typeof event === "string") @@ -10,6 +21,7 @@ export function dispatch(event, detail){ } const connections_changes= connectionsChangesObserverConstructor(); +//TODO remove listener(s) options on.connected= function(listener){ return function registerElement(element){ connections_changes.onConnected(element, listener); diff --git a/src/helpers.js b/src/helpers.js new file mode 100644 index 0000000..d50c83f --- /dev/null +++ b/src/helpers.js @@ -0,0 +1,6 @@ +export function typeOf(v){ + const t= typeof v; + if(t!=="object") return t; + if(v===null) return "null"; + return Object.prototype.toString.call(v); +} diff --git a/src/signals-common.js b/src/signals-common.js new file mode 100644 index 0000000..8b208b0 --- /dev/null +++ b/src/signals-common.js @@ -0,0 +1,23 @@ +export const mark= Symbol.for("signal"); + +export function isSignal(candidate){ + try{ return Reflect.has(candidate, mark); } + catch(e){ return false; } +} +export function valueOfSignal(signal){ + return signal[mark].value; +} +export function toSignal(signal, value){ + signal[mark]= { + value, + listeners: new Set() + }; + return signal; +} + +export function addSignalListener(signal, listener){ + return signal[mark].listeners.add(listener); +} +export function removeSignalListener(signal, listener){ + return signal[mark].listeners.delete(listener); +} diff --git a/src/signals.js b/src/signals.js index 7cf322f..7b16061 100644 --- a/src/signals.js +++ b/src/signals.js @@ -1,11 +1,6 @@ -const mark= Symbol.for("signal"); -export function isSignal(candidate){ - try{ return Reflect.has(candidate, mark); } - catch(e){ return false; } -} -export function addSignalListener(signal, listener){ - return signal[mark].listeners.add(listener); -} +import { mark, isSignal, toSignal, addSignalListener } from "./signals-common.js"; +export { isSignal, addSignalListener }; + export function S(value){ if(typeof value!=="function") return create(value); @@ -59,13 +54,6 @@ function create(value){ 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){ diff --git a/test/index.js b/test/index.js index 835b0ed..19cd0e2 100644 --- a/test/index.js +++ b/test/index.js @@ -1,11 +1,9 @@ -import { S, empty, watch, el, namespace, assign, on, dispatch } from "../index.js"; -Object.assign(globalThis, { S, watch, el, namespace, assign, on, dispatch }); +import { S, el, on, off } from "../index.js"; +//import { empty, namespace, on, dispatch } from "../index.js"; +Object.assign(globalThis, { S, el, on, off }); const style= createStyle(); const app= el(todosComponent); -dispatch("change", "Peter")(app); -console.log(app, app instanceof HTMLDivElement); - document.head.append(style.element); document.body.append(app);