@tempots/dom
Version:
Fully-typed frontend framework alternative to React and Angular
182 lines (181 loc) • 5.27 kB
TypeScript
import { DOMContext } from '../dom/dom-context';
import { Value } from '../std/value';
/**
* A function that renders content into the DOM and returns a cleanup function.
*
* Renderables are the fundamental building blocks of Tempo applications. They receive
* a DOMContext and use it to create DOM elements, text nodes, or other content.
* The returned Clear function is called when the renderable needs to be removed
* from the DOM.
*
* @example
* ```typescript
* // Simple renderable that creates a div
* const MyComponent: Renderable = (ctx) => {
* const divCtx = ctx.makeChildElement('div', undefined)
* divCtx.makeChildText('Hello, World!')
*
* // Return cleanup function
* return (removeTree) => {
* if (removeTree) {
* // Cleanup logic here
* }
* }
* }
* ```
*
* @example
* ```typescript
* // Renderable with event listeners
* const Button: Renderable = (ctx) => {
* const buttonCtx = ctx.makeChildElement('button', undefined)
* buttonCtx.makeChildText('Click me')
*
* const clearClick = buttonCtx.on('click', () => {
* console.log('Button clicked!')
* })
*
* return (removeTree) => {
* clearClick(removeTree)
* }
* }
* ```
*
* @template CTX - The type of DOMContext (defaults to DOMContext)
* @param ctx - The DOM context for rendering
* @returns A cleanup function that removes the rendered content when called
* @public
*/
export type Renderable<CTX extends DOMContext = DOMContext> = (ctx: CTX) => Clear;
/**
* A flexible type representing any content that can be rendered in Tempo.
*
* TNode (Template Node) is the union type that encompasses all possible content
* that can be rendered in a Tempo application. This includes components, text,
* signals, arrays of content, and null/undefined values for conditional rendering.
*
* @example
* ```typescript
* // All of these are valid TNode values:
*
* // Renderable component
* const component: TNode = MyComponent()
*
* // Static text
* const text: TNode = 'Hello, World!'
*
* // Signal text
* const dynamicText: TNode = userNameSignal
*
* // Array of content
* const list: TNode = [
* html.div('Item 1'),
* html.div('Item 2'),
* html.div('Item 3')
* ]
*
* // Conditional content
* const conditional: TNode = isVisible.value ? html.div('Visible') : null
* ```
*
* @example
* ```typescript
* // Function that accepts any renderable content
* function Container(children: TNode): Renderable {
* return html.div(
* attr.class('container'),
* children // Can be any TNode type
* )
* }
*
* // Usage with different TNode types
* Container('Simple text')
* Container(MyComponent())
* Container([html.p('Paragraph 1'), html.p('Paragraph 2')])
* Container(isLoading.value ? 'Loading...' : null)
* ```
*
* @example
* ```typescript
* // Building complex content with TNode
* const buildContent = (items: string[]): TNode => {
* if (items.length === 0) {
* return html.div('No items found')
* }
*
* return items.map(item => html.div(item))
* }
* ```
*
* @template CTX - The type of DOMContext (defaults to DOMContext)
* @public
*/
export type TNode<CTX extends DOMContext = DOMContext> = Renderable<CTX> | Value<string> | undefined | null | Renderable<CTX>[];
/**
* Represents a function that clears a resource.
* @param removeTree - A boolean value indicating whether to remove the tree associated with the resource.
* @public
*/
export type Clear = (removeTree: boolean) => void;
/**
* Represents a provider mark.
* @typeParam T - The type of the mark.
* @public
*/
export type ProviderMark<T> = symbol & {
readonly __type: T;
};
/**
* Represents a collection of providers.
* The keys of the record are ProviderMark types, and the values are of unknown type.
* @public
*/
export type Providers = Record<ProviderMark<unknown>, [
unknown,
undefined | (() => void)
]>;
/**
* Represents the size of an object with width and height.
* @public
*/
export type Size = {
/**
* The width of the object.
*/
readonly width: number;
/**
* The height of the object.
*/
readonly height: number;
};
/**
* Represents a nullable value or a signal of a nullable value.
* @typeParam T - The type of the value.
* @public
*/
export type NValue<T> = Value<T> | Value<T | null> | Value<T | undefined> | Value<T | null | undefined> | null | undefined;
/**
* Gets the value type of a given Value type.
* If the type is a `Signal`, it returns the inferred value type.
* Otherwise, it returns the type itself.
* @public
*/
export type GetValueType<T> = T extends Value<infer V> ? V : T;
/**
* Gets the value types of a given array of Value types.
* @public
*/
export type GetValueTypes<T extends Value<unknown>[]> = {
[K in keyof T]: GetValueType<T[K]>;
};
/**
* Removes signals from a given object type and returns a new object type
* with only the non-signal properties.
*
* @typeParam T - The input object type.
* @typeParam K - The keys of the input object type to keep (optional).
* @public
*/
export type RemoveSignals<T extends Record<string | number | symbol, Value<unknown>>, K extends (string | number | symbol) & keyof T = keyof T> = {
[k in K]: GetValueType<T[k]>;
};