import { observer } from "mobx-react-lite"; import React from "react"; import { Category, Checkbox, ColourSwatches, Column, ComboBox, InputBox, Radio, TextArea, } from "../../design"; // inputs: // - checkbox (bool) // - colour swatches (string) // - combobox (string) // - inputbox (string) // - override (tri-state) [to implement] // - radio (string) // - textarea (string) [to implement] /** * Available input types */ export type Type = | "text" | "checkbox" | "colour" | "combo" | "radio" | "textarea" | "custom"; /** * Get default value */ export function emptyValue(type: Type) { return type === "custom" ? undefined : type === "checkbox" ? false : ""; } /** * Component props */ type Props = { type: T; value: Value | (() => Value); onChange: (v: Value) => void; disabled?: boolean; } & TypeProps; /** * Multi or single-select choice entry */ type Choice = { value: string; name: React.ReactChild; }; /** * Metadata for different input types */ type Metadata = { text: { value: string; props: React.ComponentProps }; checkbox: { value: boolean; props: React.ComponentProps }; colour: { value: string; props: React.ComponentProps; }; combo: { value: string; props: Omit, "children"> & { options: Choice[]; }; }; radio: { value: string; props: { choices: (Choice & Omit, "title" | "value">)[]; }; }; textarea: { value: string; props: React.ComponentProps }; custom: { value: never; props: { element: JSX.Element } }; }; /** * Actual input value type */ export type Value = Metadata[T]["value"]; /** * Additional component props for given input type */ export type TypeProps = Omit< Metadata[T]["props"], "value" | "onChange" > & { field?: React.ReactChild; }; /** * Generic input element */ export function InputElement({ type, value, onChange, ...props }: Props) { const v = typeof value === "function" ? value() : value; let el = null; switch (type) { case "text": { el = ( onChange(ev.currentTarget.value as Value) } {...props} /> ); break; } case "checkbox": { el = ( onChange(value as Value)} {...props} /> ); break; } case "colour": { el = ( onChange(value as Value)} {...props} /> ); break; } case "combo": { const { options, ...comboProps } = props as unknown as TypeProps<"combo">; el = ( onChange(ev.currentTarget.value as Value) } {...comboProps}> {options.map((option: Choice) => ( ))} ); break; } case "radio": { const { choices } = props as unknown as TypeProps<"radio">; el = ( {choices.map(({ name, value: choiceValue, ...props }) => ( onChange(choiceValue)} {...props} /> ))} ); break; } case "custom": { el = (props as unknown as TypeProps<"custom">).element; break; } } if (props.field) { return (
{props.field} {el}
); } return el; } /** * Generic input element wrapped in MobX observer */ export const ObservedInputElement = observer(InputElement);