import { isArray, isBoolean, isNull, isNumber, isString } from "lodash"; import React, { FunctionComponent, useEffect } from "react"; import { Button as BSButton, ButtonProps as BSButtonProps, Form, } from "react-bootstrap"; import { useCollapse, useLatest } from "."; import { Chips as CChips, ChipsProps as CChipsProps, Selector as CSelector, SelectorProps as CSelectorProps, Slider as CSlider, SliderProps as CSliderProps, } from "../../components"; import { isReactText } from "../../utilities"; import { OverrideFuncType, useSingleUpdate } from "./hooks"; export const Message: FunctionComponent<{ type?: "warning" | "info"; }> = ({ type, children }) => { const cls = ["pr-4"]; cls.push(type === "warning" ? "text-warning" : "text-muted"); return {children}; }; export interface BaseInput { disabled?: boolean; settingKey: string; override?: OverrideFuncType; beforeStaged?: (v: T) => any; } export interface TextProps extends BaseInput { placeholder?: React.ReactText; password?: boolean; controlled?: boolean; } export const Text: FunctionComponent = ({ placeholder, disabled, beforeStaged, controlled, override, password, settingKey, }) => { const value = useLatest(settingKey, isReactText, override); const update = useSingleUpdate(); const collapse = useCollapse(); return ( { const val = e.currentTarget.value; collapse(val.toString()); const value = beforeStaged ? beforeStaged(val) : val; update(value, settingKey); }} > ); }; export interface CheckProps extends BaseInput { label?: string; inline?: boolean; } export const Check: FunctionComponent = ({ label, inline, override, disabled, settingKey, }) => { const update = useSingleUpdate(); const collapse = useCollapse(); const value = useLatest(settingKey, isBoolean, override); useEffect(() => collapse(value ?? false), [collapse, value]); return ( { const { checked } = e.currentTarget; update(checked, settingKey); }} disabled={disabled} checked={value ?? undefined} > ); }; function selectorValidator(v: any): v is T { return isString(v) || isNumber(v) || isArray(v); } type SelectorProps = BaseInput> & CSelectorProps; export function Selector< T extends string | string[] | number | number[], M extends boolean = false >(props: SelectorProps) { const update = useSingleUpdate(); const collapse = useCollapse(); const { settingKey, override, beforeStaged, ...selector } = props; const value = useLatest>( settingKey, selectorValidator, override ); useEffect(() => { if (isString(value) || isNull(value)) { collapse(value ?? ""); } }); return ( { v = beforeStaged ? beforeStaged(v) : v; update(v, settingKey); }} > ); } type SliderProps = {} & BaseInput & Omit; export const Slider: FunctionComponent = (props) => { const { settingKey, override, ...slider } = props; const update = useSingleUpdate(); const defaultValue = useLatest(settingKey, isNumber, override); return ( { update(v, settingKey); }} defaultValue={defaultValue ?? undefined} {...slider} > ); }; type ChipsProp = {} & BaseInput & Omit; export const Chips: FunctionComponent = (props) => { const { settingKey, override, ...chips } = props; const update = useSingleUpdate(); const value = useLatest(settingKey, isArray, override); return ( { update(v, settingKey); }} {...chips} > ); }; type ButtonProps = { onClick?: ( update: (v: any, key: string) => void, key: string, value?: string ) => void; } & Omit, "override" | "beforeStaged">; export const Button: FunctionComponent> = ( props ) => { const { onClick, settingKey, ...button } = props; const value = useLatest(settingKey, isString); const update = useSingleUpdate(); return ( { onClick && onClick(update, settingKey, value ?? undefined); }} {...button} > ); };