diff options
Diffstat (limited to 'packages/taler-wallet-webextension/src/mui/input/FormControl.tsx')
-rw-r--r-- | packages/taler-wallet-webextension/src/mui/input/FormControl.tsx | 176 |
1 files changed, 176 insertions, 0 deletions
diff --git a/packages/taler-wallet-webextension/src/mui/input/FormControl.tsx b/packages/taler-wallet-webextension/src/mui/input/FormControl.tsx new file mode 100644 index 000000000..45f5a81d1 --- /dev/null +++ b/packages/taler-wallet-webextension/src/mui/input/FormControl.tsx @@ -0,0 +1,176 @@ +/* + This file is part of GNU Taler + (C) 2022 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ +import { css } from "@linaria/core"; +import { ComponentChildren, createContext, h, VNode } from "preact"; +import { useContext, useMemo, useState } from "preact/hooks"; +// eslint-disable-next-line import/extensions +import { Colors } from "../style.js"; + +export interface Props { + color: Colors; + disabled: boolean; + error?: string | Error; + focused: boolean; + fullWidth: boolean; + hiddenLabel: boolean; + required: boolean; + variant: "filled" | "outlined" | "standard"; + margin: "none" | "normal" | "dense"; + size: "medium" | "small"; + children: ComponentChildren; +} + +export const root = css` + display: inline-flex; + flex-direction: column; + position: relative; + min-width: 0px; + padding: 0px; + margin: 0px; + border: 0px; + vertical-align: top; +`; + +const marginVariant = { + none: "", + normal: css` + margin-top: 16px; + margin-bottom: 8px; + `, + dense: css` + margin-top: 8px; + margin-bottom: 4px; + `, +}; +const fullWidthStyle = css` + width: 100%; +`; + +export const FormControlContext = createContext<FCCProps | null>(null); + +export function FormControl({ + color = "primary", + disabled = false, + error = undefined, + focused: visuallyFocused, + fullWidth = false, + hiddenLabel = false, + margin = "none", + required = false, + size = "medium", + variant = "filled", + children, +}: Partial<Props>): VNode { + const [filled, setFilled] = useState(false); + const [focusedState, setFocused] = useState(visuallyFocused); + const focused = + focusedState !== undefined && !disabled ? focusedState : false; + + const value: FCCProps = { + color, + disabled, + error, + filled, + focused, + fullWidth, + hiddenLabel, + size, + onBlur: () => { + setFocused(false); + }, + onEmpty: () => { + setFilled(false); + }, + onFilled: () => { + setFilled(true); + }, + onFocus: () => { + setFocused(true); + }, + required, + variant, + }; + + return ( + <div + class={[ + root, + marginVariant[margin], + fullWidth ? fullWidthStyle : "", + ].join(" ")} + > + <FormControlContext.Provider value={value}> + {children} + </FormControlContext.Provider> + </div> + ); +} + +export interface FCCProps { + // adornedStart, + // setAdornedStart, + color: Colors; + disabled: boolean; + error: string | undefined | Error; + filled: boolean; + focused: boolean; + fullWidth: boolean; + hiddenLabel: boolean; + size: "medium" | "small"; + onBlur: () => void; + onEmpty: () => void; + onFilled: () => void; + onFocus: () => void; + // registerEffect, + required: boolean; + variant: "filled" | "outlined" | "standard"; +} + +const defaultContextValue: FCCProps = { + color: "primary", + disabled: false, + error: undefined, + filled: false, + focused: false, + fullWidth: false, + hiddenLabel: false, + size: "medium", + onBlur: () => null, + onEmpty: () => null, + onFilled: () => null, + onFocus: () => null, + required: false, + variant: "filled", +}; + +function withoutUndefinedProperties(obj: any): any { + return Object.keys(obj).reduce((acc, key) => { + const _acc: any = acc; + if (obj[key] !== undefined && obj[key] !== false) _acc[key] = obj[key]; + return _acc; + }, {}); +} + +export function useFormControl(props: Partial<FCCProps> = {}): FCCProps { + const ctx = useContext(FormControlContext); + const cleanedProps = withoutUndefinedProperties(props); + + return useMemo(() => { + return !ctx + ? { ...defaultContextValue, ...cleanedProps } + : { ...ctx, ...cleanedProps }; + }, [cleanedProps, ctx]); +} |