UNPKG

@vitus-labs/core

Version:
339 lines (338 loc) 18.2 kB
import * as React from "react"; import { ComponentType, FC, ReactNode, cloneElement, createElement } from "react"; //#region src/compose.d.ts type ArityOneFn = (arg: any) => any; /** Extracts the last function from a tuple type. */ type PickLastInTuple<T extends any[]> = T extends [...rest: infer _U, argn: infer L] ? L : any; /** Parameter type of the rightmost (first-applied) function. */ type FirstFnParameterType<T extends any[]> = Parameters<PickLastInTuple<T>>[any]; /** Return type of the leftmost (last-applied) function. */ type LastFnReturnType<T extends any[]> = ReturnType<T[0]>; /** * Right-to-left function composition. * `compose(f, g, h)(x)` === `f(g(h(x)))`. * * Used throughout the system to build HOC chains — * `compose(attrsHoc, userHoc1, userHoc2)(Component)`. */ declare const compose: <T extends ArityOneFn[]>(...fns: T) => (p: FirstFnParameterType<T>) => LastFnReturnType<T>; //#endregion //#region src/html/htmlElementAttrs.d.ts type Base = React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>; interface HTMLElementAttrs { a: React.DetailedHTMLProps<React.AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement>; abbr: Base; address: Base; area: React.DetailedHTMLProps<React.AreaHTMLAttributes<HTMLAreaElement>, HTMLAreaElement>; article: Base; aside: Base; audio: React.DetailedHTMLProps<React.AudioHTMLAttributes<HTMLAudioElement>, HTMLAudioElement>; b: Base; bdi: Base; bdo: Base; big: Base; blockquote: React.DetailedHTMLProps<React.BlockquoteHTMLAttributes<HTMLQuoteElement>, HTMLQuoteElement>; body: React.DetailedHTMLProps<React.HTMLAttributes<HTMLBodyElement>, HTMLBodyElement>; br: React.DetailedHTMLProps<React.HTMLAttributes<HTMLBRElement>, HTMLBRElement>; button: React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>; canvas: React.DetailedHTMLProps<React.CanvasHTMLAttributes<HTMLCanvasElement>, HTMLCanvasElement>; caption: Base; cite: React.DetailedHTMLProps<React.HTMLAttributes<HTMLQuoteElement>, HTMLQuoteElement>; code: Base; col: React.DetailedHTMLProps<React.ColHTMLAttributes<HTMLTableColElement>, HTMLTableColElement>; colgroup: React.DetailedHTMLProps<React.ColgroupHTMLAttributes<HTMLTableColElement>, HTMLTableColElement>; data: React.DetailedHTMLProps<React.DataHTMLAttributes<HTMLDataElement>, HTMLDataElement>; datalist: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDataListElement>, HTMLDataListElement>; dd: Base; del: React.DetailedHTMLProps<React.DelHTMLAttributes<HTMLModElement>, HTMLModElement>; details: Base; dfn: Base; dialog: React.DetailedHTMLProps<React.DialogHTMLAttributes<HTMLDialogElement>, HTMLDialogElement>; div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>; dl: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDListElement>, HTMLDListElement>; dt: Base; em: Base; embed: React.DetailedHTMLProps<React.EmbedHTMLAttributes<HTMLEmbedElement>, HTMLEmbedElement>; fieldset: React.DetailedHTMLProps<React.FieldsetHTMLAttributes<HTMLFieldSetElement>, HTMLFieldSetElement>; figcaption: Base; figure: Base; footer: Base; form: React.DetailedHTMLProps<React.FormHTMLAttributes<HTMLFormElement>, HTMLFormElement>; h1: React.DetailedHTMLProps<React.HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>; h2: React.DetailedHTMLProps<React.HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>; h3: React.DetailedHTMLProps<React.HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>; h4: React.DetailedHTMLProps<React.HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>; h5: React.DetailedHTMLProps<React.HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>; h6: React.DetailedHTMLProps<React.HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>; header: Base; hr: React.DetailedHTMLProps<React.HTMLAttributes<HTMLHRElement>, HTMLHRElement>; html: React.DetailedHTMLProps<React.HtmlHTMLAttributes<HTMLHtmlElement>, HTMLHtmlElement>; i: Base; iframe: React.DetailedHTMLProps<React.IframeHTMLAttributes<HTMLIFrameElement>, HTMLIFrameElement>; img: React.DetailedHTMLProps<React.ImgHTMLAttributes<HTMLImageElement>, HTMLImageElement>; input: React.DetailedHTMLProps<React.InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>; ins: React.DetailedHTMLProps<React.InsHTMLAttributes<HTMLModElement>, HTMLModElement>; kbd: Base; label: React.DetailedHTMLProps<React.LabelHTMLAttributes<HTMLLabelElement>, HTMLLabelElement>; legend: React.DetailedHTMLProps<React.HTMLAttributes<HTMLLegendElement>, HTMLLegendElement>; li: React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>; main: Base; map: React.DetailedHTMLProps<React.MapHTMLAttributes<HTMLMapElement>, HTMLMapElement>; mark: Base; meter: Base; nav: Base; object: React.DetailedHTMLProps<React.ObjectHTMLAttributes<HTMLObjectElement>, HTMLObjectElement>; ol: React.DetailedHTMLProps<React.OlHTMLAttributes<HTMLOListElement>, HTMLOListElement>; optgroup: React.DetailedHTMLProps<React.OptgroupHTMLAttributes<HTMLOptGroupElement>, HTMLOptGroupElement>; option: React.DetailedHTMLProps<React.OptionHTMLAttributes<HTMLOptionElement>, HTMLOptionElement>; output: Base; p: React.DetailedHTMLProps<React.HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>; picture: Base; pre: React.DetailedHTMLProps<React.HTMLAttributes<HTMLPreElement>, HTMLPreElement>; progress: React.DetailedHTMLProps<React.ProgressHTMLAttributes<HTMLProgressElement>, HTMLProgressElement>; q: React.DetailedHTMLProps<React.HTMLAttributes<HTMLQuoteElement>, HTMLQuoteElement>; rp: Base; rt: Base; ruby: Base; s: Base; samp: Base; section: Base; select: React.DetailedHTMLProps<React.SelectHTMLAttributes<HTMLSelectElement>, HTMLSelectElement>; small: Base; source: React.DetailedHTMLProps<React.SourceHTMLAttributes<HTMLSourceElement>, HTMLSourceElement>; span: React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>; strong: Base; sub: Base; summary: Base; sup: Base; svg: React.SVGProps<SVGSVGElement>; table: React.DetailedHTMLProps<React.TableHTMLAttributes<HTMLTableElement>, HTMLTableElement>; tbody: React.DetailedHTMLProps<React.HTMLAttributes<HTMLTableSectionElement>, HTMLTableSectionElement>; td: React.DetailedHTMLProps<React.TdHTMLAttributes<HTMLTableCellElement>, HTMLTableCellElement>; template: React.DetailedHTMLProps<React.HTMLAttributes<HTMLTemplateElement>, HTMLTemplateElement>; textarea: React.DetailedHTMLProps<React.TextareaHTMLAttributes<HTMLTextAreaElement>, HTMLTextAreaElement>; tfoot: React.DetailedHTMLProps<React.HTMLAttributes<HTMLTableSectionElement>, HTMLTableSectionElement>; th: React.DetailedHTMLProps<React.ThHTMLAttributes<HTMLTableCellElement>, HTMLTableCellElement>; thead: React.DetailedHTMLProps<React.HTMLAttributes<HTMLTableSectionElement>, HTMLTableSectionElement>; time: Base; tr: React.DetailedHTMLProps<React.HTMLAttributes<HTMLTableRowElement>, HTMLTableRowElement>; track: React.DetailedHTMLProps<React.TrackHTMLAttributes<HTMLTrackElement>, HTMLTrackElement>; u: Base; ul: React.DetailedHTMLProps<React.HTMLAttributes<HTMLUListElement>, HTMLUListElement>; var: Base; video: React.DetailedHTMLProps<React.VideoHTMLAttributes<HTMLVideoElement>, HTMLVideoElement>; wbr: Base; } //#endregion //#region src/html/htmlTags.d.ts declare const HTML_TAGS: readonly ["a", "abbr", "address", "area", "article", "aside", "audio", "b", "bdi", "bdo", "big", "blockquote", "body", "br", "button", "canvas", "caption", "cite", "code", "col", "colgroup", "data", "datalist", "dd", "del", "details", "dfn", "dialog", "div", "dl", "dt", "em", "embed", "fieldset", "figcaption", "figure", "footer", "form", "h1", "h2", "h3", "h4", "h5", "h6", "header", "hr", "html", "i", "iframe", "img", "input", "ins", "kbd", "label", "legend", "li", "main", "map", "mark", "meter", "nav", "object", "ol", "optgroup", "option", "output", "p", "picture", "pre", "progress", "q", "rp", "rt", "ruby", "s", "samp", "section", "select", "small", "source", "span", "strong", "sub", "summary", "sup", "svg", "table", "tbody", "td", "template", "textarea", "tfoot", "th", "thead", "time", "tr", "track", "u", "ul", "var", "video", "wbr"]; declare const HTML_TEXT_TAGS: readonly ["abbr", "b", "bdi", "bdo", "big", "blockquote", "cite", "code", "del", "div", "dl", "dt", "em", "figcaption", "h1", "h2", "h3", "h4", "h5", "h6", "i", "ins", "kbd", "label", "legend", "li", "p", "pre", "q", "rp", "rt", "s", "small", "span", "strong", "sub", "summary", "sup", "time", "u"]; type HTMLTags = (typeof HTML_TAGS)[number]; type HTMLTextTags = (typeof HTML_TEXT_TAGS)[number]; //#endregion //#region src/html/index.d.ts type HTMLTagAttrsByTag<T extends HTMLTags> = T extends HTMLTags ? HTMLElementAttrs[T] : {}; //#endregion //#region src/config.d.ts /** * Augmentable interface representing the result of the engine's `css` * tagged template. Empty by default — each connector package narrows it * via module declaration merging: * * ```ts * // @vitus-labs/connector-styler * declare module '@vitus-labs/core' { * interface CSSEngineResult extends StylerCSSResult {} * } * ``` * * Consumers' types automatically resolve to the engine they `init()`'d with, * without core depending on any specific engine package. */ interface CSSEngineResult {} /** * Describes the shape of a CSS-in-JS engine connector. * Packages like `@vitus-labs/connector-styler`, `@vitus-labs/connector-emotion`, * and `@vitus-labs/connector-styled-components` export this shape. * * Required properties (`css`, `styled`, `provider`) are consumed by config * across all packages. Optional properties (`keyframes`, `createGlobalStyle`, * `useTheme`) are exposed for direct use in application code. */ interface CSSEngineConnector { /** Tagged template for composable CSS fragments. */ css: (strings: TemplateStringsArray, ...values: any[]) => CSSEngineResult; /** Component factory: `styled(tag)`\`...\`` → React component. */ styled: ((tag: any, options?: any) => (strings: TemplateStringsArray, ...values: any[]) => any) & Record<string, any>; /** ThemeProvider component wrapping children with a theme context. */ provider: FC<{ theme: any; children: ReactNode; }>; /** Tagged template for @keyframes animations. */ keyframes?: (strings: TemplateStringsArray, ...values: any[]) => any; /** Factory for injecting global CSS. */ createGlobalStyle?: (strings: TemplateStringsArray, ...values: any[]) => any; /** Hook to read the current theme from the engine's context. */ useTheme?: () => any; } interface PlatformConfig { component: ComponentType | HTMLTags; textComponent: ComponentType | HTMLTags; createMediaQueries?: (props: { breakpoints: Record<string, number>; rootSize: number; css: CSSEngineConnector['css']; }) => Record<string, (...args: any[]) => any>; } type InitConfig = Partial<CSSEngineConnector & PlatformConfig>; /** * Singleton configuration that bridges the UI system with the chosen * CSS-in-JS engine. All packages reference `config.css`, `config.styled`, * etc. — the engine is swapped via `init()` with a connector. * * The `css` and `styled` properties are **stable delegate functions** that * can be safely destructured at module level (`const { styled, css } = config`). * They internally read the latest engine reference set by `init()`. * * When destructured before `init()` is called: * - `css` returns a thunk (function) that resolves at render time * - `styled` returns a lazy component that creates the real component on first render */ declare class Configuration { _css: CSSEngineConnector['css'] | null; _styled: CSSEngineConnector['styled'] | null; _provider: CSSEngineConnector['provider'] | null; _keyframes: CSSEngineConnector['keyframes'] | null; _createGlobalStyle: CSSEngineConnector['createGlobalStyle'] | null; _useTheme: CSSEngineConnector['useTheme'] | null; component: ComponentType | HTMLTags; textComponent: ComponentType | HTMLTags; createMediaQueries: PlatformConfig['createMediaQueries']; /** * Stable CSS delegate. When the engine is available, delegates immediately. * When not (module load time before init), returns a thunk that resolves * at render time — all CSS-in-JS engines treat functions as interpolations. */ css: (strings: TemplateStringsArray, ...values: any[]) => CSSEngineResult; /** * Stable styled delegate (Proxy). Supports `styled(tag)` and `styled.div`. * When the engine is not yet available, returns a lazy component * that creates the real styled component on first render. */ styled: CSSEngineConnector['styled']; /** The external ThemeProvider from the configured engine. */ get ExternalProvider(): CSSEngineConnector['provider'] | null; /** Keyframes factory from the configured engine, or null. */ get keyframes(): CSSEngineConnector['keyframes'] | null; /** Global style factory from the configured engine, or null. */ get createGlobalStyle(): CSSEngineConnector['createGlobalStyle'] | null; /** Theme hook from the configured engine, or null. */ get useTheme(): CSSEngineConnector['useTheme'] | null; constructor(); /** * Initialize or swap the CSS-in-JS engine. Must be called before any * component renders (typically at the app entry point). * * @example * ```typescript * import { init } from '@vitus-labs/core' * import * as connector from '@vitus-labs/connector-styler' * init(connector) * ``` */ init: (props: InitConfig) => void; } declare const config: Configuration; declare const init: (props: InitConfig) => void; //#endregion //#region src/types.d.ts interface Breakpoints { [key: string]: number; } type BreakpointKeys = keyof Breakpoints; //#endregion //#region src/context.d.ts /** * Internal React context shared across all @vitus-labs packages. * Carries the theme object plus any extra provider props. */ declare const context: import("react").Context<any>; type Theme = Partial<{ rootSize: number; breakpoints: Breakpoints; } & Record<string, any>>; type ProviderType = Partial<{ theme: Theme; children: ReactNode; } & Record<string, any>>; /** * Dual-layer provider that feeds both the internal VitusLabs context * and an optional external styling provider (e.g. styled-components' * ThemeProvider). When no theme is supplied, renders children directly. */ declare const Provider: FC<ProviderType>; //#endregion //#region src/hoistNonReactStatics.d.ts declare const hoistNonReactStatics: <T, S>(target: T, source: S, excludeList?: Record<string, true>) => T; //#endregion //#region src/isEmpty.d.ts /** * Type-safe emptiness check for objects, arrays, null, and undefined. * Returns `true` for null, undefined, empty objects `{}`, and empty arrays `[]`. * Non-object primitives (string, number) also return `true` as any. */ type IsEmpty = <T extends Record<number | string, any> | any[] | null | undefined>(param: T) => T extends null | undefined ? true : keyof T extends never ? true : T extends T[] ? T[number] extends never ? true : false : false; declare const isEmpty: IsEmpty; //#endregion //#region src/isEqual.d.ts /** * Order-independent deep equality for plain objects, arrays, and primitives. * Handles null, undefined, nested structures, and circular references via * cycle detection. Does not handle Date, RegExp, Map, Set — not needed for * theme/props comparison. */ declare const isEqual: (a: unknown, b: unknown) => boolean; //#endregion //#region src/render.d.ts type CreateTypes = Parameters<typeof createElement>[0]; type CloneTypes = Parameters<typeof cloneElement>[0]; type RenderProps<T extends Record<string, unknown> | undefined> = (props: Partial<T>) => ReactNode; /** * Flexible element renderer that handles multiple content types: * - Primitives (string, number) — returned as-is * - Arrays and fragments — returned as-is * - Component types (class/function) — created via `createElement` * - Valid elements — cloned with `attachProps` if provided * - Falsy values — return null */ type Render = <T extends Record<string, any> | undefined>(content?: CreateTypes | CloneTypes | ReactNode | ReactNode[] | RenderProps<T>, attachProps?: T) => ReturnType<typeof createElement> | ReturnType<typeof cloneElement> | null; declare const render: Render; //#endregion //#region src/useStableValue.d.ts /** * Returns a referentially stable version of `value`. The returned reference * only changes when the value is no longer deeply equal to the previous one. * * Use this to stabilize object/array props before passing them as hook * dependencies, preventing unnecessary recalculations in useMemo/useEffect. * * Based on the useDeepCompareMemoize pattern from use-deep-compare. */ declare const useStableValue: <T>(value: T) => T; //#endregion //#region src/utils.d.ts declare const omit: <T extends Record<string, any>>(obj: T | null | undefined, keys?: readonly (string | keyof T)[] | ReadonlySet<string | keyof T>) => Partial<T>; declare const pick: <T extends Record<string, any>>(obj: T | null | undefined, keys?: readonly (string | keyof T)[]) => Partial<T>; declare const get: (obj: any, path: string | string[], defaultValue?: any) => any; declare const set: (obj: Record<string, any>, path: string | string[], value: any) => Record<string, any>; declare const throttle: <T extends (...args: any[]) => any>(fn: T, wait?: number, options?: { leading?: boolean; trailing?: boolean; }) => T & { cancel: () => void; }; declare const merge: <T extends Record<string, any>>(target: T, ...sources: Record<string, any>[]) => T; //#endregion export { type BreakpointKeys, type Breakpoints, type CSSEngineConnector, type CSSEngineResult, type HTMLElementAttrs, type HTMLTagAttrsByTag, type HTMLTags, type HTMLTextTags, HTML_TAGS, HTML_TEXT_TAGS, type IsEmpty, Provider, type Render, compose, config, context, get, hoistNonReactStatics, init, isEmpty, isEqual, merge, omit, pick, render, set, throttle, useStableValue }; //# sourceMappingURL=index2.d.ts.map