Skip to content

Commit

Permalink
allow a custom event decoder to be specified for an event kind
Browse files Browse the repository at this point in the history
cleanup client hook and events
  • Loading branch information
eliknebel committed Nov 3, 2024
1 parent 99b861e commit f9eaea7
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 22 deletions.
54 changes: 45 additions & 9 deletions client/src/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,22 @@ export type EventHandlerProvider = (
) => On;

export const initEventHandlerProvider =
(socket: WebSocket): EventHandlerProvider =>
(el, events: EventIdentifier[]) =>
(
socket: WebSocket,
customEventDecoders: Record<string, any> = {}
): EventHandlerProvider =>
(elementTag, events: EventIdentifier[]) =>
events.reduce((acc, { kind, id }) => {
const handler = (e) => {
socket.send(
JSON.stringify(["event", { id, kind, value: valueForEvent(e) }])
JSON.stringify([
"event",
{
id,
kind,
value: valueForEvent(e, elementTag, customEventDecoders[kind]),
},
])
);
};

Expand All @@ -26,7 +36,13 @@ export const initEventHandlerProvider =
};
}, {});

const valueForEvent = (e) => {
const valueForEvent = (e: Event, elementTag, customEventDecoder) => {
// If a custom event decoder is provided, use it
if (customEventDecoder) {
return customEventDecoder(e);
}

// Otherwise, use the default event decoder based on the event type
if (e instanceof InputEvent || e instanceof PointerEvent) {
return {
target: {
Expand All @@ -48,19 +64,39 @@ const valueForEvent = (e) => {
};
}

// If the event is a submit event, we want to prevent the default form
// submission and send the form data instead
if (e instanceof SubmitEvent) {
// prevent the default form submission and page reload
e.preventDefault();

const formData = {};
new FormData(e.target as HTMLFormElement).forEach(
(value, key) => (formData[key] = value)
);
return {
formData: buildFormData(e.target as HTMLFormElement),
};
}

// If the event is a change event on a form, we want to send the form data
if (elementTag === "form" && e.type === "change") {
const inputEl = e.target as HTMLInputElement;

if (!inputEl.form) {
throw new Error(
"form change event requires the input to be inside a form"
);
}

return {
formData: formData,
formData: buildFormData(inputEl.form),
};
}

return null;
};

const buildFormData = (form: HTMLFormElement) => {
const formData = {};

new FormData(form).forEach((value, key) => (formData[key] = value));

return formData;
};
5 changes: 3 additions & 2 deletions client/src/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@ export type ClientHookProvider = (elementHooks: HookIdentifier[]) => Module;

export const initClientHookProvider = (
socket: WebSocket,
hooks: Record<string, any>,
clientHookMap: Record<string, any>
hooks: Record<string, any> = {}
): ClientHookProvider => {
let clientHookMap: Record<string, any> = {};

return (elementHooks: HookIdentifier[]) => ({
create: (emptyVNode, vnode) => {
elementHooks.forEach((h) => {
Expand Down
12 changes: 5 additions & 7 deletions client/src/sprocket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,12 @@ type Opts = {
targetEl?: Element;
hooks?: Record<string, any>;
initialProps?: Record<string, string>;
customEventDecoders?: Record<string, any>;
};

export function connect(path: String, opts: Opts) {
const csrfToken = opts.csrfToken || new Error("Missing CSRF token");
const targetEl = opts.targetEl || document.documentElement;
const hooks = opts.hooks || {};

let ws_protocol = location.protocol === "https:" ? "wss:" : "ws:";
let socket = new WebSocket(ws_protocol + "//" + location.host + path);
Expand All @@ -52,15 +52,13 @@ export function connect(path: String, opts: Opts) {
}
);

let clientHookMap: Record<string, any> = {};
const clientHookProvider = initClientHookProvider(
const clientHookProvider = initClientHookProvider(socket, opts.hooks);

const eventHandlerProvider = initEventHandlerProvider(
socket,
hooks,
clientHookMap
opts.customEventDecoders
);

const eventHandlerProvider = initEventHandlerProvider(socket);

const providers: Providers = {
clientHookProvider,
eventHandlerProvider,
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,4 @@
"snabbdom": "^3.5.1",
"topbar": "^2.0.1"
}
}
}
6 changes: 3 additions & 3 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1726,9 +1726,9 @@ camelcase@^6.2.0:
integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==

caniuse-lite@^1.0.30001449, caniuse-lite@^1.0.30001503:
version "1.0.30001589"
resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001589.tgz"
integrity sha512-vNQWS6kI+q6sBlHbh71IIeC+sRwK2N3EDySc/updIGhIee2x5z00J4c1242/5/d6EpEMdOnk/m+6tuk4/tcsqg==
version "1.0.30001677"
resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001677.tgz"
integrity sha512-fmfjsOlJUpMWu+mAAtZZZHz7UEwsUxIIvu1TJfO1HqFQvB/B+ii0xr9B5HpbZY/mC4XZ8SvjHJqtAY6pDPQEog==

chalk@^2.0.0:
version "2.4.2"
Expand Down

0 comments on commit f9eaea7

Please sign in to comment.