summaryrefslogtreecommitdiff
path: root/packages/taler-wallet-webextension/src/mui/input/FormControl.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'packages/taler-wallet-webextension/src/mui/input/FormControl.tsx')
-rw-r--r--packages/taler-wallet-webextension/src/mui/input/FormControl.tsx176
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]);
+}