import { ChangeEventHandler, Children, ComponentType, FC, FormEventHandler, HTMLAttributes, ReactElement, ReactNode, cloneElement, useCallback, useMemo } from "react"; import { Button, ButtonProps, Checkbox, Classes, Code, ControlGroup, H4, H5, IPopoverProps, Icon, InputGroup, InputGroupProps, Menu, MenuItem, NumericInput, NumericInputProps, Switch, SwitchProps, TextArea, TextAreaProps } from "@blueprintjs/core"; import { IListItemsProps, Select, SelectProps } from "@blueprintjs/select"; import { Placement } from "@blueprintjs/popover2"; import { useBool } from "@hooks"; import { CustomClasses } from "../../constants"; import { AsBoolean } from "Types/helpers"; import "./common.sass"; const popoverProps: Partial = { canEscapeKeyClose: false, minimal: true, placement: "bottom" as Placement, popoverClassName: CustomClasses.POPOVER }; /** Converts a string from camelCase to Title Case * @see https://stackoverflow.com/questions/7225407/convert-camelcasetext-to-title-case-text */ function camelToTitleCase(text: string): string { const result = text.replace(/([A-Z])/g, " $1"); const finalResult = result.charAt(0).toUpperCase() + result.slice(1); return finalResult; } const Row: FC = ({ children }) =>
{children}
; type RowColProps = { description?: ReactNode, rightElement?: ReactNode, title?: ReactNode }; const RowCol: FC = ({ children, description = null, rightElement = null, title = null }) => (
{title && {title}} {description && {description}}
{rightElement}
{children}
); type RowGroupOptions = Record; type RowGroupProps = { description?: ReactNode, onChange: RowGroupOptionProps["handleSelect"], options: RowGroupOptions, selected: string, title?: ReactNode }; const RowGroup: FC = ({ children, description = null, onChange, options, selected, title = null }) => { return
{title && {title}} {description && {description}}
{Children.map(children, (child) => { return cloneElement( child as ReactElement, { handleSelect: onChange, options, selected } ); })}
; }; type RowGroupOptionPublicProps = { alignToBaseline?: boolean, description?: ReactNode, id: keyof RowGroupOptions }; type RowGroupOptionProps = RowGroupOptionPublicProps & { handleSelect: (value: RowGroupOptionPublicProps["id"]) => void, options: RowGroupOptions, selected: keyof RowGroupOptions }; const _RowGroupOption: FC = ({ alignToBaseline = false, children, description = null, handleSelect, id, options, selected }) => { const isSelected = useMemo(() => selected == id, [id, selected]); const onChange = useCallback(() => handleSelect(id), [handleSelect, id]); return
{options[id]} {description && {description}}
} onChange={onChange} /> {children} ; }; const RowGroupOption = _RowGroupOption as ComponentType; const Title: FC = ({ children }) =>

{children}

; const OptionTitle: FC = ({ children }) =>
{children}
; const Description: FC = ({ children }) => {children}; const Definition = ({ item, text = null }: { item: string, text?: string | null }) =>
{item} {text && {text}}
; type NumericSelectProps = { description?: ReactNode, label: string, title?: ReactNode, value: number, setValue: (val: number) => void } & Partial; const NumericSelect = ({ description = null, label, setValue, title = null, value, ...extraProps }: NumericSelectProps) => { const handler = useCallback>((num, _numAsString) => setValue(num), [setValue]); return
{title && {title}} {description && {description}}
; }; type BetterSelectOption = { label: string, value: string | boolean }; type BetterSelectListProps = IListItemsProps; type BetterSelectProps = { buttonProps?: Partial, onSelect: (value: BetterSelectOption["value"]) => void, options: BetterSelectOption[], popoverTargetProps?: HTMLAttributes, value: BetterSelectOption["value"] } & Partial>; const BetterSelect = ({ buttonProps = {}, onSelect, options, popoverTargetProps = {}, value, ...extraProps }: BetterSelectProps) => { const selectHandler = useCallback((item) => onSelect(item.value), [onSelect]); const itemRenderer = useCallback((item, itemProps) => { const { handleClick/*, modifiers: { active }*/ } = itemProps; const isSelected = item.value == value; return : null} onClick={handleClick} aria-selected={isSelected} text={item.label} />; }, [value]); const menuRenderer = useCallback(({ items, itemsParentRef, renderItem }) => { const renderedItems = items.map(renderItem).filter(item => item != null); return ( {renderedItems} ); }, [popoverTargetProps]); const mergedPopoverProps = useMemo(() => ({ ...popoverProps, targetProps: popoverTargetProps }), [popoverTargetProps]); return ; }; type SingleInputProps = { description?: ReactNode, menuTitle: string, title?: ReactNode, } & Omit; const SingleInput = ({ buttonProps = {}, description = null, menuTitle, onSelect, options, title = null, value, ...extraProps }: SingleInputProps) => { const suppProps = useMemo(() => ({ title: menuTitle }), [menuTitle]); return
{title && {title}} {description && {description}}
; }; type TextAreaInputProps = { label?: string, onChange: (value: string) => void, value: string } & Partial>; const TextAreaInput = ({ label = undefined, onChange, value, ...extraProps }: TextAreaInputProps) => { const valueHandler = useCallback>((event) => onChange(event.target.value), [onChange]); return