import invariant from 'tiny-invariant'; import { z } from 'zod'; import { ApplicationController, Detail } from './application_controller'; export class TurboEventController extends ApplicationController { static values = { type: String, detail: Object }; declare readonly typeValue: string; declare readonly detailValue: Detail; connect(): void { this.globalDispatch(this.typeValue, this.detailValue); this.element.remove(); } } const MutationAction = z.enum(['show', 'hide', 'focus']); type MutationAction = z.infer; const Mutation = z.union([ z.object({ action: MutationAction, delay: z.number().optional(), target: z.string() }), z.object({ action: MutationAction, delay: z.number().optional(), targets: z.string() }) ]); type Mutation = z.infer; addEventListener('dom:mutation', (event) => { const detail = (event as CustomEvent).detail; const mutation = Mutation.parse(detail); mutate(mutation); }); const Mutations: Record void> = { hide: (mutation) => { for (const element of findElements(mutation)) { element.classList.add('hidden'); } }, show: (mutation) => { for (const element of findElements(mutation)) { element.classList.remove('hidden'); } }, focus: (mutation) => { for (const element of findElements(mutation)) { element.focus(); } } }; function mutate(mutation: Mutation) { const fn = Mutations[mutation.action]; invariant(fn, `Could not find mutation ${mutation.action}`); if (mutation.delay) { setTimeout(() => fn(mutation), mutation.delay); } else { fn(mutation); } } function findElements( mutation: Mutation ): Element[] { if ('target' in mutation) { const element = document.querySelector(`#${mutation.target}`); invariant(element, `Could not find element with id ${mutation.target}`); return [element]; } else if ('targets' in mutation) { return [...document.querySelectorAll(mutation.targets)]; } invariant(false, 'Could not find element'); }