@types/react-blessed
Version:
TypeScript definitions for react-blessed
291 lines (247 loc) • 12.4 kB
TypeScript
import * as Blessed from "blessed";
import * as React from "react";
export {};
/* RENDERER *****************************************************************/
// eslint-disable-next-line @typescript-eslint/no-invalid-void-type
export type Callback = () => void | null | undefined;
export type renderer = (c: React.JSX.Element, s: Blessed.Widgets.Screen, callback?: Callback) => React.Component | null;
export function render(c: React.JSX.Element, s: Blessed.Widgets.Screen, callback?: Callback): React.Component | null;
export function createBlessedRenderer(bls: any): renderer;
/* BLESSED ELEMENTS **********************************************************/
export type Element = Blessed.Widgets.BlessedElement;
export type ScrollableBoxElement = Blessed.Widgets.ScrollableBoxElement;
export type ScrollableTextElement = Blessed.Widgets.ScrollableTextElement;
export type BoxElement = Blessed.Widgets.BoxElement;
export type TextElement = Blessed.Widgets.TextElement;
export type LineElement = Blessed.Widgets.LineElement;
export type BigTextElement = Blessed.Widgets.BigTextElement;
export type ListElement = Blessed.Widgets.ListElement;
export type FileManagerElement = Blessed.Widgets.FileManagerElement;
export type ListTableElement = Blessed.Widgets.ListTableElement;
export type ListbarElement = Blessed.Widgets.ListbarElement;
export type InputElement = Blessed.Widgets.InputElement;
export type TextareaElement = Blessed.Widgets.TextareaElement;
export type TextboxElement = Blessed.Widgets.TextboxElement;
export type ButtonElement = Blessed.Widgets.ButtonElement;
export type CheckboxElement = Blessed.Widgets.CheckboxElement;
export type RadioSetElement = Blessed.Widgets.RadioSetElement;
export type RadioButtonElement = Blessed.Widgets.RadioButtonElement;
export type TableElement = Blessed.Widgets.TableElement;
export type PromptElement = Blessed.Widgets.PromptElement;
export type QuestionElement = Blessed.Widgets.QuestionElement;
export type MessageElement = Blessed.Widgets.MessageElement;
export type LoadingElement = Blessed.Widgets.LoadingElement;
export type LogElement = Blessed.Widgets.Log;
export type ProgressBarElement = Blessed.Widgets.ProgressBarElement;
export type TerminalElement = Blessed.Widgets.TerminalElement;
export type LayoutElement = Blessed.Widgets.LayoutElement;
/* EVENTS *******************************************************************/
type Prefix<T extends string, P extends string> = `${T}${P}`;
// create event handlers that map to 'blessed' events. see
// https://github.com/Yomguithereal/react-blessed/blob/f5e1f791dea1788745695d557040b91f573f9ef5/src/fiber/events.js
type EventHandlerProp<T extends string, E extends (...args: never) => void> = {
[key in `on${Capitalize<T>}`]?: E;
};
// 'react-blessed' handles 'blessed' events by matching event names to
// handlers by prefixing event names with with "on" and camelCasing the
// result. this cannot be fully recreated in TS so we must manually map them
// here.
type ScreenElement = "click" | "mouseover" | "mouseout" | "mouseup";
type ScreenElementPrefix = "element";
type ExludedScreenEventNames = Prefix<ScreenElementPrefix, Prefix<" ", ScreenElement>>;
type CamelCasedScreenEventNames = Prefix<ScreenElementPrefix, Capitalize<ScreenElement>>;
type ScreenEventNames =
| Exclude<Blessed.Widgets.NodeScreenEventType, ExludedScreenEventNames>
| CamelCasedScreenEventNames;
type GenericContentPrefix = "set" | "parsed";
type GenericContent = "content";
type ExludedGenericEventNames = Prefix<GenericContentPrefix, Prefix<" ", GenericContent>>;
type CamelCasedGenericEventNames = Prefix<GenericContentPrefix, Capitalize<GenericContent>>;
type GenericEventNames =
| Exclude<Blessed.Widgets.NodeGenericEventType, ExludedGenericEventNames>
| CamelCasedGenericEventNames;
type ProgressBarEventNames = Parameters<Blessed.Widgets.ProgressBarElement["on"]>[0];
type SpreadableArgs<T, K = T extends unknown[] ? T : [T]> = K;
interface EventHandler<T> {
(...args: SpreadableArgs<T>): void;
}
// event args need to be manually typed because Blessed.Widgets.NodeWithEvents
// overloads the event handlers (making it impossible? to extract the
// parameters with TS utils) and does not expose the event callbacks as
// importable types
export type ScreenEvent = Blessed.Widgets.Screen;
export type ScreenEventHandler = EventHandler<ScreenEvent>;
type ScreenEventProps = EventHandlerProp<ScreenEventNames, ScreenEventHandler>;
export type MouseEvent = Blessed.Widgets.Events.IMouseEventArg;
export type MouseEventHandler = EventHandler<MouseEvent>;
type MouseEventProps = EventHandlerProp<Blessed.Widgets.NodeMouseEventType, MouseEventHandler>;
export type GenericEvent = undefined;
export type GenericEventHandler = EventHandler<GenericEvent>;
type GenericEventProps = EventHandlerProp<GenericEventNames, GenericEventHandler>;
export type KeyPressEvent = [key: any, event: Blessed.Widgets.Events.IKeyEventArg];
export type KeyPressEventHandler = EventHandler<KeyPressEvent>;
type KeyPressEventProps = EventHandlerProp<"keypress", KeyPressEventHandler>;
export type WarningEvent = string;
export type WarningEventHandler = EventHandler<WarningEvent>;
type WarningEventProps = EventHandlerProp<"warning", WarningEventHandler>;
export type ProgressBarEvent = undefined;
export type ProgressBarEventHandler = EventHandler<ProgressBarEvent>;
type ProgressBarEventProps = EventHandlerProp<ProgressBarEventNames, ProgressBarEventHandler>;
interface EventProps
extends ScreenEventProps, GenericEventProps, MouseEventProps, KeyPressEventProps, WarningEventProps
{}
/* BLESSED-REACT LOCALLY DEFINED PROPS **************************************/
// @types/blessed defines 'styles' as 'any' but 'blessed' can only can only
// take certain values. define them here.
interface BorderStyle {
type?: "line" | "bg";
ch?: string;
bg?: string;
fg?: string;
bold?: boolean;
underline?: boolean;
}
interface ItemStyle {
bg?: string;
fg?: string;
bold?: boolean;
underline?: boolean;
blink?: boolean;
inverse?: boolean;
invisible?: boolean;
}
interface ListStyle extends ElementStyle {
selected?: ItemStyle;
item?: ItemStyle;
}
interface ProgressBarStyle extends ElementStyle {
bar?: { bg?: string; fg?: string };
}
interface ElementStyle extends ItemStyle {
border?: BorderStyle;
focus?: { bg?: string; fg?: string };
hover?: { bg?: string; fg?: string };
transparent?: boolean;
scrollbar?: { bg?: string; fg?: string; track?: { bg?: string; fg?: string } };
}
// remove indexers
// https://stackoverflow.com/questions/51465182/how-to-remove-index-signature-using-mapped-types
type KnownKeys<T> = {
[K in keyof T as string extends K ? never : number extends K ? never : K]: T[K];
};
type WithClassProp<T, K = T | undefined | false | null> = T & { class?: K | K[] };
type ProgressBarProps<T> = T extends ProgressBarElement ? ProgressBarEventProps & { style?: ProgressBarStyle } : {};
type ListProps<T> = T extends ListElement ? ProgressBarEventProps & { style?: ListStyle; selected?: number } : {};
// layout does not require prop 'layout' in Blessed.Widgets.LayoutOptions--make it optional
type LayoutProps<T> = T extends LayoutElement ? Partial<Blessed.Widgets.LayoutOptions> : {};
// remove {[key: string]: any} indexer defined in Blessed.Widgets.IOptions.
// 'blessed' doesn't exist in a DOM so it probably doesn't make sense to allow any property
type FilterOptions<T extends Record<any, any>> = Partial<Omit<KnownKeys<T>, "style" | "children">>;
type ModifiedBlessedOptions<T extends Record<any, any>> = FilterOptions<T> & {
children?: React.ReactNode;
style?: ElementStyle;
} & EventProps;
/* REACT-BLESSED JSX ********************************************************/
/**
* this type can be used to get props for 'react-blessed' elements in the same
* manner that React.HTMLProps can be used to get DOM element props. e.g.
* ```ts
* import { FC } from 'react'
* import { BlessedProps, BoxElement } from 'react-blessed';
* type MyBoxProps = BlessedProps<BoxElement>;
* const MyBox: React.FC<MyBoxProps> = props => <box {...props} />;
* ```
* @see DetailedBlessedProps
* @see React.HTMLAttributes
*/
export type BlessedAttributes<E extends Element> = WithClassProp<
ModifiedBlessedOptions<E["options"]> & ProgressBarProps<E> & ListProps<E> & LayoutProps<E>
>;
/**
* mirrors react prop generation for HTML JSX.IntrinsicElements.
* @see React.DetailedHTMLProps
*/
export type DetailedBlessedProps<E extends Element> = BlessedAttributes<E> & React.ClassAttributes<E>;
export interface BlessedIntrinsicElements {
element: DetailedBlessedProps<Element>;
box: DetailedBlessedProps<BoxElement>;
scrollablebox: DetailedBlessedProps<ScrollableBoxElement>;
scrollabletext: DetailedBlessedProps<ScrollableTextElement>;
bigtext: DetailedBlessedProps<BigTextElement>;
list: DetailedBlessedProps<ListElement>;
filemanager: DetailedBlessedProps<FileManagerElement>;
listtable: DetailedBlessedProps<ListTableElement>;
listbar: DetailedBlessedProps<ListbarElement>;
textbox: DetailedBlessedProps<TextboxElement>;
checkbox: DetailedBlessedProps<CheckboxElement>;
radioset: DetailedBlessedProps<RadioSetElement>;
radiobutton: DetailedBlessedProps<RadioButtonElement>;
prompt: DetailedBlessedProps<PromptElement>;
question: DetailedBlessedProps<QuestionElement>;
message: DetailedBlessedProps<MessageElement>;
loading: DetailedBlessedProps<LoadingElement>;
log: DetailedBlessedProps<LogElement>;
progressbar: DetailedBlessedProps<ProgressBarElement>;
terminal: DetailedBlessedProps<Blessed.Widgets.TerminalElement>;
layout: DetailedBlessedProps<Blessed.Widgets.LayoutElement>;
// escape: Blessed.escape is not an element
// program: Blessed.Widgets.Program is not an element
}
// 'react-blessed' accepts JSX with 'blessed' element names with and without
// a 'blessed-' prefix. see
// https://github.com/Yomguithereal/react-blessed/blob/f5e1f791dea1788745695d557040b91f573f9ef5/src/fiber/fiber.js#L49
export type BlessedIntrinsicElementsPrefixed = {
[Key in keyof BlessedIntrinsicElements as Prefix<"blessed-", Key>]: BlessedIntrinsicElements[Key];
};
// it isn't possible to use the global JSX namespace because some 'blessed'
// elements will collide with ones set in react defs.
// augment react JSX when old JSX transform is used
declare module "react" {
namespace JSX {
interface ButtonHTMLAttributes<T> extends
HTMLAttributes<T>,
Omit<
DetailedBlessedProps<ButtonElement>,
"draggable" | "onBlur" | "onClick" | "onFocus" | "onResize" | "ref" | "style"
>
{}
interface TableHTMLAttributes<T> extends
HTMLAttributes<T>,
Omit<
DetailedBlessedProps<TableElement>,
"border" | "draggable" | "onBlur" | "onClick" | "onFocus" | "onResize" | "ref" | "style"
>
{}
interface TextareaHTMLAttributes<T> extends
HTMLAttributes<T>,
Omit<
DetailedBlessedProps<TextElement>,
"draggable" | "fill" | "focusable" | "onBlur" | "onClick" | "onFocus" | "onResize" | "ref" | "style"
>
{}
interface InputHTMLAttributes<T> extends
HTMLAttributes<T>,
Omit<
DetailedBlessedProps<InputElement>,
"draggable" | "onBlur" | "onClick" | "onFocus" | "onResize" | "ref" | "style"
>
{}
interface SVGLineElementAttributes<T> extends
SVGProps<T>,
Omit<
DetailedBlessedProps<LineElement>,
"focusable" | "onBlur" | "onClick" | "onFocus" | "onResize" | "orientation" | "ref" | "style"
>
{}
interface SVGTextElementAttributes<T> extends
SVGProps<T>,
Omit<
DetailedBlessedProps<TextElement>,
"fill" | "focusable" | "onBlur" | "onClick" | "onFocus" | "onResize" | "ref" | "style"
>
{}
// set IntrinsicElements to 'react-blessed' elements both with and without
// 'blessed-' prefix
interface IntrinsicElements extends BlessedIntrinsicElementsPrefixed, BlessedIntrinsicElements {}
}
}