summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOwen Jacobson <owen@grimoire.ca>2025-07-08 01:35:28 -0400
committerOwen Jacobson <owen@grimoire.ca>2025-07-08 01:58:25 -0400
commitc631c8fc855b1854f14fc7fbf1d8afedaa37a0db (patch)
treee14698c4a26382461f3290564212e77fdaca5d1e
parentaeb159c401ef446e6564e5a3643027560a3e22f4 (diff)
Event capture and display tools.
This is meant to be used in swatches, to display the events and callbacks generated by a component as part of the swatch. The usage pattern is described in the comments (in both places). Naturally, this has its own swatch.
-rw-r--r--ui/lib/components/swatch/EventLog.svelte37
-rw-r--r--ui/lib/swatch/event-capture.svelte.js22
-rw-r--r--ui/routes/(swatch)/.swatch/+page.svelte4
-rw-r--r--ui/routes/(swatch)/.swatch/swatch/EventLog/+page.svelte38
4 files changed, 100 insertions, 1 deletions
diff --git a/ui/lib/components/swatch/EventLog.svelte b/ui/lib/components/swatch/EventLog.svelte
new file mode 100644
index 0000000..2d8c5c0
--- /dev/null
+++ b/ui/lib/components/swatch/EventLog.svelte
@@ -0,0 +1,37 @@
+<script>
+ /*
+ * The interface exposed by this component is designed to be compatible with the interface
+ * exposed by the `EventCapture` class, so that you can do this:
+ *
+ * let capture = $state(new EventCapture());
+ * const someEvent = capture.on('someEvent');
+ *
+ * // …
+ *
+ * <EventLog events={capture.events} clear={capture.clear.bind(capture)} />
+ */
+
+ let { events, clear = () => {} } = $props();
+
+ function onclick() {
+ clear();
+ }
+</script>
+
+<button {onclick}>clear</button>
+<table>
+ <thead>
+ <tr>
+ <th>event</th>
+ <th>arguments</th>
+ </tr>
+ </thead>
+ <tbody>
+ {#each events as { event, args }}
+ <tr>
+ <td>{event}</td>
+ <td><code>{JSON.stringify(args)}</code></td>
+ </tr>
+ {/each}
+ </tbody>
+</table>
diff --git a/ui/lib/swatch/event-capture.svelte.js b/ui/lib/swatch/event-capture.svelte.js
new file mode 100644
index 0000000..32c0f39
--- /dev/null
+++ b/ui/lib/swatch/event-capture.svelte.js
@@ -0,0 +1,22 @@
+/*
+ * The interface exposed by this class is designed to closely match the interface expected by
+ * the `EventLog` component, so that you can do this:
+ *
+ * let capture = $state(new EventCapture());
+ * const someEvent = capture.on('someEvent');
+ *
+ * // …
+ *
+ * <EventLog events={capture.events} clear={capture.clear.bind(capture)} />
+ */
+export default class EventCapture {
+ events = $state([]);
+
+ on(event) {
+ return (...args) => this.events.push({ event, args });
+ }
+
+ clear() {
+ this.events = [];
+ }
+}
diff --git a/ui/routes/(swatch)/.swatch/+page.svelte b/ui/routes/(swatch)/.swatch/+page.svelte
index 8d03c8d..abcb53f 100644
--- a/ui/routes/(swatch)/.swatch/+page.svelte
+++ b/ui/routes/(swatch)/.swatch/+page.svelte
@@ -7,4 +7,6 @@
<h2>components</h2>
-<ul></ul>
+<ul>
+ <li><a href="swatch/EventLog">swatch/EventLog</a></li>
+</ul>
diff --git a/ui/routes/(swatch)/.swatch/swatch/EventLog/+page.svelte b/ui/routes/(swatch)/.swatch/swatch/EventLog/+page.svelte
new file mode 100644
index 0000000..a751ca3
--- /dev/null
+++ b/ui/routes/(swatch)/.swatch/swatch/EventLog/+page.svelte
@@ -0,0 +1,38 @@
+<script>
+ import EventCapture from '$lib/swatch/event-capture.svelte.js';
+ import { json } from '$lib/swatch/derive.js';
+
+ import EventLog from '$lib/components/swatch/EventLog.svelte';
+
+ let eventsInput = $state(
+ JSON.stringify(
+ [{ event: 'example', args: ['argument a', 'argument b'] }],
+ /* replacer */ null,
+ /* space */ 2,
+ ),
+ );
+ let events = $derived(json(eventsInput));
+
+ let capture = $state(new EventCapture());
+ const clear = capture.on('clear');
+</script>
+
+<h1><code>swatch/EventLog</code></h1>
+
+<nav><p><a href="..">Back to swatches</a></p></nav>
+
+<h2>properties</h2>
+
+<div class="component-properties">
+ <label>events (json) <textarea bind:value={eventsInput}></textarea></label>
+</div>
+
+<h2>rendered</h2>
+
+<div class="component-preview">
+ <EventLog {events} {clear} />
+</div>
+
+<h2>events</h2>
+
+<EventLog events={capture.events} clear={capture.clear.bind(capture)} />