preact
Version:
Fast 3kb React-compatible Virtual DOM library.
191 lines (165 loc) • 6.17 kB
TypeScript
// Intentionally not using a relative path to take advantage of
// the TS version resolution mechanism
import * as preact from 'preact';
export enum HookType {
useState = 1,
useReducer = 2,
useEffect = 3,
useLayoutEffect = 4,
useRef = 5,
useImperativeHandle = 6,
useMemo = 7,
useCallback = 8,
useContext = 9,
useErrorBoundary = 10,
// Not a real hook, but the devtools treat is as such
useDebugvalue = 11
}
export interface DevSource {
fileName: string;
lineNumber: number;
}
export interface ErrorInfo {
componentStack?: string;
}
export interface Options extends preact.Options {
/** Attach a hook that is invoked before render, mainly to check the arguments. */
_root?(vnode: ComponentChild, parent: preact.ContainerNode): void;
/** Attach a hook that is invoked before a vnode is diffed. */
_diff?(vnode: VNode): void;
/** Attach a hook that is invoked after a tree was mounted or was updated. */
_commit?(vnode: VNode, commitQueue: Component[]): void;
/** Attach a hook that is invoked before a vnode has rendered. */
_render?(vnode: VNode): void;
/** Attach a hook that is invoked before a hook's state is queried. */
_hook?(component: Component, index: number, type: HookType): void;
/** Bypass effect execution. Currenty only used in devtools for hooks inspection */
_skipEffects?: boolean;
/** Attach a hook that is invoked after an error is caught in a component but before calling lifecycle hooks */
_catchError(
error: any,
vnode: VNode,
oldVNode?: VNode | undefined,
errorInfo?: ErrorInfo | undefined
): void;
/** Attach a hook that fires when hydration can't find a proper DOM-node to match with */
_hydrationMismatch?(
vnode: VNode,
excessDomChildren: Array<PreactElement | null>
): void;
}
export type ComponentChild =
| VNode<any>
| string
| number
| boolean
| null
| undefined;
export type ComponentChildren = ComponentChild[] | ComponentChild;
export interface FunctionComponent<P = {}>
extends preact.FunctionComponent<P> {
// Internally, createContext uses `contextType` on a Function component to
// implement the Consumer component
contextType?: PreactContext;
// Internally, createContext stores a ref to the context object on the Provider
// Function component to help devtools
_contextRef?: PreactContext;
// Define these properties as undefined on FunctionComponent to get rid of
// some errors in `diff()`
getDerivedStateFromProps?: undefined;
getDerivedStateFromError?: undefined;
}
export interface ComponentClass<P = {}> extends preact.ComponentClass<P> {
_contextRef?: any;
// Override public contextType with internal PreactContext type
contextType?: PreactContext;
}
// Redefine ComponentType using our new internal FunctionComponent interface above
export type ComponentType<P = {}> = ComponentClass<P> | FunctionComponent<P>;
export interface PreactElement extends preact.ContainerNode {
// Namespace detection
readonly namespaceURI?: string;
// Property used to update Text nodes
data?: CharacterData['data'];
// Property to set __dangerouslySetInnerHTML
innerHTML?: Element['innerHTML'];
// Attribute reading and setting
readonly attributes?: Element['attributes'];
setAttribute?: Element['setAttribute'];
removeAttribute?: Element['removeAttribute'];
// Event listeners
addEventListener?: Element['addEventListener'];
removeEventListener?: Element['removeEventListener'];
// Setting styles
readonly style?: CSSStyleDeclaration;
// nextSibling required for inserting nodes
readonly nextSibling: PreactElement | null;
// Used to match DOM nodes to VNodes during hydration. Note: doesn't exist
// on Text nodes
readonly localName?: string;
// Input handling
value?: HTMLInputElement['value'];
checked?: HTMLInputElement['checked'];
// Internal properties
_children?: VNode<any> | null;
/** Event listeners to support event delegation */
_listeners?: Record<string, (e: Event) => void>;
}
export interface PreactEvent extends Event {
_dispatched?: number;
}
// We use the `current` property to differentiate between the two kinds of Refs so
// internally we'll define `current` on both to make TypeScript happy
type RefObject<T> = { current: T | null };
type RefCallback<T> = {
(instance: T | null): void | (() => void);
current: undefined;
};
export type Ref<T> = RefObject<T> | RefCallback<T>;
export interface VNode<P = {}> extends preact.VNode<P> {
// Redefine type here using our internal ComponentType type, and specify
// string has an undefined `defaultProps` property to make TS happy
type: (string & { defaultProps: undefined }) | ComponentType<P>;
props: P & { children: ComponentChildren };
ref?: Ref<any> | null;
_children: Array<VNode<any>> | null;
_parent: VNode | null;
_depth: number | null;
/**
* The [first (for Fragments)] DOM child of a VNode
*/
_dom: PreactElement | null;
_component: Component | null;
constructor: undefined;
_original: number;
_index: number;
_flags: number;
}
export interface Component<P = {}, S = {}> extends Omit<preact.Component<P, S>, 'base'> {
// When component is functional component, this is reset to functional component
constructor: ComponentType<P>;
state: S; // Override Component["state"] to not be readonly for internal use, specifically Hooks
base?: PreactElement;
_dirty: boolean;
_force?: boolean;
_renderCallbacks: Array<() => void>; // Only class components
_stateCallbacks: Array<() => void>; // Only class components
_globalContext?: any;
_vnode?: VNode<P> | null;
_nextState?: S | null; // Only class components
/** Only used in the devtools to later dirty check if state has changed */
_prevState?: S | null;
/**
* Pointer to the parent dom node. This is only needed for top-level Fragment
* components or array returns.
*/
_parentDom?: PreactElement | null;
// Always read, set only when handling error
_processingException?: Component<any, any> | null;
// Always read, set only when handling error. This is used to indicate at diffTime to set _processingException
_pendingError?: Component<any, any> | null;
}
export interface PreactContext extends preact.Context<any> {
_id: string;
_defaultValue: any;
}