/**
* 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 {};