UNPKG

tweak-tools

Version:

Tweak your React projects until awesomeness

318 lines (317 loc) 11.1 kB
/// <reference types="react" /> /** * Types exposed through the public API */ import type { VectorSettings } from '../components/Vector/vector-types'; import { StoreType, Data, DataInput } from './internal'; import type { BeautifyUnionType, UnionToIntersection } from './utils'; export declare type RenderFn = (get: (key: string) => any) => boolean; /** * Utility types that joins a value with its settings */ export declare type InputWithSettings<V extends unknown, Settings = {}, K extends string = 'value'> = { [key in K]: V; } & { type?: TweakInputs; } & Settings; /** * Either the raw value, either the value with its settings * In other words => value || { value, ...settings } */ export declare type MergedInputWithSettings<V, Settings = {}, K extends string = 'value'> = V | InputWithSettings<V, Settings, K>; /** * Special Inputs */ export declare enum SpecialInputs { BUTTON = "BUTTON", BUTTON_GROUP = "BUTTON_GROUP", MONITOR = "MONITOR", FOLDER = "FOLDER" } export declare enum TweakInputs { SELECT = "SELECT", IMAGE = "IMAGE", NUMBER = "NUMBER", COLOR = "COLOR", STRING = "STRING", BOOLEAN = "BOOLEAN", INTERVAL = "INTERVAL", VECTOR3D = "VECTOR3D", VECTOR2D = "VECTOR2D" } export declare type ButtonSettings = { disabled?: boolean; }; export declare type ButtonInput = { type: SpecialInputs.BUTTON; onClick: (get: (path: string) => any) => void; settings: ButtonSettings; }; export declare type ButtonGroupOpts = { [title: string]: (get: (path: string) => any) => void; }; export declare type ButtonGroupInputOpts = ButtonGroupOpts | { label?: string | JSX.Element | null; opts: ButtonGroupOpts; }; export declare type ButtonGroupInput = { type: SpecialInputs.BUTTON_GROUP; opts: ButtonGroupInputOpts; }; export declare type MonitorSettings = { graph?: boolean; interval?: number; }; export declare type MonitorInput = { type: SpecialInputs.MONITOR; objectOrFn: React.MutableRefObject<any> | Function; settings: MonitorSettings; }; export declare type SpecialInput = MonitorInput | ButtonInput | ButtonGroupInput; export declare type FolderSettings = { collapsed?: boolean; render?: RenderFn; color?: string; /** works similar to css order property */ order?: number; }; export declare type NumberSettings = { min?: number; max?: number; step?: number; }; export declare type VectorObj = Record<string, number>; export declare type Vector2dArray = [number, number]; export declare type Vector2d = Vector2dArray | VectorObj; export declare type Vector2dSettings = VectorSettings<Vector2d, 'x' | 'y'> & { joystick?: boolean | 'invertY'; lock?: boolean; }; export declare type Vector2dInput = MergedInputWithSettings<Vector2d, Vector2dSettings>; export declare type Vector3dArray = [number, number, number]; export declare type Vector3d = Vector3dArray | VectorObj; export declare type Vector3dSettings = VectorSettings<Vector3d, 'x' | 'y' | 'z'> & { lock?: boolean; }; export declare type Vector3dInput = MergedInputWithSettings<Vector3d, Vector3dSettings>; export declare type IntervalInput = { value: [number, number]; min: number; max: number; }; export declare type ImageInput = { image: undefined | string; }; declare type SelectInput = { options: any[] | Record<string, any>; value?: any; }; declare type SelectWithValueInput<T, K> = { options: T[] | Record<string, T>; value: K; }; declare type SelectWithoutValueInput<T> = { options: T[] | Record<string, T>; }; declare type ColorRgbaInput = { r: number; g: number; b: number; a?: number; }; declare type ColorHslaInput = { h: number; s: number; l: number; a?: number; }; declare type ColorHsvaInput = { h: number; s: number; v: number; a?: number; }; export declare type ColorVectorInput = ColorRgbaInput | ColorHslaInput | ColorHsvaInput; declare type BooleanInput = boolean; declare type StringSettings = { rows?: boolean | number; editable?: boolean; }; declare type StringInput = InputWithSettings<string, StringSettings>; export declare type FolderInput<Schema> = { type: SpecialInputs.FOLDER; schema: Schema; settings: FolderSettings; }; export declare type CustomInput<Value> = { type: string; __customInput: Value; }; declare type SchemaItem = InputWithSettings<number, NumberSettings> | InputWithSettings<boolean> | InputWithSettings<string> | IntervalInput | ColorVectorInput | Vector2dInput | Vector3dInput | ImageInput | SelectInput | BooleanInput | StringInput | CustomInput<unknown>; declare type GenericSchemaItemOptions = { render?: RenderFn; label?: string | JSX.Element; hint?: string; order?: number; }; declare type OnHandlerContext = DataInput & { get(path: string): any; }; declare type OnChangeHandlerContext = OnHandlerContext & { /** * Whether the onChange handler is invoked initially. */ initial: boolean; }; export declare type OnChangeHandler = (value: any, path: string, context: OnChangeHandlerContext) => void; declare type TransientOnChangeSchemaItemOptions = { onChange: OnChangeHandler; transient?: true; }; declare type NonTransientOnChangeSchemaItemOptions = { onChange: OnChangeHandler; transient: false; }; declare type NoOnChangeSchemaItemOptions = { onChange?: undefined; transient?: undefined; }; declare type OnChangeSchemaItemOptions = TransientOnChangeSchemaItemOptions | NonTransientOnChangeSchemaItemOptions | NoOnChangeSchemaItemOptions; export declare type InputOptions = GenericSchemaItemOptions & OnChangeSchemaItemOptions & { optional?: boolean; disabled?: boolean; onEditStart?: (value: any, path: string, context: OnHandlerContext) => void; onEditEnd?: (value: any, path: string, context: OnHandlerContext) => void; }; declare type SchemaItemWithOptions = number | boolean | string | (SchemaItem & InputOptions) | (SpecialInput & GenericSchemaItemOptions) | FolderInput<unknown>; export declare type Schema = Record<string, SchemaItemWithOptions>; /** * Dummy type used internally to flag non compatible input types. * @internal */ declare type NotAPrimitiveType = { ____: 'NotAPrimitiveType'; }; declare type PrimitiveToValue<P> = P extends CustomInput<infer CustomValue> ? BeautifyUnionType<CustomValue> : P extends ImageInput ? string | undefined : P extends SelectWithValueInput<infer SelectValue, infer Options> ? SelectValue | Options : P extends SelectWithoutValueInput<infer Options> ? Options : P extends IntervalInput ? [number, number] : P extends { value: infer Value; } ? PrimitiveToValue<Value> : P extends VectorObj ? P : P extends Vector3dArray ? [number, number, number] : P extends Vector2dArray ? [number, number] : P extends number ? number : P extends string ? string : P extends boolean ? boolean : NotAPrimitiveType; export declare type SchemaToValues<Schema, IncludeTransient extends boolean = false> = BeautifyUnionType<UnionToIntersection<Tree<IncludeTransient, Schema>>>; declare type EndLeaf = { ___leaf: 'leaf'; }; declare type Join<Leaf1, Leaf1Key extends keyof Leaf1, Leaf2> = EndLeaf extends Leaf2 ? { [i in Leaf1Key]: Leaf1[Leaf1Key]; } : Leaf2; declare type Tree<IncludeTransient extends boolean, Leaf, LeafKey extends string | number | symbol = ''> = { 0: Leaf extends { schema: infer Schema; } ? { [Key in keyof Schema]: Join<Schema, Key, Schema[Key]>; } : never; 1: never; 2: { [Key in LeafKey]: Leaf extends { optional: true; } | { disabled: true; } ? PrimitiveToValue<Leaf> | undefined : PrimitiveToValue<Leaf>; }; 3: { [Key in keyof Leaf]: Join<Leaf, Key, Tree<IncludeTransient, Leaf[Key], Key>>; }[keyof Leaf]; 4: EndLeaf; }[LeafKey extends '' ? 3 : Leaf extends FolderInput<unknown> ? 0 : Leaf extends SpecialInput ? 1 : PrimitiveToValue<Leaf> extends NotAPrimitiveType ? Leaf extends object ? 3 : 4 : Leaf extends TransientOnChangeSchemaItemOptions ? IncludeTransient extends true ? 2 : 1 : 2]; /** * If P is '' then T is the whole schema and we shouldn't run any type check * on the schema, to the risk that { a: 1, b: 2 } is recognized as Vector * instead of a two number inputs. */ /** * Interface to build a plugin. * * @public */ export interface Plugin<Input, Value = Input, InternalSettings = {}> { /** * The component that shows the input value; */ component: React.ComponentType; /** * Normalizes the input into a { value, settings } object. * * @example * Let's consider a color with an inverted settings option that computes the negative * of that color. The plugin could look something like: * ```ts * myColorPlugin({ color: '#fff', inverted: true }) * ``` * * In that case, your normalize funciton would be something like: * ```ts * function normalize({ color, inverted }) { * return { value: color, settings: { inverted }} * } * ``` */ normalize?: (input: Input, path: string, data: Data) => { value: Value; settings?: InternalSettings; }; /** * Sanitizes the user value before registering it to the store. For * example, the Number plugin would santize "3.00" into 3. If the provided * value isn't formatted properly, the sanitize function should throw. */ sanitize?: (value: any, settings: InternalSettings, prevValue: any, path: string, store: StoreType) => Value; /** * Formats the value into the value that will be displayed by the component. * If the input value of the Number plugin, then format will add proper * padding and show "3.00". * (Prop name in useInputContext context hook is `displayedValue`) */ format?: (value: any, settings: InternalSettings) => any; } export declare type InputContextProps = { id: string; label: string | JSX.Element; hint?: string; path: string; key: string; optional: boolean; disabled: boolean; disable: (flag: boolean) => void; storeId: string; value: unknown; displayValue: unknown; onChange: React.Dispatch<any>; emitOnEditStart: () => void; emitOnEditEnd: () => void; onUpdate: (v: any | ((v: any) => any)) => void; settings: unknown; setSettings: (v: any) => void; }; /** * Interface consumed by the useInputContext hook so that its returned values * are properly typed. * * @example * ```ts * useInputContext<TweakInputProps<boolean>>() * ``` * @public */ export interface TweakInputProps<V, InternalSettings = {}, DisplayValue = V> { path?: string; id?: string; hint?: string; disabled?: boolean; displayValue: DisplayValue; value: V; onChange: React.Dispatch<any>; emitOnEditStart: () => void; emitOnEditEnd: () => void; onUpdate: (v: any | ((v: any) => any)) => void; settings: InternalSettings; setSettings: (v: Partial<InternalSettings>) => void; } export {};