/** * Azoth JSX Type Definitions * * Azoth JSX produces "DOM literals" - actual DOM elements, not virtual DOM. * `

hello

` yields an HTMLParagraphElement, not a React component. * * These type definitions leverage TypeScript's built-in lib.dom.d.ts types * to provide accurate intellisense for Azoth JSX. */ // Self-contained structural mirrors of maya's JSDoc typedefs. maya ships no // .d.ts (generated declarations are the future fix — see TODO), and consumers // can't resolve types from JSDoc'd .js without allowJs, so these live here. // Structural: any conforming object matches, including maya's real Channel. // channels/channel.js — the Input implementer + JSX component. interface Channel { readonly initial: unknown; readonly from: unknown; readonly append: boolean; update(props?: any, childNodes?: Node): Channel | void; } // compose/compose.js @typedef Input — "seed the slot, then drive it from a // source"; recognized structurally by `from`. interface Input { initial?: Composable; from: Promise | AsyncIterable | null | undefined; append?: boolean; } // compose/compose.js @typedef Component — create()'s full lifecycle shape // (optional one-time initialize intake + the UIComponent base). interface Component { initialize?(props?: any, childNodes?: Node): void; render(): Composable; update(props?: any, childNodes?: Node): Composable | void; } // maya's Composable — everything compose() accepts: a {…} slot value, or a // component's return. (DOMChild was the child subset; this is the full set, // mirroring compose's own dispatch.) type Composable = | string | number | bigint | boolean | null | undefined | Node | Channel | Input // { initial?, from, append? } // Anything with render() — compose's render branch needs only that; // update() is the ADDITIONAL change-channel verb (see UIComponent). // Structural, so render-only classes/objects are Composable too. | { render(): Composable } | Promise | AsyncIterable | ReadableStream | ((props?: any, childNodes?: Node) => Composable) // function / rerenderable | Composable[]; type DOMChild = Composable; // Properties to exclude from element attributes type ExcludedProps = "children"; // Get writable properties from an element, excluding functions and specific props type WritableElementProps = { [ K in keyof T as K extends ExcludedProps ? never : K extends string ? (T[K] extends Function ? never : K) : never ]?: T[K]; }; // HTML attributes that differ from DOM properties // Azoth supports both HTML attributes (class, for) and DOM properties (className, htmlFor) type HTMLAttributeAliases = { class?: string; // HTML attribute (alias for className) for?: string; // HTML attribute (alias for htmlFor) }; // Combined props for an intrinsic element type IntrinsicElementProps = & WritableElementProps & HTMLAttributeAliases & { children?: DOMChild; }; // Custom elements (hyphenated tags) are author-defined, so props are open. // Matched via a template-literal index key (below) so ONLY hyphenated tags // resolve to this — an unknown NON-hyphenated tag (e.g. an HTML typo) still // errors. Authors can augment a specific tag with precise props if they want. type CustomElementProps = { children?: DOMChild; [prop: string]: any; }; // SVG attributes are authored as strings/numbers, but the DOM reflects them as // SVGAnimated* objects — so reusing the element interfaces here would reject // `viewBox="0 0 10 10"` or `r={5}`. Open for now; precise SVG attribute typing // is a deferred refinement (a hand-rolled attribute map, React-style). type SVGElementProps = { children?: DOMChild; [attr: string]: any; }; declare global { namespace JSX { // JSX expressions evaluate to DOM Nodes // Specific element types require assertion:

hi

