Skip to content

Instantly share code, notes, and snippets.

@adamghill
Last active January 1, 2025 22:41
Show Gist options
  • Save adamghill/2a102ba71ca3d5e15fb8d4f452defb92 to your computer and use it in GitHub Desktop.
Save adamghill/2a102ba71ca3d5e15fb8d4f452defb92 to your computer and use it in GitHub Desktop.
Playing around with some ideas in https://hawkticehurst.com/2024/12/declarative-signals/
<!--
Just playing around with https://github.com/hawkticehurst/stellar/blob/vnext/signal-element.js from https://hawkticehurst.com/2024/12/declarative-signals/.
There are also some silly utility functions here to clean up the examples below.
How-to:
1. Grab my fork at https://github.com/adamghill/stellar/blob/remove-custom-renderer/signal-element.js
2. Grab this HTML
3. `python -m http.server 8000`
4. Go to http://localhost:8000/signal-element-example.html
-->
<!DOCTYPE html>
<html lang="en">
<head>
<!-- From https://github.com/adamghill/stellar/blob/remove-custom-renderer/signal-element.js -->
<script type="module" src="signal-element.js"></script>
<!-- Silly utility functions -->
<script>
const select = function(selector) {
return document.querySelector(selector);
}
const listen = function(el, event, fn, options) {
if (Array.isArray(event)) {
for (const e of event) {
listen(el, e, fn);
}
return
}
if (typeof el === 'string') {
return listen(select(el), event, fn);
}
if (typeof event === 'symbol') {
event = event.description;
}
return el.addEventListener(event, fn, options);
}
const Event = Object.freeze({
LOAD: Symbol("load"),
CLICK: Symbol("click"),
INPUT: Symbol("input"),
KEYDOWN: Symbol("keydown"),
});
</script>
</head>
<body>
<signal-hello-world>
<h1>Hello World</h1>
<label for="input">Enter name:</label>
<input id="input" type="text" value="World" />
<p>
Hello <x-signal>World</x-signal>!
</p>
<script>
const name = select('signal-hello-world x-signal');
listen('signal-hello-world input', Event.INPUT, (event) => {
name.state = event.currentTarget.value;
});
</script>
</signal-hello-world>
<signal-counter>
<h1>Counter</h1>
<button>Count is <x-signal>0</x-signal></button>
<script>
const button = select('signal-counter button');
const count = select('signal-counter x-signal');
listen(button, Event.CLICK, () => {
count.state = count.state + 1;
});
</script>
</signal-counter>
<signal-markdown-editor>
<h1>Markdown Editor</h1>
<markdown-editor>
<textarea># Hello markdown!</textarea>
<x-signal render="html">
<h1>Hello markdown!</h1>
</x-signal>
</markdown-editor>
<script type="module">
import { marked } from 'https://unpkg.com/[email protected]/lib/marked.esm.js';
const editor = select('signal-markdown-editor textarea');
const output = select('signal-markdown-editor x-signal');
listen(editor, [Event.LOAD, Event.INPUT], () => {
output.state = marked(editor.value)
});
</script>
</signal-markdown-editor>
<signal-custom-render>
<h1>Custom Render</h1>
<p>
<x-signal id="numbers" state="[1,2,3,4]"></x-signal>
=
<x-signal id="sum"></x-signal>
</p>
<button id="add">Add number</button>
<script type="module">
const numbers = select('signal-custom-render #numbers');
numbers.render = (state) => {
return state.join(' + ');
};
const sum = select('signal-custom-render #sum');
sum.render = (state) => {
sum.state = numbers.state.reduce((s, c) => s + c, 0);
return sum.state;
};
listen('signal-custom-render #add', Event.CLICK, () => {
numbers.state = [...numbers.state, numbers.state.length + 1];
});
</script>
</signal-custom-render>
<signal-todo>
<h1>Todo List</h1>
<label for="todo">Add todo:</label>
<div>
<input id="todo" type="text" />
<button>Add</button>
</div>
<x-signal state="['Get groceries']" id="todos">
<ul>
<li>Get groceries</li>
</ul>
</x-signal>
<script>
const todos = select('signal-todo #todos');
todos.render = (state) => {
return `<ul>
${state.map((todo) => `<li>${todo}</li>`).join('')}
</ul>`;
};
const todo = select('signal-todo #todo');
function addTodo() {
if (todo.value.length > 0) {
todos.state = [...todos.state, todo.value];
todo.value = '';
}
}
listen(todo, Event.KEYDOWN, (event) => {
if (event.key === 'Enter') {
addTodo();
}
});
listen('signal-todo button', Event.CLICK, addTodo);
</script>
</signal-todo>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment