Files
bookhoard/web/src/events.ts
T
john-okeefe 60c5a093b5 feat(typescript): add core infrastructure modules
- Add centralized API type definitions (types/api.d.ts)
  - Interfaces for all API responses matching Go handler JSON
  - Snake_case field names matching actual API responses
  - Source file references in comments for verification

- Add API client module (api.ts)
  - Procedural get/post/put/delete functions
  - Automatic auth header injection
  - Exported to window for cross-module access

- Add DOM utilities (dom.ts)
  - escapeHtml for safe HTML rendering
  - querySelector wrappers with null checks
  - Element creation helpers

- Add event delegation helpers (events.ts)
  - Reusable event delegation pattern
  - Data attribute selectors for dynamic content

- Add localStorage wrapper (storage.ts)
  - Type-safe token management
  - Theme persistence helpers
2026-02-18 16:40:29 -05:00

118 lines
3.2 KiB
TypeScript

function onDelegatedClick(selector: string, handler: (element: HTMLElement, event: MouseEvent) => void): void {
document.addEventListener('click', (event: MouseEvent) => {
const target = event.target as HTMLElement;
const element = target.closest(selector) as HTMLElement | null;
if (element) {
handler(element, event);
}
});
}
function onDelegatedSubmit(selector: string, handler: (form: HTMLFormElement, event: Event) => void): void {
document.addEventListener('submit', (event: Event) => {
const target = event.target as HTMLElement;
const form = target.closest(selector) as HTMLFormElement | null;
if (form) {
handler(form, event);
}
});
}
function onDelegatedChange(selector: string, handler: (element: HTMLElement, event: Event) => void): void {
document.addEventListener('change', (event: Event) => {
const target = event.target as HTMLElement;
const element = target.closest(selector) as HTMLElement | null;
if (element) {
handler(element, event);
}
});
}
function onDelegatedKeydown(selector: string, handler: (element: HTMLElement, event: KeyboardEvent) => void): void {
document.addEventListener('keydown', (event: KeyboardEvent) => {
const target = event.target as HTMLElement;
const element = target.closest(selector) as HTMLElement | null;
if (element) {
handler(element, event);
}
});
}
function getDataAttribute(element: HTMLElement, name: string): string | undefined {
return element.dataset[name];
}
function setDataAttribute(element: HTMLElement, name: string, value: string): void {
element.dataset[name] = value;
}
function onClick(element: HTMLElement | null, handler: (event: MouseEvent) => void): void {
if (element) {
element.addEventListener('click', handler);
}
}
function onSubmit(element: HTMLFormElement | null, handler: (event: Event) => void): void {
if (element) {
element.addEventListener('submit', handler);
}
}
function onChange(element: HTMLElement | null, handler: (event: Event) => void): void {
if (element) {
element.addEventListener('change', handler);
}
}
function onKeydown(element: HTMLElement | null, handler: (event: KeyboardEvent) => void): void {
if (element) {
element.addEventListener('keydown', handler);
}
}
function onInput(element: HTMLElement | null, handler: (event: Event) => void): void {
if (element) {
element.addEventListener('input', handler);
}
}
function preventDefault(event: Event): void {
event.preventDefault();
}
function stopPropagation(event: Event): void {
event.stopPropagation();
}
(window as any).events = {
onDelegatedClick,
onDelegatedSubmit,
onDelegatedChange,
onDelegatedKeydown,
getDataAttribute,
setDataAttribute,
onClick,
onSubmit,
onChange,
onKeydown,
onInput,
preventDefault,
stopPropagation
};
export {
onDelegatedClick,
onDelegatedSubmit,
onDelegatedChange,
onDelegatedKeydown,
getDataAttribute,
setDataAttribute,
onClick,
onSubmit,
onChange,
onKeydown,
onInput,
preventDefault,
stopPropagation
};