as HTMLParagraphElement // Future: TypeScript contribution for per-tag return types type Element = Node; // What may be used as a JSX tag: an intrinsic/custom-element string tag; // null/undefined (a conditional no-op — `` where C is null); a // function or class component (returns a Composable, including a // rerenderable, which is why `() => rerenderer(...)` typechecks); or a // Component object (create()'s full { initialize?, render, update }). // Components are invoked `(props, childNodes)` — childNodes is the // JSX content COMPOSED to one Node: the element itself for a single // child, a DocumentFragment for several/text/{expr}, absent for none. // (Pinned: valhalla/child-nodes.test.tsx.) type ElementType = | string // intrinsic + custom-element tags | null | undefined // conditional no-op: where C is null | ((props?: any, childNodes?: Node) => Composable) // function component | (new (props?: any, childNodes?: Node) => Composable) // class component | Component; // object component (full lifecycle) // Children attribute interface ElementChildrenAttribute { children: {}; } // Intrinsic elements: HTML + SVG interface IntrinsicElements { // HTML Elements a: IntrinsicElementProps; abbr: IntrinsicElementProps; address: IntrinsicElementProps; area: IntrinsicElementProps; article: IntrinsicElementProps; aside: IntrinsicElementProps; audio: IntrinsicElementProps; b: IntrinsicElementProps; base: IntrinsicElementProps; bdi: IntrinsicElementProps; bdo: IntrinsicElementProps; blockquote: IntrinsicElementProps; body: IntrinsicElementProps; br: IntrinsicElementProps; button: IntrinsicElementProps; canvas: IntrinsicElementProps; caption: IntrinsicElementProps; cite: IntrinsicElementProps; code: IntrinsicElementProps; col: IntrinsicElementProps; colgroup: IntrinsicElementProps; data: IntrinsicElementProps; datalist: IntrinsicElementProps; dd: IntrinsicElementProps; del: IntrinsicElementProps; details: IntrinsicElementProps; dfn: IntrinsicElementProps; dialog: IntrinsicElementProps; div: IntrinsicElementProps; dl: IntrinsicElementProps; dt: IntrinsicElementProps; em: IntrinsicElementProps; embed: IntrinsicElementProps; fieldset: IntrinsicElementProps; figcaption: IntrinsicElementProps; figure: IntrinsicElementProps; footer: IntrinsicElementProps; form: IntrinsicElementProps; h1: IntrinsicElementProps; h2: IntrinsicElementProps; h3: IntrinsicElementProps; h4: IntrinsicElementProps; h5: IntrinsicElementProps; h6: IntrinsicElementProps; head: IntrinsicElementProps; header: IntrinsicElementProps; hgroup: IntrinsicElementProps; hr: IntrinsicElementProps; html: IntrinsicElementProps; i: IntrinsicElementProps; iframe: IntrinsicElementProps; img: IntrinsicElementProps; input: IntrinsicElementProps; ins: IntrinsicElementProps; kbd: IntrinsicElementProps; label: IntrinsicElementProps; legend: IntrinsicElementProps; li: IntrinsicElementProps; link: IntrinsicElementProps; main: IntrinsicElementProps; map: IntrinsicElementProps; mark: IntrinsicElementProps; menu: IntrinsicElementProps; meta: IntrinsicElementProps; meter: IntrinsicElementProps; nav: IntrinsicElementProps; noscript: IntrinsicElementProps; object: IntrinsicElementProps; ol: IntrinsicElementProps; optgroup: IntrinsicElementProps; option: IntrinsicElementProps; output: IntrinsicElementProps; p: IntrinsicElementProps; picture: IntrinsicElementProps; pre: IntrinsicElementProps; progress: IntrinsicElementProps; q: IntrinsicElementProps; rp: IntrinsicElementProps; rt: IntrinsicElementProps; ruby: IntrinsicElementProps; s: IntrinsicElementProps; samp: IntrinsicElementProps; script: IntrinsicElementProps; section: IntrinsicElementProps; select: IntrinsicElementProps; slot: IntrinsicElementProps; small: IntrinsicElementProps; source: IntrinsicElementProps; span: IntrinsicElementProps; strong: IntrinsicElementProps; style: IntrinsicElementProps; sub: IntrinsicElementProps; summary: IntrinsicElementProps; sup: IntrinsicElementProps; table: IntrinsicElementProps; tbody: IntrinsicElementProps; td: IntrinsicElementProps; template: IntrinsicElementProps; textarea: IntrinsicElementProps; tfoot: IntrinsicElementProps; th: IntrinsicElementProps; thead: IntrinsicElementProps; time: IntrinsicElementProps; title: IntrinsicElementProps; tr: IntrinsicElementProps; track: IntrinsicElementProps; u: IntrinsicElementProps; ul: IntrinsicElementProps; var: IntrinsicElementProps; video: IntrinsicElementProps; wbr: IntrinsicElementProps; // SVG Elements (svg-only tag names; shared names like title/a/script // stay HTML above). Open props — see SVGElementProps. svg: SVGElementProps; g: SVGElementProps; path: SVGElementProps; circle: SVGElementProps; ellipse: SVGElementProps; rect: SVGElementProps; line: SVGElementProps; polyline: SVGElementProps; polygon: SVGElementProps; text: SVGElementProps; tspan: SVGElementProps; defs: SVGElementProps; use: SVGElementProps; symbol: SVGElementProps; clipPath: SVGElementProps; mask: SVGElementProps; pattern: SVGElementProps; image: SVGElementProps; linearGradient: SVGElementProps; radialGradient: SVGElementProps; stop: SVGElementProps; filter: SVGElementProps; foreignObject: SVGElementProps; marker: SVGElementProps; view: SVGElementProps; desc: SVGElementProps; metadata: SVGElementProps; // Custom elements: the template-literal key matches ONLY hyphenated // tags, so `` resolves here while a non-hyphenated typo // still errors. Author-defined → open props. [customTag: `${string}-${string}`]: CustomElementProps; } } // JSX factory function signature (for TypeScript's classic JSX transform) function h( tag: string, props?: object | null, ...children: DOMChild[] ): Node; function Fragment(props: { children?: DOMChild }): Node; } export {};