Skip to content

Commit

Permalink
feature: attach/detach node instead of hidden
Browse files Browse the repository at this point in the history
  • Loading branch information
KevinBLT committed Jan 11, 2024
1 parent 331bddc commit 6605d8b
Show file tree
Hide file tree
Showing 6 changed files with 88 additions and 20 deletions.
3 changes: 2 additions & 1 deletion packages/@hec.js/ui/example/nested-signal/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@
</head>
<body>

<pre>{{ person.name }}</pre>
<pre data-for="let person of persons">{{ person.name }}</pre>

<button data-on="click:nextName">Next name</button>
<button data-on="click:nextPerson">Next person</button>
<button data-on="click:nextList">Next list</button>
</body>
</html>
37 changes: 30 additions & 7 deletions packages/@hec.js/ui/example/nested-signal/signal.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,39 @@
import { signal, templateByNode } from "../../lib/index.js";
import { generateRandomName } from "./util.js";

const person = signal({
name: signal(generateRandomName())
})

function makeList() {
return Array.from({ length: 5 }, () => {
return signal({
name: signal(generateRandomName())
});
});
}

const persons = signal(makeList());

const nextList = () => {
persons(makeList());
}

const nextPerson = () => {

for (const p of persons()) {
p({ name: signal(generateRandomName()) });
}

}

const nextName = () => {
person().name(generateRandomName());
for (const p of persons()) {
p().name(generateRandomName());
}
}

templateByNode(document.body, {
person,
persons,
nextList,
nextName,
nextPerson: () => person({ name: signal(generateRandomName()) })
});
nextPerson,
});

13 changes: 13 additions & 0 deletions packages/@hec.js/ui/example/plugins/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -54,5 +54,18 @@ <h3>[data-include]: Loades the data of given path lazily when the element is vis
<pre data-include="./include.html"></pre>
</div>

<div>
<h3>[data-route]: Shows a node only if a route matches.</h3>

<button onclick="history.pushState(null, null, './fu/')">Reveal</button>

<div data-route="/example/plugins/fu/">
I am here!
<div data-route="/">
OK :)
</div>
</div>
</div>

</body>
</html>
12 changes: 10 additions & 2 deletions packages/@hec.js/ui/lib/src/plugins/data-if.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,19 @@ export const dataIfPlugin = {
select: '[data-if]',

run: (node, props) => {
const condition = prop(props, node.dataset.if);
const condition = prop(props, node.dataset.if),
placeholder = document.createComment('if: ' + node.dataset.if);

node.replaceWith(placeholder);

/** @param { boolean } condition */
const update = (condition) => {
node.hidden = !condition;
if (condition) {
node.hidden = false;
placeholder.after(node);
} else {
node.remove();
}
}

update(f(condition));
Expand Down
16 changes: 13 additions & 3 deletions packages/@hec.js/ui/lib/src/plugins/data-route.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,28 @@ export const dataRoutePlugin = {
select: '[data-route]',

run: (node) => {
const pattern = new URLPattern({pathname: joinsRoutes(node)});
const absoluteRoute = joinsRoutes(node),
pattern = new URLPattern({pathname: absoluteRoute}),
placeholder = document.createComment('route: ' + absoluteRoute);

node.replaceWith(placeholder);

const update = () => {
node.hidden = !pattern.test(location.href);
const href = location.href.replace(/index\.*[a-z0-9]*$/gm, '');

if (!node.hidden) {
if (pattern.test(href)) {
node.hidden = false;
placeholder.after(node);

/** @type { HTMLMetaElement } */
const meta = document.querySelector('head meta[name="route"]');

if (meta) {
meta.content = pattern.pathname;
}

} else {
node.remove();
}
}

Expand Down
27 changes: 20 additions & 7 deletions packages/@hec.js/ui/lib/src/signal.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ import { f } from "./props.js";
* } & ((newValue?: T | undefined) => T) } Signal
*/

/**
* @template T
* @typedef { (subcription: Subscriber<T>, options?: { signal: AbortSignal } | undefined) => void } SubscribeFn
*/

/**
* @template T
* @param { T } value
Expand Down Expand Up @@ -48,10 +53,7 @@ export function signal(value = null, options = {}) {
return value;
}

/**
* @param { Subscriber<T> } subscription
* @param { { signal: AbortSignal } | undefined } options
*/
/** @type { SubscribeFn<T> } */
const subscribe = (subscription, options = null) => {
subscribers.push(subscription);

Expand All @@ -78,11 +80,22 @@ export function signal(value = null, options = {}) {
* @returns { Signal<V> }
*/
map: (fn) => {
const mapped = signal(fn(value));
const mapped = signal(fn(value)),
abort = new AbortController(),
sub = mapped.subscribe;

subscribe({ next: (v) => mapped(fn(v)) }, { signal: abort.signal });

return Object.assign(mapped, {
set: () => null,

subscribe({ next: (v) => mapped(fn(v)) });
/** @type { SubscribeFn<V> } */
subscribe: (subscription, options) => {
sub(subscription, options);
options?.signal.addEventListener('abort', () => abort.abort());
}

return Object.assign(mapped, { set: () => null });
});
},

/**
Expand Down

0 comments on commit 6605d8b

Please sign in to comment.