From 68b6daa123340ef028145912bf2daa5671508129 Mon Sep 17 00:00:00 2001 From: marius Date: Mon, 2 Sep 2024 09:00:02 +0200 Subject: [PATCH 01/67] feat: initialised new Input logic, validation hook --- src/components/input/Input.stories.tsx | 68 ++++----- src/components/input/Input.tsx | 183 ++++++++----------------- src/components/input/useValidation.ts | 50 +++++++ 3 files changed, 141 insertions(+), 160 deletions(-) create mode 100644 src/components/input/useValidation.ts diff --git a/src/components/input/Input.stories.tsx b/src/components/input/Input.stories.tsx index f6d88529..5621dbf9 100644 --- a/src/components/input/Input.stories.tsx +++ b/src/components/input/Input.stories.tsx @@ -1,41 +1,45 @@ import React from "react"; -import Input from "./Input"; -import {IconMail} from "@tabler/icons-react"; +import {Input, InputWrapper} from "./Input"; +import {useValidation} from "./useValidation"; export default { title: "Input", component: Input }; -export const Mail = () => - e-mail - - - - Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam - +export const Default = () => { + const rules = [ + (value: string) => ({ + isValid: value.trim() !== "", + message: "Email is required" + }), + (value: string) => ({ + isValid: value.includes("@"), + message: "Email is invalid" + }) + ]; + const { value, setValue, state, message, validateInput } = useValidation({ + validationRules: rules, + successMessage: "Email is valid" + }); -export const Disabled = () => - - - - Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam - - -export const NotValid = () => - - - Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor - invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. - - Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam - - -export const Valid = () => - - Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor - invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. - - Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam - \ No newline at end of file + return ( + + { + console.log(value); + setValue(value); + }} + onBlur={validateInput} + /> + + ); +} \ No newline at end of file diff --git a/src/components/input/Input.tsx b/src/components/input/Input.tsx index 00ac30f6..2275ab70 100644 --- a/src/components/input/Input.tsx +++ b/src/components/input/Input.tsx @@ -1,147 +1,74 @@ -import React, {DetailedHTMLProps, InputHTMLAttributes, ReactElement, ReactNode, RefAttributes} from "react"; +import React, {DetailedHTMLProps, InputHTMLAttributes, ReactElement, ReactNode, RefAttributes, useState} from "react"; import "./Input.style.scss" import {TablerIcon} from "@tabler/icons-react"; +import {Code0Component} from "../../utils/types"; - -export type InputChildType = InputControlType | InputDescType | InputLabelType - -export interface InputType { - children: ReactElement | ReactElement[] - //defaults to false - disabled?: boolean - //defaults to undefined - valid?: boolean | undefined +export type InputState = { + value: boolean; + message: string; } - -const Input: React.FC = (props: InputType) => { - - const {disabled= false, children, valid} = props - const childNodes = React.Children.toArray(children).map(value => { - if (React.isValidElement(value) && value.type == InputControl) - return React.cloneElement(value as ReactElement, { - "aria-disabled": disabled, - "disabled": disabled - }) - return value - }) - - return
- {childNodes} -
-} - -export type InputControlTypesType = "email" - | "date" - | "datetime-local" - | "hidden" - | "number" - | "password" - | "search" - | "tel" - | "text" - | "time" - | "url" - | "week" - -// params / props declaration for InputComponent -export interface InputControlType extends DetailedHTMLProps, HTMLInputElement> { - placeholder: string - //TODO: allow both as non required and make sure this does not result in errors inside the component - children?: ReactElement[] | ReactElement - //defaults to false - disabled?: boolean - //default is text type - type?: InputControlTypesType -} - -/** - * Component to create the input. Manages the icon and the success / failure message. - * Extends the normal HTMLInputElement to allow further adjustments. - * - * @example - * {@link InputControlIcon} {@link InputControlMessage} - * - * @since 0.1.0-pre-alpha - * @author Nico Sammito - */ -const InputControl: React.ForwardRefExoticComponent & RefAttributes> = React.forwardRef((props, ref) => { - - const {type, placeholder, children, disabled, ...args} = props - const childNodes = children && !Array.isArray(children) ? Array.of(children) : children; - const icon = childNodes ? childNodes.find(child => child.type == InputControlIcon) : null - const message = childNodes ? childNodes.find(child => child.type == InputControlMessage) : null - - const onFocusParam = args.onFocus - const onBlurParam = args.onBlur - - const onFocus = ((event: React.FocusEvent) => { - if (event.target.parentElement) - event.target.parentElement.classList.add("input__control--active") - if (onFocusParam) onFocusParam(event) - }) - const onBlur = ((event: React.FocusEvent) => { - if (event.target.parentElement) - event.target.parentElement.classList.remove("input__control--active") - if (onBlurParam) onBlurParam(event) - }) - - args.onFocus = onFocus - args.onBlur = onBlur - - return <> -
- {icon ?? null} - { - (event.target as HTMLInputElement).focus() - }}/> -
- {message ?? null} - -}) - -export type InputControlMessageType = { - children: string +export interface InputType extends InputHTMLAttributes { + onValueChange?: (value: string) => void; + preValue?: string; } -const InputControlMessage: React.FC = ({children}) => { - return

{children}

-} +export interface PinInputType { -export type InputControlIconType = { - children: ReactElement } -const InputControlIcon: React.FC = ({children}) => { - return - {children} - +export interface InputWrapperType { + label?: string; + description?: string; + success?: InputState; + warning?: InputState; + error?: InputState; + children: ReactNode; } -export type InputLabelType = { - children: string +const Input: React.FC = ({ preValue, onValueChange, ...props }) => { + const [value, setValue] = useState(preValue || ""); + + const handleChange = (e: React.ChangeEvent) => { + const inputValue = e.target.value; + setValue(inputValue); + onValueChange?.(inputValue); + } + + return ( + + ); } -const InputLabel: React.FC = ({children}) => { - return +const PinInput: React.FC = () => { + return ( +
+
+ ); } - -export type InputDescType = { - children: string +const InputWrapper: React.FC = ({ label, description, success, warning, error, children }) => { + return ( +
+ {label && } + {description &&

{description}

} + {children} + {success?.value &&

{success.message}

} + {warning?.value &&

{warning.message}

} + {error?.value &&

{error.message}

} +
+ ); } -const InputDesc: React.FC = ({children}) => { - return

{children}

-} -export default Object.assign(Input, { - Desc: InputDesc, - Label: InputLabel, - Control: Object.assign(InputControl, { - Message: InputControlMessage, - Icon: InputControlIcon - }) -}); \ No newline at end of file +export { + Input as default, + PinInput, + InputWrapper +}; \ No newline at end of file diff --git a/src/components/input/useValidation.ts b/src/components/input/useValidation.ts new file mode 100644 index 00000000..1fe27b4f --- /dev/null +++ b/src/components/input/useValidation.ts @@ -0,0 +1,50 @@ +import {useCallback, useState} from "react"; + +export type ValidationRule = (value: string) => { + isValid: boolean; + message: string; +} + +type ValidationStatus = 'idle' | 'error' | 'warning' | 'success'; + +interface UseInputValidationProps { + //default value is empty string + initialValue?: string; + validationRules: ValidationRule[]; + //default is 0 + warningBuffer?: number; + successMessage?: string; + warningMessage?: string; +} + +export function useValidation({ initialValue = "", validationRules, warningBuffer = 0, successMessage, warningMessage }: UseInputValidationProps) { + const [value, setValue] = useState(initialValue); + const [state, setState] = useState('idle'); + const [message, setMessage] = useState(""); + + const validateInput = useCallback(() => { + if (!validationRules) return; + let errorCount = 0; + let errorMessage = ""; + + for (const rule of validationRules) { + const {isValid, message} = rule(value); + if (isValid) continue; + errorCount++; + if (!errorMessage) errorMessage = message; + } + + if (errorCount === 0) { + setState('success'); + setMessage(successMessage || 'Input is valid'); + } else if (errorCount <= warningBuffer && warningMessage) { + setState('warning'); + setMessage(warningMessage || 'Input is valid but with warnings'); + } else { + setState('error'); + setMessage(errorMessage.trim() === "" ? "Input is invalid" : errorMessage); + } + }, [successMessage, validationRules, value, warningBuffer, warningMessage]); + + return {value, setValue, state, message, validateInput}; +} \ No newline at end of file From 03ed70598865ed9ad3c617e9cb727ca807978df9 Mon Sep 17 00:00:00 2001 From: Marius Ahsmus Date: Thu, 5 Sep 2024 16:28:35 +0200 Subject: [PATCH 02/67] feat: pin input logic --- src/components/input/Input.stories.tsx | 37 +++++++++++- src/components/input/Input.tsx | 82 ++++++++++++++++++++++---- 2 files changed, 105 insertions(+), 14 deletions(-) diff --git a/src/components/input/Input.stories.tsx b/src/components/input/Input.stories.tsx index 5621dbf9..6c42d7d7 100644 --- a/src/components/input/Input.stories.tsx +++ b/src/components/input/Input.stories.tsx @@ -1,5 +1,5 @@ import React from "react"; -import {Input, InputWrapper} from "./Input"; +import Input, {InputWrapper, PinInput} from "./Input"; import {useValidation} from "./useValidation"; export default { @@ -7,7 +7,7 @@ export default { component: Input }; -export const Default = () => { +export const DefaultInput = () => { const rules = [ (value: string) => ({ isValid: value.trim() !== "", @@ -42,4 +42,37 @@ export const Default = () => { /> ); +} + +export const DefaultPinInput = () => { + const rules = [ + (value: string) => ({ + isValid: value === "1234", + message: "Email is required" + }) + ]; + + const { value, setValue, state, message, validateInput } = useValidation({ + validationRules: rules, + successMessage: "Email is valid" + }); + + return ( + + { + console.log(value); + setValue(value); + }} + onBlur={validateInput} + /> + + ); } \ No newline at end of file diff --git a/src/components/input/Input.tsx b/src/components/input/Input.tsx index 2275ab70..a973800f 100644 --- a/src/components/input/Input.tsx +++ b/src/components/input/Input.tsx @@ -1,4 +1,12 @@ -import React, {DetailedHTMLProps, InputHTMLAttributes, ReactElement, ReactNode, RefAttributes, useState} from "react"; +import React, { + DetailedHTMLProps, + InputHTMLAttributes, + ReactElement, + ReactNode, + RefAttributes, useEffect, + useRef, + useState +} from "react"; import "./Input.style.scss" import {TablerIcon} from "@tabler/icons-react"; import {Code0Component} from "../../utils/types"; @@ -14,7 +22,10 @@ export interface InputType extends InputHTMLAttributes { } export interface PinInputType { - + value: string; + onValueChange?: (value: string) => void; + onBlur?: () => void; + preValue?: number[]; } export interface InputWrapperType { @@ -37,7 +48,7 @@ const Input: React.FC = ({ preValue, onValueChange, ...props }) => { return ( = ({ preValue, onValueChange, ...props }) => { ); } -const PinInput: React.FC = () => { +const PinInput: React.FC = ({ value, preValue, onValueChange, onBlur, ...props }) => { + const inputRefs = [useRef(null), useRef(null), useRef(null), useRef(null)]; + + useEffect(() => { + inputRefs[0].current?.focus(); + }, []); + + const focusNextInput = (currentIndex: number) => { + if (currentIndex < 3) { + inputRefs[currentIndex + 1].current?.focus(); + } else { + inputRefs[currentIndex].current?.blur(); + onBlur?.(); + } + }; + + const handleChange = (e: React.ChangeEvent, index: number) => { + const inputValue = e.target.value; + if (inputValue.length <= 1 && /^\d*$/.test(inputValue)) { + const newValue = value.split(''); + newValue[index] = inputValue; + onValueChange?.(newValue.join('')); + + if (inputValue.length === 1) { + focusNextInput(index); + } + } + } + + const handleKeyDown = (e: React.KeyboardEvent, index: number) => { + if (e.key === 'Backspace' && !value[index] && index > 0) { + inputRefs[index - 1].current?.focus(); + } + }; + return ( -
+
+ {inputRefs.map((ref, index) => ( + handleChange(e, index)} + onKeyDown={(e) => handleKeyDown(e, index)} + {...props} + /> + ))}
); } -const InputWrapper: React.FC = ({ label, description, success, warning, error, children }) => { +const InputWrapper: React.FC = ({label, description, success, warning, error, children}) => { return ( -
- {label && } - {description &&

{description}

} +
+ {label && } + {description &&

{description}

} {children} - {success?.value &&

{success.message}

} - {warning?.value &&

{warning.message}

} - {error?.value &&

{error.message}

} + {success?.value &&

{success.message}

} + {warning?.value &&

{warning.message}

} + {error?.value &&

{error.message}

}
); } From dee5d4e379a077beb559245ffe8a9510aaab2fbf Mon Sep 17 00:00:00 2001 From: nicosammito Date: Tue, 8 Oct 2024 20:09:30 +0200 Subject: [PATCH 03/67] removed old input/form logic --- src/components/input/Input.style.scss | 122 ------------------------ src/components/input/Input.tsx | 132 -------------------------- src/components/input/useValidation.ts | 50 ---------- src/index.ts | 1 - 4 files changed, 305 deletions(-) delete mode 100644 src/components/input/Input.style.scss delete mode 100644 src/components/input/Input.tsx delete mode 100644 src/components/input/useValidation.ts diff --git a/src/components/input/Input.style.scss b/src/components/input/Input.style.scss deleted file mode 100644 index 1ed8d7ff..00000000 --- a/src/components/input/Input.style.scss +++ /dev/null @@ -1,122 +0,0 @@ -@import "../../styles/helpers"; - -.input { - margin-bottom: 1rem; - - &:last-child, &:last-of-type { - margin-bottom: 0; - } - - @include disabled; - - &__control { - display: flex; - align-items: center; - margin-bottom: .5rem; - - @include box(); - } - - &__label { - color: rgba($white, .5); - font-size: .75rem; - font-family: Ubuntu, sans-serif; - margin-bottom: .5rem; - display: block; - text-transform: uppercase; - } - - &__field { - position: relative; - display: inline-block; - background: none; - width: 100%; - color: rgba($white, .5); - font-family: Ubuntu, sans-serif; - border: none; - outline: none; - padding: .75rem .5rem; - box-shadow: none; - font-size: 1rem; - - &::placeholder { - color: rgba($white, .25); - } - } - - &__icon { - display: flex; - width: 1.25rem; - height: 1.25rem; - justify-content: center; - align-items: center; - aspect-ratio: 50/50; - margin-left: .5rem; - pointer-events: none; - - > * { - width: 1.25rem; - height: 1.25rem; - } - - } - - &__desc { - padding-left: 1rem; - color: rgba($white, .5); - font-size: .75rem; - font-family: Ubuntu, sans-serif; - margin: .5rem 0; - - &:before { - //tabler info icon as an svg component - content: url('data:image/svg+xml; utf8, '); - height: .75rem; - width: .75rem; - padding: .25rem 0; - margin-right: .25rem; - } - } - - &__message { - display: none; - position: relative; - color: rgba($white, .5); - border-radius: $borderRadius; - font-size: .75rem; - z-index: -1; - font-family: Ubuntu, sans-serif; - - > p { - margin: 0; - padding: .5rem .5rem .5rem 1rem; - - &:before { - //tabler info icon as an svg component - content: url('data:image/svg+xml; utf8, '); - height: .75rem; - width: .75rem; - padding: .25rem 0; - margin-right: .25rem; - } - } - } - - &--not-valid { - - .input__message { - display: block; - background: rgba($error, .1); - - } - } - - &--valid { - - .input__message { - display: block; - background: rgba($success, .1); - - } - } -} \ No newline at end of file diff --git a/src/components/input/Input.tsx b/src/components/input/Input.tsx deleted file mode 100644 index a973800f..00000000 --- a/src/components/input/Input.tsx +++ /dev/null @@ -1,132 +0,0 @@ -import React, { - DetailedHTMLProps, - InputHTMLAttributes, - ReactElement, - ReactNode, - RefAttributes, useEffect, - useRef, - useState -} from "react"; -import "./Input.style.scss" -import {TablerIcon} from "@tabler/icons-react"; -import {Code0Component} from "../../utils/types"; - -export type InputState = { - value: boolean; - message: string; -} - -export interface InputType extends InputHTMLAttributes { - onValueChange?: (value: string) => void; - preValue?: string; -} - -export interface PinInputType { - value: string; - onValueChange?: (value: string) => void; - onBlur?: () => void; - preValue?: number[]; -} - -export interface InputWrapperType { - label?: string; - description?: string; - success?: InputState; - warning?: InputState; - error?: InputState; - children: ReactNode; -} - -const Input: React.FC = ({ preValue, onValueChange, ...props }) => { - const [value, setValue] = useState(preValue || ""); - - const handleChange = (e: React.ChangeEvent) => { - const inputValue = e.target.value; - setValue(inputValue); - onValueChange?.(inputValue); - } - - return ( - - ); -} - -const PinInput: React.FC = ({ value, preValue, onValueChange, onBlur, ...props }) => { - const inputRefs = [useRef(null), useRef(null), useRef(null), useRef(null)]; - - useEffect(() => { - inputRefs[0].current?.focus(); - }, []); - - const focusNextInput = (currentIndex: number) => { - if (currentIndex < 3) { - inputRefs[currentIndex + 1].current?.focus(); - } else { - inputRefs[currentIndex].current?.blur(); - onBlur?.(); - } - }; - - const handleChange = (e: React.ChangeEvent, index: number) => { - const inputValue = e.target.value; - if (inputValue.length <= 1 && /^\d*$/.test(inputValue)) { - const newValue = value.split(''); - newValue[index] = inputValue; - onValueChange?.(newValue.join('')); - - if (inputValue.length === 1) { - focusNextInput(index); - } - } - } - - const handleKeyDown = (e: React.KeyboardEvent, index: number) => { - if (e.key === 'Backspace' && !value[index] && index > 0) { - inputRefs[index - 1].current?.focus(); - } - }; - - return ( -
- {inputRefs.map((ref, index) => ( - handleChange(e, index)} - onKeyDown={(e) => handleKeyDown(e, index)} - {...props} - /> - ))} -
- ); -} - -const InputWrapper: React.FC = ({label, description, success, warning, error, children}) => { - return ( -
- {label && } - {description &&

{description}

} - {children} - {success?.value &&

{success.message}

} - {warning?.value &&

{warning.message}

} - {error?.value &&

{error.message}

} -
- ); -} - - -export { - Input as default, - PinInput, - InputWrapper -}; \ No newline at end of file diff --git a/src/components/input/useValidation.ts b/src/components/input/useValidation.ts deleted file mode 100644 index 1fe27b4f..00000000 --- a/src/components/input/useValidation.ts +++ /dev/null @@ -1,50 +0,0 @@ -import {useCallback, useState} from "react"; - -export type ValidationRule = (value: string) => { - isValid: boolean; - message: string; -} - -type ValidationStatus = 'idle' | 'error' | 'warning' | 'success'; - -interface UseInputValidationProps { - //default value is empty string - initialValue?: string; - validationRules: ValidationRule[]; - //default is 0 - warningBuffer?: number; - successMessage?: string; - warningMessage?: string; -} - -export function useValidation({ initialValue = "", validationRules, warningBuffer = 0, successMessage, warningMessage }: UseInputValidationProps) { - const [value, setValue] = useState(initialValue); - const [state, setState] = useState('idle'); - const [message, setMessage] = useState(""); - - const validateInput = useCallback(() => { - if (!validationRules) return; - let errorCount = 0; - let errorMessage = ""; - - for (const rule of validationRules) { - const {isValid, message} = rule(value); - if (isValid) continue; - errorCount++; - if (!errorMessage) errorMessage = message; - } - - if (errorCount === 0) { - setState('success'); - setMessage(successMessage || 'Input is valid'); - } else if (errorCount <= warningBuffer && warningMessage) { - setState('warning'); - setMessage(warningMessage || 'Input is valid but with warnings'); - } else { - setState('error'); - setMessage(errorMessage.trim() === "" ? "Input is invalid" : errorMessage); - } - }, [successMessage, validationRules, value, warningBuffer, warningMessage]); - - return {value, setValue, state, message, validateInput}; -} \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index dc6e29d4..f282a727 100644 --- a/src/index.ts +++ b/src/index.ts @@ -7,7 +7,6 @@ export { default as Col} from "./components/col/Col" export { default as Container} from "./components/container/Container" export { default as Dropdown} from "./components/dropdown/Dropdown" export { default as Text} from "./components/Text/Text" -export { default as Input } from "./components/input/Input"; export { default as ListGroup} from "./components/list-group/ListGroup" export { default as Menu} from "./components/menu/Menu" export { default as Popover} from "./components/popover/Popover" From fdc486a926f52d4211592fe57a12fac4edec5883 Mon Sep 17 00:00:00 2001 From: nicosammito Date: Tue, 8 Oct 2024 20:09:54 +0200 Subject: [PATCH 04/67] removed old input components from tests --- src/components/dropdown/Dropdown.stories.tsx | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/components/dropdown/Dropdown.stories.tsx b/src/components/dropdown/Dropdown.stories.tsx index ff502cf2..40147ab1 100644 --- a/src/components/dropdown/Dropdown.stories.tsx +++ b/src/components/dropdown/Dropdown.stories.tsx @@ -2,9 +2,8 @@ import {Meta} from "@storybook/react"; import React from "react"; import Dropdown from "./Dropdown"; import Button from "../button/Button"; -import {IconAbc, IconSearch} from "@tabler/icons-react"; +import {IconAbc} from "@tabler/icons-react"; import ButtonGroup from "../button-group/ButtonGroup"; -import Input from "../input/Input"; const meta: Meta = { title: "Dropdown", @@ -30,11 +29,6 @@ export const Dropdowns = () => { - - - - - Item 1 From 93f49c9030841c234f2cb56acfb00459af3a0595 Mon Sep 17 00:00:00 2001 From: nicosammito Date: Tue, 8 Oct 2024 20:10:24 +0200 Subject: [PATCH 05/67] implemented useForm hook and test component --- src/components/form/Input.stories.tsx | 29 ++++++++++ src/components/form/useForm.ts | 75 +++++++++++++++++++++++++ src/components/input/Input.stories.tsx | 78 -------------------------- 3 files changed, 104 insertions(+), 78 deletions(-) create mode 100644 src/components/form/Input.stories.tsx create mode 100644 src/components/form/useForm.ts delete mode 100644 src/components/input/Input.stories.tsx diff --git a/src/components/form/Input.stories.tsx b/src/components/form/Input.stories.tsx new file mode 100644 index 00000000..4e03b334 --- /dev/null +++ b/src/components/form/Input.stories.tsx @@ -0,0 +1,29 @@ +import React, {forwardRef} from "react"; +import useForm from "./useForm"; + +const TestC: React.FC = forwardRef((props, ref) => { + console.log(props) + return +}) +export default { + title: "Input", + component: TestC +} + +export const Test = () => { + + const [inputs, validate] = useForm({ + initialValues: { + test: "test@" + }, + validate: { + test: (value) => !value.includes("@") ? "Hier ist was falsch" : null + } + }) + + return <> + + + + +} \ No newline at end of file diff --git a/src/components/form/useForm.ts b/src/components/form/useForm.ts new file mode 100644 index 00000000..3b6e9bec --- /dev/null +++ b/src/components/form/useForm.ts @@ -0,0 +1,75 @@ +"use client" + +import {RefObject, useCallback, useMemo, useRef, useState} from "react"; + +export type Validations = Partial<{ + [Key in keyof Values]: (value: Values[Key]) => string | null; +}> + +interface FormValidationProps { + initialValues: Values + validate?: Validations +} + +interface ValidationProps { + value: Value + valid: boolean + notValidMessage: string | null + ref: RefObject +} + +type ValidationsProps = Partial<{ + [Key in keyof Values]: ValidationProps +}> + +type FormValidationReturn = [ValidationsProps, () => void] + +const useForm = = Record>(props: FormValidationProps): FormValidationReturn => { + + const {initialValues, validate} = props + + const [valuesState, setValuesStore] = useState(initialValues) + const inputProps = useMemo>(() => { + + let inputProps: ValidationsProps = {} + + Object.entries(valuesState).map(([k, v]) => ({ + name: k, + initialValue: v, + function: !!validate && !!validate[k] ? validate[k] : (value: typeof v) => null + })).forEach(item => { + Object.assign(inputProps, { + [item.name]: { + defaultValue: item.initialValue, + notValidMessage: item.function(item.initialValue), + valid: !item.function(item.initialValue), + ref: useRef(null) + } + }) + }) + + return inputProps + + }, [valuesState]) + + const validateFunction = useCallback(() => { + + let values: { [index: string]: any } = {...valuesState} + + Object.entries(inputProps as ValidationsProps).forEach(([key, value]) => { + const inputRef: RefObject = value.ref + values[key] = inputRef.current?.value + }) + + setValuesStore(values as Values) + + }, [inputProps]) + + return [ + inputProps, + validateFunction + ] + +} + +export default useForm diff --git a/src/components/input/Input.stories.tsx b/src/components/input/Input.stories.tsx deleted file mode 100644 index 6c42d7d7..00000000 --- a/src/components/input/Input.stories.tsx +++ /dev/null @@ -1,78 +0,0 @@ -import React from "react"; -import Input, {InputWrapper, PinInput} from "./Input"; -import {useValidation} from "./useValidation"; - -export default { - title: "Input", - component: Input -}; - -export const DefaultInput = () => { - const rules = [ - (value: string) => ({ - isValid: value.trim() !== "", - message: "Email is required" - }), - (value: string) => ({ - isValid: value.includes("@"), - message: "Email is invalid" - }) - ]; - - const { value, setValue, state, message, validateInput } = useValidation({ - validationRules: rules, - successMessage: "Email is valid" - }); - - return ( - - { - console.log(value); - setValue(value); - }} - onBlur={validateInput} - /> - - ); -} - -export const DefaultPinInput = () => { - const rules = [ - (value: string) => ({ - isValid: value === "1234", - message: "Email is required" - }) - ]; - - const { value, setValue, state, message, validateInput } = useValidation({ - validationRules: rules, - successMessage: "Email is valid" - }); - - return ( - - { - console.log(value); - setValue(value); - }} - onBlur={validateInput} - /> - - ); -} \ No newline at end of file From 8b511228da0db1f87ab27ea9a3c1ee39a0d49231 Mon Sep 17 00:00:00 2001 From: nicosammito Date: Thu, 10 Oct 2024 07:56:34 +0200 Subject: [PATCH 06/67] fiy for do not use a hook inside a hook warning --- src/components/form/useForm.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/components/form/useForm.ts b/src/components/form/useForm.ts index 3b6e9bec..f1007878 100644 --- a/src/components/form/useForm.ts +++ b/src/components/form/useForm.ts @@ -28,6 +28,7 @@ const useForm = = Record>(props const {initialValues, validate} = props + const refs = Object.entries(initialValues).map(() => useRef(null)) const [valuesState, setValuesStore] = useState(initialValues) const inputProps = useMemo>(() => { @@ -37,13 +38,13 @@ const useForm = = Record>(props name: k, initialValue: v, function: !!validate && !!validate[k] ? validate[k] : (value: typeof v) => null - })).forEach(item => { + })).forEach((item, index) => { Object.assign(inputProps, { [item.name]: { defaultValue: item.initialValue, notValidMessage: item.function(item.initialValue), valid: !item.function(item.initialValue), - ref: useRef(null) + ref: refs[index] } }) }) @@ -61,7 +62,7 @@ const useForm = = Record>(props values[key] = inputRef.current?.value }) - setValuesStore(values as Values) + setValuesStore(() => values as Values) }, [inputProps]) From 0aad7e95e94eb4f6140b66b3883a09b9cb1fd924 Mon Sep 17 00:00:00 2001 From: nicosammito Date: Thu, 10 Oct 2024 14:06:38 +0200 Subject: [PATCH 07/67] changing active and focus border behaviour --- src/styles/_helpers.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/styles/_helpers.scss b/src/styles/_helpers.scss index c3f6750f..9818bac5 100644 --- a/src/styles/_helpers.scss +++ b/src/styles/_helpers.scss @@ -21,7 +21,7 @@ outline: none; } - &:active { + &:active, &--active, &:focus, &:focus-visible { border: 1px solid borderColor($color, true); } } From 24a9f1c29197b4cc923cc2b888517e97acc18df5 Mon Sep 17 00:00:00 2001 From: nicosammito Date: Thu, 10 Oct 2024 14:07:39 +0200 Subject: [PATCH 08/67] new input component --- src/components/form/Input.stories.tsx | 68 ++++++++++++++---- src/components/form/Input.style.scss | 88 ++++++++++++++++++++++++ src/components/form/Input.tsx | 61 ++++++++++++++++ src/components/form/InputDescription.tsx | 17 +++++ src/components/form/InputLabel.tsx | 17 +++++ src/components/form/InputMessage.tsx | 19 +++++ 6 files changed, 258 insertions(+), 12 deletions(-) create mode 100644 src/components/form/Input.style.scss create mode 100644 src/components/form/Input.tsx create mode 100644 src/components/form/InputDescription.tsx create mode 100644 src/components/form/InputLabel.tsx create mode 100644 src/components/form/InputMessage.tsx diff --git a/src/components/form/Input.stories.tsx b/src/components/form/Input.stories.tsx index 4e03b334..e70fc0c5 100644 --- a/src/components/form/Input.stories.tsx +++ b/src/components/form/Input.stories.tsx @@ -1,29 +1,73 @@ -import React, {forwardRef} from "react"; +import React from "react"; import useForm from "./useForm"; +import Input from "./Input"; +import Card from "../card/Card"; +import Button from "../button/Button"; +import {IconEye, IconMail} from "@tabler/icons-react"; +import Select from "../select/Select"; +import {Text} from "../../index"; -const TestC: React.FC = forwardRef((props, ref) => { - console.log(props) - return -}) export default { title: "Input", - component: TestC + component: Input } export const Test = () => { const [inputs, validate] = useForm({ initialValues: { - test: "test@" + test: null }, validate: { - test: (value) => !value.includes("@") ? "Hier ist was falsch" : null + test: (value) => { + if (!value) return "Test is required" + return null + } } }) - return <> - - - + return +
+ } + left={ + + } + leftType={"action"} + rightType={"icon"} + label={"Email"} + description={"Provide a valid email address"} + type={"text"} + placeholder={"test"} + required + {...(inputs.test)}/> +
+ + + + + Fruits + + + + + + + + + } + rightType={"action"} + label={"Email"} + description={"Provide a valid email address"} + type={"text"} + placeholder={"test"} + required + {...(inputs.test)}/> +
+ + +
} \ No newline at end of file diff --git a/src/components/form/Input.style.scss b/src/components/form/Input.style.scss new file mode 100644 index 00000000..e9cf4dce --- /dev/null +++ b/src/components/form/Input.style.scss @@ -0,0 +1,88 @@ +@import "../../styles/helpers"; + +.input { + + @include box(true, $primary); + display: flex; + align-items: center; + + + &:has(&__control:focus) { + border: 1px solid borderColor($primary, true); + } + + &--not-valid { + border: 1px solid borderColor($error, true); + } + + &__left, &__right { + display: flex; + height: 100%; + align-items: center; + + &--action { + padding: 0; + } + + &--placeholder { + @include box(false, $secondary); + padding: $xxs; + } + + } + + &__left { + &--icon { + padding: $xxs 0 $xxs $xxs; + } + } + + &__right { + &--icon { + padding: $xxs $xxs $xxs 0; + } + } + + &__control { + background: none; + border: none; + outline: none; + padding: $xs $xxs; + flex: 1; + box-shadow: none; + font-size: $sm; + color: rgba($white, .5); + } + + + &__label { + text-transform: uppercase; + color: rgba($white, .5); + font-size: $xs; + margin: $xxs 0; + display: block; + } + + &__description { + color: rgba($white, .5); + font-size: $sm; + margin: $xxs 0; + display: block; + } + + &__message { + @include box(false, $error); + padding: $xxs; + margin: $xxs 0; + display: flex; + align-items: center; + font-size: $xs; + gap: $xxs; + + > svg { + width: $xs; + height: $xs; + } + } + +} \ No newline at end of file diff --git a/src/components/form/Input.tsx b/src/components/form/Input.tsx new file mode 100644 index 00000000..b27e82f5 --- /dev/null +++ b/src/components/form/Input.tsx @@ -0,0 +1,61 @@ +import {Code0Component, Color} from "../../utils/types"; +import React from "react"; +import {ValidationProps} from "./useForm"; +import {mergeCode0Props} from "../../utils/utils"; +import "./Input.style.scss" +import InputLabel from "./InputLabel"; +import InputDescription from "./InputDescription"; +import InputMessage from "./InputMessage"; + +export interface InputProps extends Omit, "label">, ValidationProps { + + right?: React.ReactNode | React.ReactElement + left?: React.ReactNode | React.ReactElement + leftType?: "action" | "placeholder" | "icon" + rightType?: "action" | "placeholder" | "icon" + label?: React.ReactNode | React.ReactElement + description?: React.ReactNode | React.ReactElement + color?: Color +} + + +const Input: React.FC> = React.forwardRef((props: InputProps, ref) => { + + const { + label, + description, + disabled = false, + left, + right, + leftType = "icon", + rightType = "action", + notValidMessage, + valid, + ...rest + } = props + + return <> + + {!!label ? : null} + {!!description ? : null} + +
+ + {!!left ? + {left} + : null} + + + + {!!right ? + {right} + : null} + +
+ + {!valid && notValidMessage ? : null} + +}) + + +export default Input \ No newline at end of file diff --git a/src/components/form/InputDescription.tsx b/src/components/form/InputDescription.tsx new file mode 100644 index 00000000..46d0ad9c --- /dev/null +++ b/src/components/form/InputDescription.tsx @@ -0,0 +1,17 @@ +import React from "react"; + +export interface InputDescriptionProps { + children: React.ReactNode | React.ReactElement +} + +const InputDescription: React.FC = (props) => { + + const {children} = props + + return + {children} + + +} + +export default InputDescription \ No newline at end of file diff --git a/src/components/form/InputLabel.tsx b/src/components/form/InputLabel.tsx new file mode 100644 index 00000000..4fee9f7a --- /dev/null +++ b/src/components/form/InputLabel.tsx @@ -0,0 +1,17 @@ +import React from "react"; + +export interface InputLabelProps { + children: React.ReactNode | React.ReactElement +} + +const InputLabel: React.FC = (props) => { + + const {children} = props + + return + +} + +export default InputLabel \ No newline at end of file diff --git a/src/components/form/InputMessage.tsx b/src/components/form/InputMessage.tsx new file mode 100644 index 00000000..8d6d54fb --- /dev/null +++ b/src/components/form/InputMessage.tsx @@ -0,0 +1,19 @@ +import React from "react"; +import {IconExclamationCircle} from "@tabler/icons-react"; + +export interface InputMessageProps { + children: string +} + +const InputMessage: React.FC = (props) => { + + const {children} = props + + return + + {children} + + +} + +export default InputMessage \ No newline at end of file From 6a8683e5e4d39b4c8e7c6f4da8780412f15e5d02 Mon Sep 17 00:00:00 2001 From: nicosammito Date: Thu, 10 Oct 2024 14:08:11 +0200 Subject: [PATCH 09/67] fixing some logic bugs inside the useForm hook and export interfaces and types --- src/components/form/useForm.ts | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/components/form/useForm.ts b/src/components/form/useForm.ts index f1007878..61963125 100644 --- a/src/components/form/useForm.ts +++ b/src/components/form/useForm.ts @@ -6,23 +6,23 @@ export type Validations = Partial<{ [Key in keyof Values]: (value: Values[Key]) => string | null; }> -interface FormValidationProps { +export interface FormValidationProps { initialValues: Values validate?: Validations } -interface ValidationProps { - value: Value - valid: boolean - notValidMessage: string | null - ref: RefObject +export interface ValidationProps { + defaultValue?: Value + valid?: boolean + notValidMessage?: string | null + ref?: RefObject } -type ValidationsProps = Partial<{ +export type ValidationsProps = Partial<{ [Key in keyof Values]: ValidationProps }> -type FormValidationReturn = [ValidationsProps, () => void] +export type FormValidationReturn = [ValidationsProps, () => void] const useForm = = Record>(props: FormValidationProps): FormValidationReturn => { @@ -39,11 +39,14 @@ const useForm = = Record>(props initialValue: v, function: !!validate && !!validate[k] ? validate[k] : (value: typeof v) => null })).forEach((item, index) => { + + const message = item.initialValue !== null ? item.function(item.initialValue) : null + Object.assign(inputProps, { [item.name]: { defaultValue: item.initialValue, - notValidMessage: item.function(item.initialValue), - valid: !item.function(item.initialValue), + notValidMessage: message, + valid: message === null ? true : !message, ref: refs[index] } }) From 6e1f0a5b6773c13bcd250959ca5669f662b8878c Mon Sep 17 00:00:00 2001 From: nicosammito Date: Thu, 10 Oct 2024 22:52:23 +0200 Subject: [PATCH 10/67] changing padding to xs --- src/components/form/Input.style.scss | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/components/form/Input.style.scss b/src/components/form/Input.style.scss index e9cf4dce..1ebf9790 100644 --- a/src/components/form/Input.style.scss +++ b/src/components/form/Input.style.scss @@ -2,6 +2,8 @@ .input { + $padding: $xs; + @include box(true, $primary); display: flex; align-items: center; From 27eb2e2e49d809070b2f5e53ea85891802a3ea82 Mon Sep 17 00:00:00 2001 From: nicosammito Date: Thu, 10 Oct 2024 22:52:48 +0200 Subject: [PATCH 11/67] stretching left and right items to fit into input --- src/components/form/Input.style.scss | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/components/form/Input.style.scss b/src/components/form/Input.style.scss index 1ebf9790..f20b2189 100644 --- a/src/components/form/Input.style.scss +++ b/src/components/form/Input.style.scss @@ -6,7 +6,7 @@ @include box(true, $primary); display: flex; - align-items: center; + align-items: stretch; &:has(&__control:focus) { @@ -19,8 +19,8 @@ &__left, &__right { display: flex; - height: 100%; - align-items: center; + align-items: stretch; + &--action { padding: 0; @@ -28,20 +28,20 @@ &--placeholder { @include box(false, $secondary); - padding: $xxs; + padding: $padding; } } &__left { &--icon { - padding: $xxs 0 $xxs $xxs; + padding: $padding 0 $padding $padding; } } &__right { &--icon { - padding: $xxs $xxs $xxs 0; + padding: $padding $padding $padding 0; } } @@ -49,7 +49,7 @@ background: none; border: none; outline: none; - padding: $xs $xxs; + padding: $padding $padding; flex: 1; box-shadow: none; font-size: $sm; @@ -61,25 +61,25 @@ text-transform: uppercase; color: rgba($white, .5); font-size: $xs; - margin: $xxs 0; + margin: $padding 0; display: block; } &__description { color: rgba($white, .5); font-size: $sm; - margin: $xxs 0; + margin: $padding 0; display: block; } &__message { @include box(false, $error); - padding: $xxs; - margin: $xxs 0; + padding: $padding; + margin: $padding 0; display: flex; align-items: center; font-size: $xs; - gap: $xxs; + gap: $padding; > svg { width: $xs; From f7a7f9f9bc9b0cf0ab7379fcaaef97ab397ae278 Mon Sep 17 00:00:00 2001 From: nicosammito Date: Thu, 10 Oct 2024 22:53:04 +0200 Subject: [PATCH 12/67] fixing type errors and conflicts --- src/components/form/Input.tsx | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/components/form/Input.tsx b/src/components/form/Input.tsx index b27e82f5..7456c856 100644 --- a/src/components/form/Input.tsx +++ b/src/components/form/Input.tsx @@ -1,5 +1,5 @@ import {Code0Component, Color} from "../../utils/types"; -import React from "react"; +import React, {LegacyRef} from "react"; import {ValidationProps} from "./useForm"; import {mergeCode0Props} from "../../utils/utils"; import "./Input.style.scss" @@ -7,7 +7,9 @@ import InputLabel from "./InputLabel"; import InputDescription from "./InputDescription"; import InputMessage from "./InputMessage"; -export interface InputProps extends Omit, "label">, ValidationProps { +type Code0Input = Omit, "defaultValue">, "ref">, "left">, "right">, "label"> + +export interface InputProps extends Code0Input, ValidationProps { right?: React.ReactNode | React.ReactElement left?: React.ReactNode | React.ReactElement @@ -19,7 +21,7 @@ export interface InputProps extends Omit, "l } -const Input: React.FC> = React.forwardRef((props: InputProps, ref) => { +const Input: React.ForwardRefExoticComponent, "ref">> = React.forwardRef((props: InputProps, ref) => { const { label, @@ -41,15 +43,15 @@ const Input: React.FC> = React.forwardRef((props: InputProps - {!!left ? + {!!left ?
{left} - : null} +
: null} - + | undefined} {...mergeCode0Props("input__control", rest)}/> - {!!right ? + {!!right ?
{right} - : null} +
: null}
From c67ea07141cb2bf799c7dc08c65fe813cd67e29c Mon Sep 17 00:00:00 2001 From: nicosammito Date: Tue, 22 Oct 2024 15:44:17 +0200 Subject: [PATCH 13/67] adding wrapper styling option --- src/components/form/Input.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/components/form/Input.tsx b/src/components/form/Input.tsx index 7456c856..7707ca34 100644 --- a/src/components/form/Input.tsx +++ b/src/components/form/Input.tsx @@ -11,6 +11,7 @@ type Code0Input = Omit, "de export interface InputProps extends Code0Input, ValidationProps { + wrapperComponent?: Code0Component right?: React.ReactNode | React.ReactElement left?: React.ReactNode | React.ReactElement leftType?: "action" | "placeholder" | "icon" @@ -24,6 +25,7 @@ export interface InputProps extends Code0Input, ValidationProps { const Input: React.ForwardRefExoticComponent, "ref">> = React.forwardRef((props: InputProps, ref) => { const { + wrapperComponent = {}, label, description, disabled = false, @@ -32,7 +34,7 @@ const Input: React.ForwardRefExoticComponent, "ref">> = Rea leftType = "icon", rightType = "action", notValidMessage, - valid, + valid = true, ...rest } = props @@ -41,7 +43,7 @@ const Input: React.ForwardRefExoticComponent, "ref">> = Rea {!!label ? : null} {!!description ? : null} -
+
{!!left ?
{left} From 85f090e97ebf6f27d0e30febaa375dc493a3968c Mon Sep 17 00:00:00 2001 From: nicosammito Date: Tue, 22 Oct 2024 15:44:44 +0200 Subject: [PATCH 14/67] examples --- src/components/form/Input.stories.tsx | 135 ++++++++++++++++++-------- 1 file changed, 94 insertions(+), 41 deletions(-) diff --git a/src/components/form/Input.stories.tsx b/src/components/form/Input.stories.tsx index e70fc0c5..de3e18e5 100644 --- a/src/components/form/Input.stories.tsx +++ b/src/components/form/Input.stories.tsx @@ -3,71 +3,124 @@ import useForm from "./useForm"; import Input from "./Input"; import Card from "../card/Card"; import Button from "../button/Button"; -import {IconEye, IconMail} from "@tabler/icons-react"; -import Select from "../select/Select"; -import {Text} from "../../index"; +import {IconEye, IconKey, IconLogin, IconMail, IconMinus, IconPlus, IconX} from "@tabler/icons-react"; +import ButtonGroup from "../button-group/ButtonGroup"; +import Text from "../Text/Text"; export default { title: "Input", component: Input } -export const Test = () => { +export const Login = () => { const [inputs, validate] = useForm({ initialValues: { - test: null + email: null, + password: null, + checkbox: true }, validate: { - test: (value) => { - if (!value) return "Test is required" + email: (value) => { + if (!value) return "Email is required" + return null + }, + password: (value) => { + if (!value) return "Password is required" return null } + }, + onSubmit: (values) => { + console.log(values) } }) - return + return + Login +
+ + Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et + dolore magna aliquyam erat, sed diam voluptua. + +
} - left={ - - } - leftType={"action"} - rightType={"icon"} + placeholder={"Email"} label={"Email"} - description={"Provide a valid email address"} - type={"text"} - placeholder={"test"} - required - {...(inputs.test)}/> + type={"checkbox"} + description={"Your Email address for login"} + left={} + right={} + {...inputs.checkbox} + />
- - - - Fruits - - - - - - - - - } - rightType={"action"} + placeholder={"Email"} label={"Email"} - description={"Provide a valid email address"} - type={"text"} - placeholder={"test"} - required - {...(inputs.test)}/> + type={"email"} + description={"Your Email address for login"} + left={} + right={} + {...inputs.email} + /> +
+ } + right={ + + + } + {...inputs.password} + />
- +
+ + +
+
+} + +export const WebsiteInput = () => { + + return + } + /> + + +} + +export const NumberInput = () => { + + return + } + leftType={"action"} + right={} + /> + + } \ No newline at end of file From e75da8e040236edf219b411e6e8f823669a703b3 Mon Sep 17 00:00:00 2001 From: nicosammito Date: Tue, 22 Oct 2024 15:44:56 +0200 Subject: [PATCH 15/67] styling --- src/components/form/Input.style.scss | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/components/form/Input.style.scss b/src/components/form/Input.style.scss index f20b2189..445a332b 100644 --- a/src/components/form/Input.style.scss +++ b/src/components/form/Input.style.scss @@ -6,6 +6,7 @@ @include box(true, $primary); display: flex; + z-index: 1; align-items: stretch; @@ -21,7 +22,6 @@ display: flex; align-items: stretch; - &--action { padding: 0; } @@ -35,12 +35,14 @@ &__left { &--icon { + align-items: center; padding: $padding 0 $padding $padding; } } &__right { &--icon { + align-items: center; padding: $padding $padding $padding 0; } } @@ -61,21 +63,24 @@ text-transform: uppercase; color: rgba($white, .5); font-size: $xs; - margin: $padding 0; + //margin: $padding 0; display: block; } &__description { color: rgba($white, .5); font-size: $sm; - margin: $padding 0; + margin: $padding/2 0 $padding; display: block; } &__message { @include box(false, $error); - padding: $padding; - margin: $padding 0; + border-top-right-radius: 0; + border-top-left-radius: 0; + padding: $padding * 2 $padding $padding; + top: -$padding; + z-index: 0; display: flex; align-items: center; font-size: $xs; From 4b7b1499b7892a6276432e9c2a9388be2f7537f6 Mon Sep 17 00:00:00 2001 From: nicosammito Date: Tue, 22 Oct 2024 15:45:25 +0200 Subject: [PATCH 16/67] better performance of useForm hook and added onSubmit function --- src/components/form/useForm.ts | 55 ++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/src/components/form/useForm.ts b/src/components/form/useForm.ts index 61963125..7255e2e4 100644 --- a/src/components/form/useForm.ts +++ b/src/components/form/useForm.ts @@ -1,6 +1,6 @@ "use client" -import {RefObject, useCallback, useMemo, useRef, useState} from "react"; +import {RefObject, useCallback, useRef, useState} from "react"; export type Validations = Partial<{ [Key in keyof Values]: (value: Values[Key]) => string | null; @@ -8,7 +8,8 @@ export type Validations = Partial<{ export interface FormValidationProps { initialValues: Values - validate?: Validations + validate?: Validations, + onSubmit?: (values: Values) => void } export interface ValidationProps { @@ -24,50 +25,58 @@ export type ValidationsProps = Partial<{ export type FormValidationReturn = [ValidationsProps, () => void] + const useForm = = Record>(props: FormValidationProps): FormValidationReturn => { - const {initialValues, validate} = props + const {initialValues, validate, onSubmit = () => {}} = props const refs = Object.entries(initialValues).map(() => useRef(null)) - const [valuesState, setValuesStore] = useState(initialValues) - const inputProps = useMemo>(() => { + const [inputProps, setInputProps] = useState>({}) + + const validateFunction = useCallback(() => { + let submittable = true let inputProps: ValidationsProps = {} + let submitProps: Object = {} + + Object.entries(initialValues).map(([k, v], index) => { + + const inputRef: RefObject = refs[index] + const currentValue = inputRef.current?.value + + return { + name: k, + value: currentValue as typeof v || undefined, + function: !!validate && !!validate[k] ? validate[k] : (value: typeof currentValue) => null + } - Object.entries(valuesState).map(([k, v]) => ({ - name: k, - initialValue: v, - function: !!validate && !!validate[k] ? validate[k] : (value: typeof v) => null - })).forEach((item, index) => { + }).forEach((item, index) => { - const message = item.initialValue !== null ? item.function(item.initialValue) : null + const message = item.value !== null ? item.function(item.value) : null + submittable = submittable ? message === null ? true : !message : false Object.assign(inputProps, { [item.name]: { - defaultValue: item.initialValue, + defaultValue: item.value, notValidMessage: message, valid: message === null ? true : !message, ref: refs[index] } }) - }) - return inputProps + Object.assign(submitProps, { + [item.name]: item.value + }) - }, [valuesState]) + }) - const validateFunction = useCallback(() => { + setInputProps(() => inputProps) - let values: { [index: string]: any } = {...valuesState} + if (submittable) onSubmit(submitProps as Values) - Object.entries(inputProps as ValidationsProps).forEach(([key, value]) => { - const inputRef: RefObject = value.ref - values[key] = inputRef.current?.value - }) - setValuesStore(() => values as Values) - }, [inputProps]) + }, []) return [ inputProps, From 7fa0873fc8fb4cd5e377ca76643c8d8b57693af0 Mon Sep 17 00:00:00 2001 From: nicosammito Date: Tue, 22 Oct 2024 15:46:09 +0200 Subject: [PATCH 17/67] removing checkbox --- src/components/form/Input.stories.tsx | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/components/form/Input.stories.tsx b/src/components/form/Input.stories.tsx index de3e18e5..544ae737 100644 --- a/src/components/form/Input.stories.tsx +++ b/src/components/form/Input.stories.tsx @@ -44,16 +44,6 @@ export const Login = () => {
- } - right={} - {...inputs.checkbox} - /> -
Date: Tue, 22 Oct 2024 16:40:51 +0200 Subject: [PATCH 18/67] removing ref because of type conflicts --- src/components/form/useForm.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/form/useForm.ts b/src/components/form/useForm.ts index 7255e2e4..4d29647a 100644 --- a/src/components/form/useForm.ts +++ b/src/components/form/useForm.ts @@ -16,7 +16,8 @@ export interface ValidationProps { defaultValue?: Value valid?: boolean notValidMessage?: string | null - ref?: RefObject + //ref?: RefObject, + required?: boolean } export type ValidationsProps = Partial<{ From c323a22bcf80c8ee1710398067994869ae1279ef Mon Sep 17 00:00:00 2001 From: nicosammito Date: Tue, 22 Oct 2024 16:41:10 +0200 Subject: [PATCH 19/67] adding input type checking --- src/components/form/useForm.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/components/form/useForm.ts b/src/components/form/useForm.ts index 4d29647a..3a6ffb4c 100644 --- a/src/components/form/useForm.ts +++ b/src/components/form/useForm.ts @@ -43,7 +43,8 @@ const useForm = = Record>(props Object.entries(initialValues).map(([k, v], index) => { const inputRef: RefObject = refs[index] - const currentValue = inputRef.current?.value + const type = inputRef.current?.type ?? "text" + const currentValue = (type == "checkbox" || type == "radio") ? inputRef.current?.checked : inputRef.current?.value return { name: k, @@ -61,7 +62,8 @@ const useForm = = Record>(props defaultValue: item.value, notValidMessage: message, valid: message === null ? true : !message, - ref: refs[index] + ref: refs[index], + ...(!!validate ? {required: true} : {}) } }) From a66097661f5fa4a1110221ad70cfdd24cf8a37cc Mon Sep 17 00:00:00 2001 From: nicosammito Date: Tue, 22 Oct 2024 16:41:29 +0200 Subject: [PATCH 20/67] type problems --- src/components/form/Input.tsx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/components/form/Input.tsx b/src/components/form/Input.tsx index 7707ca34..0a8a4f12 100644 --- a/src/components/form/Input.tsx +++ b/src/components/form/Input.tsx @@ -1,4 +1,4 @@ -import {Code0Component, Color} from "../../utils/types"; +import {Code0Component} from "../../utils/types"; import React, {LegacyRef} from "react"; import {ValidationProps} from "./useForm"; import {mergeCode0Props} from "../../utils/utils"; @@ -7,7 +7,7 @@ import InputLabel from "./InputLabel"; import InputDescription from "./InputDescription"; import InputMessage from "./InputMessage"; -type Code0Input = Omit, "defaultValue">, "ref">, "left">, "right">, "label"> +type Code0Input = Omit, "defaultValue">, "left">, "right">, "label"> export interface InputProps extends Code0Input, ValidationProps { @@ -18,11 +18,10 @@ export interface InputProps extends Code0Input, ValidationProps { rightType?: "action" | "placeholder" | "icon" label?: React.ReactNode | React.ReactElement description?: React.ReactNode | React.ReactElement - color?: Color } -const Input: React.ForwardRefExoticComponent, "ref">> = React.forwardRef((props: InputProps, ref) => { +const Input: React.ForwardRefExoticComponent> = React.forwardRef((props: InputProps, ref) => { const { wrapperComponent = {}, From df84a289dfc685386346d58045df75ff51675e45 Mon Sep 17 00:00:00 2001 From: nicosammito Date: Tue, 22 Oct 2024 16:41:45 +0200 Subject: [PATCH 21/67] first implementation of password input --- src/components/form/Input.stories.tsx | 8 ++--- src/components/form/PasswordInput.tsx | 45 +++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 6 deletions(-) create mode 100644 src/components/form/PasswordInput.tsx diff --git a/src/components/form/Input.stories.tsx b/src/components/form/Input.stories.tsx index 544ae737..95f75d1f 100644 --- a/src/components/form/Input.stories.tsx +++ b/src/components/form/Input.stories.tsx @@ -6,6 +6,7 @@ import Button from "../button/Button"; import {IconEye, IconKey, IconLogin, IconMail, IconMinus, IconPlus, IconX} from "@tabler/icons-react"; import ButtonGroup from "../button-group/ButtonGroup"; import Text from "../Text/Text"; +import PasswordInput from "./PasswordInput"; export default { title: "Input", @@ -54,16 +55,11 @@ export const Login = () => { {...inputs.email} />
- } - right={ - - - } {...inputs.password} />
diff --git a/src/components/form/PasswordInput.tsx b/src/components/form/PasswordInput.tsx new file mode 100644 index 00000000..0b843e6f --- /dev/null +++ b/src/components/form/PasswordInput.tsx @@ -0,0 +1,45 @@ +import React, {RefObject} from "react"; +import Input, {InputProps} from "./Input"; +import ButtonGroup from "../button-group/ButtonGroup"; +import {IconEye, IconX} from "@tabler/icons-react"; +import Button from "../button/Button"; + +interface PasswordInputProps extends Omit, "wrapperComponent" | "right" | "rightType" | "type"> { + clearable?: boolean, + visible?: boolean +} + + +const PasswordInput: React.ForwardRefExoticComponent = React.forwardRef((props, ref: RefObject) => { + + const { + clearable = true, + visible = true, + ...rest + } = props + + const toClearable = () => { + if (ref.current) ref.current.value = "" + } + + const toVisible = () => { + if (ref.current && ref.current.type == "password") ref.current.type = "text" + else if (ref.current && ref.current.type == "text") ref.current.type = "password" + } + + const rightAction = clearable && visible ? + + + : clearable || visible ? : <> + + return + +}) + +export default PasswordInput \ No newline at end of file From 8d171d50158401b9c7bb9740f05b539285c94883 Mon Sep 17 00:00:00 2001 From: marius Date: Mon, 2 Sep 2024 09:00:02 +0200 Subject: [PATCH 22/67] feat: initialised new Input logic, validation hook --- src/components/input/Input.stories.tsx | 45 ++++++++++++++++ src/components/input/Input.tsx | 74 ++++++++++++++++++++++++++ src/components/input/useValidation.ts | 50 +++++++++++++++++ 3 files changed, 169 insertions(+) create mode 100644 src/components/input/Input.stories.tsx create mode 100644 src/components/input/Input.tsx create mode 100644 src/components/input/useValidation.ts diff --git a/src/components/input/Input.stories.tsx b/src/components/input/Input.stories.tsx new file mode 100644 index 00000000..5621dbf9 --- /dev/null +++ b/src/components/input/Input.stories.tsx @@ -0,0 +1,45 @@ +import React from "react"; +import {Input, InputWrapper} from "./Input"; +import {useValidation} from "./useValidation"; + +export default { + title: "Input", + component: Input +}; + +export const Default = () => { + const rules = [ + (value: string) => ({ + isValid: value.trim() !== "", + message: "Email is required" + }), + (value: string) => ({ + isValid: value.includes("@"), + message: "Email is invalid" + }) + ]; + + const { value, setValue, state, message, validateInput } = useValidation({ + validationRules: rules, + successMessage: "Email is valid" + }); + + return ( + + { + console.log(value); + setValue(value); + }} + onBlur={validateInput} + /> + + ); +} \ No newline at end of file diff --git a/src/components/input/Input.tsx b/src/components/input/Input.tsx new file mode 100644 index 00000000..2275ab70 --- /dev/null +++ b/src/components/input/Input.tsx @@ -0,0 +1,74 @@ +import React, {DetailedHTMLProps, InputHTMLAttributes, ReactElement, ReactNode, RefAttributes, useState} from "react"; +import "./Input.style.scss" +import {TablerIcon} from "@tabler/icons-react"; +import {Code0Component} from "../../utils/types"; + +export type InputState = { + value: boolean; + message: string; +} + +export interface InputType extends InputHTMLAttributes { + onValueChange?: (value: string) => void; + preValue?: string; +} + +export interface PinInputType { + +} + +export interface InputWrapperType { + label?: string; + description?: string; + success?: InputState; + warning?: InputState; + error?: InputState; + children: ReactNode; +} + +const Input: React.FC = ({ preValue, onValueChange, ...props }) => { + const [value, setValue] = useState(preValue || ""); + + const handleChange = (e: React.ChangeEvent) => { + const inputValue = e.target.value; + setValue(inputValue); + onValueChange?.(inputValue); + } + + return ( + + ); +} + +const PinInput: React.FC = () => { + return ( +
+
+ ); +} + +const InputWrapper: React.FC = ({ label, description, success, warning, error, children }) => { + return ( +
+ {label && } + {description &&

{description}

} + {children} + {success?.value &&

{success.message}

} + {warning?.value &&

{warning.message}

} + {error?.value &&

{error.message}

} +
+ ); +} + + +export { + Input as default, + PinInput, + InputWrapper +}; \ No newline at end of file diff --git a/src/components/input/useValidation.ts b/src/components/input/useValidation.ts new file mode 100644 index 00000000..1fe27b4f --- /dev/null +++ b/src/components/input/useValidation.ts @@ -0,0 +1,50 @@ +import {useCallback, useState} from "react"; + +export type ValidationRule = (value: string) => { + isValid: boolean; + message: string; +} + +type ValidationStatus = 'idle' | 'error' | 'warning' | 'success'; + +interface UseInputValidationProps { + //default value is empty string + initialValue?: string; + validationRules: ValidationRule[]; + //default is 0 + warningBuffer?: number; + successMessage?: string; + warningMessage?: string; +} + +export function useValidation({ initialValue = "", validationRules, warningBuffer = 0, successMessage, warningMessage }: UseInputValidationProps) { + const [value, setValue] = useState(initialValue); + const [state, setState] = useState('idle'); + const [message, setMessage] = useState(""); + + const validateInput = useCallback(() => { + if (!validationRules) return; + let errorCount = 0; + let errorMessage = ""; + + for (const rule of validationRules) { + const {isValid, message} = rule(value); + if (isValid) continue; + errorCount++; + if (!errorMessage) errorMessage = message; + } + + if (errorCount === 0) { + setState('success'); + setMessage(successMessage || 'Input is valid'); + } else if (errorCount <= warningBuffer && warningMessage) { + setState('warning'); + setMessage(warningMessage || 'Input is valid but with warnings'); + } else { + setState('error'); + setMessage(errorMessage.trim() === "" ? "Input is invalid" : errorMessage); + } + }, [successMessage, validationRules, value, warningBuffer, warningMessage]); + + return {value, setValue, state, message, validateInput}; +} \ No newline at end of file From 224d23078f0504ebaf6f1a6ca659273eea12bd48 Mon Sep 17 00:00:00 2001 From: Marius Ahsmus Date: Thu, 5 Sep 2024 16:28:35 +0200 Subject: [PATCH 23/67] feat: pin input logic --- src/components/input/Input.stories.tsx | 37 +++++++++++- src/components/input/Input.tsx | 82 ++++++++++++++++++++++---- 2 files changed, 105 insertions(+), 14 deletions(-) diff --git a/src/components/input/Input.stories.tsx b/src/components/input/Input.stories.tsx index 5621dbf9..6c42d7d7 100644 --- a/src/components/input/Input.stories.tsx +++ b/src/components/input/Input.stories.tsx @@ -1,5 +1,5 @@ import React from "react"; -import {Input, InputWrapper} from "./Input"; +import Input, {InputWrapper, PinInput} from "./Input"; import {useValidation} from "./useValidation"; export default { @@ -7,7 +7,7 @@ export default { component: Input }; -export const Default = () => { +export const DefaultInput = () => { const rules = [ (value: string) => ({ isValid: value.trim() !== "", @@ -42,4 +42,37 @@ export const Default = () => { /> ); +} + +export const DefaultPinInput = () => { + const rules = [ + (value: string) => ({ + isValid: value === "1234", + message: "Email is required" + }) + ]; + + const { value, setValue, state, message, validateInput } = useValidation({ + validationRules: rules, + successMessage: "Email is valid" + }); + + return ( + + { + console.log(value); + setValue(value); + }} + onBlur={validateInput} + /> + + ); } \ No newline at end of file diff --git a/src/components/input/Input.tsx b/src/components/input/Input.tsx index 2275ab70..a973800f 100644 --- a/src/components/input/Input.tsx +++ b/src/components/input/Input.tsx @@ -1,4 +1,12 @@ -import React, {DetailedHTMLProps, InputHTMLAttributes, ReactElement, ReactNode, RefAttributes, useState} from "react"; +import React, { + DetailedHTMLProps, + InputHTMLAttributes, + ReactElement, + ReactNode, + RefAttributes, useEffect, + useRef, + useState +} from "react"; import "./Input.style.scss" import {TablerIcon} from "@tabler/icons-react"; import {Code0Component} from "../../utils/types"; @@ -14,7 +22,10 @@ export interface InputType extends InputHTMLAttributes { } export interface PinInputType { - + value: string; + onValueChange?: (value: string) => void; + onBlur?: () => void; + preValue?: number[]; } export interface InputWrapperType { @@ -37,7 +48,7 @@ const Input: React.FC = ({ preValue, onValueChange, ...props }) => { return ( = ({ preValue, onValueChange, ...props }) => { ); } -const PinInput: React.FC = () => { +const PinInput: React.FC = ({ value, preValue, onValueChange, onBlur, ...props }) => { + const inputRefs = [useRef(null), useRef(null), useRef(null), useRef(null)]; + + useEffect(() => { + inputRefs[0].current?.focus(); + }, []); + + const focusNextInput = (currentIndex: number) => { + if (currentIndex < 3) { + inputRefs[currentIndex + 1].current?.focus(); + } else { + inputRefs[currentIndex].current?.blur(); + onBlur?.(); + } + }; + + const handleChange = (e: React.ChangeEvent, index: number) => { + const inputValue = e.target.value; + if (inputValue.length <= 1 && /^\d*$/.test(inputValue)) { + const newValue = value.split(''); + newValue[index] = inputValue; + onValueChange?.(newValue.join('')); + + if (inputValue.length === 1) { + focusNextInput(index); + } + } + } + + const handleKeyDown = (e: React.KeyboardEvent, index: number) => { + if (e.key === 'Backspace' && !value[index] && index > 0) { + inputRefs[index - 1].current?.focus(); + } + }; + return ( -
+
+ {inputRefs.map((ref, index) => ( + handleChange(e, index)} + onKeyDown={(e) => handleKeyDown(e, index)} + {...props} + /> + ))}
); } -const InputWrapper: React.FC = ({ label, description, success, warning, error, children }) => { +const InputWrapper: React.FC = ({label, description, success, warning, error, children}) => { return ( -
- {label && } - {description &&

{description}

} +
+ {label && } + {description &&

{description}

} {children} - {success?.value &&

{success.message}

} - {warning?.value &&

{warning.message}

} - {error?.value &&

{error.message}

} + {success?.value &&

{success.message}

} + {warning?.value &&

{warning.message}

} + {error?.value &&

{error.message}

}
); } From 070bb53949327c68b843061e3884210cb3902845 Mon Sep 17 00:00:00 2001 From: nicosammito Date: Tue, 8 Oct 2024 20:09:30 +0200 Subject: [PATCH 24/67] removed old input/form logic --- src/components/input/Input.tsx | 132 -------------------------- src/components/input/useValidation.ts | 50 ---------- 2 files changed, 182 deletions(-) delete mode 100644 src/components/input/Input.tsx delete mode 100644 src/components/input/useValidation.ts diff --git a/src/components/input/Input.tsx b/src/components/input/Input.tsx deleted file mode 100644 index a973800f..00000000 --- a/src/components/input/Input.tsx +++ /dev/null @@ -1,132 +0,0 @@ -import React, { - DetailedHTMLProps, - InputHTMLAttributes, - ReactElement, - ReactNode, - RefAttributes, useEffect, - useRef, - useState -} from "react"; -import "./Input.style.scss" -import {TablerIcon} from "@tabler/icons-react"; -import {Code0Component} from "../../utils/types"; - -export type InputState = { - value: boolean; - message: string; -} - -export interface InputType extends InputHTMLAttributes { - onValueChange?: (value: string) => void; - preValue?: string; -} - -export interface PinInputType { - value: string; - onValueChange?: (value: string) => void; - onBlur?: () => void; - preValue?: number[]; -} - -export interface InputWrapperType { - label?: string; - description?: string; - success?: InputState; - warning?: InputState; - error?: InputState; - children: ReactNode; -} - -const Input: React.FC = ({ preValue, onValueChange, ...props }) => { - const [value, setValue] = useState(preValue || ""); - - const handleChange = (e: React.ChangeEvent) => { - const inputValue = e.target.value; - setValue(inputValue); - onValueChange?.(inputValue); - } - - return ( - - ); -} - -const PinInput: React.FC = ({ value, preValue, onValueChange, onBlur, ...props }) => { - const inputRefs = [useRef(null), useRef(null), useRef(null), useRef(null)]; - - useEffect(() => { - inputRefs[0].current?.focus(); - }, []); - - const focusNextInput = (currentIndex: number) => { - if (currentIndex < 3) { - inputRefs[currentIndex + 1].current?.focus(); - } else { - inputRefs[currentIndex].current?.blur(); - onBlur?.(); - } - }; - - const handleChange = (e: React.ChangeEvent, index: number) => { - const inputValue = e.target.value; - if (inputValue.length <= 1 && /^\d*$/.test(inputValue)) { - const newValue = value.split(''); - newValue[index] = inputValue; - onValueChange?.(newValue.join('')); - - if (inputValue.length === 1) { - focusNextInput(index); - } - } - } - - const handleKeyDown = (e: React.KeyboardEvent, index: number) => { - if (e.key === 'Backspace' && !value[index] && index > 0) { - inputRefs[index - 1].current?.focus(); - } - }; - - return ( -
- {inputRefs.map((ref, index) => ( - handleChange(e, index)} - onKeyDown={(e) => handleKeyDown(e, index)} - {...props} - /> - ))} -
- ); -} - -const InputWrapper: React.FC = ({label, description, success, warning, error, children}) => { - return ( -
- {label && } - {description &&

{description}

} - {children} - {success?.value &&

{success.message}

} - {warning?.value &&

{warning.message}

} - {error?.value &&

{error.message}

} -
- ); -} - - -export { - Input as default, - PinInput, - InputWrapper -}; \ No newline at end of file diff --git a/src/components/input/useValidation.ts b/src/components/input/useValidation.ts deleted file mode 100644 index 1fe27b4f..00000000 --- a/src/components/input/useValidation.ts +++ /dev/null @@ -1,50 +0,0 @@ -import {useCallback, useState} from "react"; - -export type ValidationRule = (value: string) => { - isValid: boolean; - message: string; -} - -type ValidationStatus = 'idle' | 'error' | 'warning' | 'success'; - -interface UseInputValidationProps { - //default value is empty string - initialValue?: string; - validationRules: ValidationRule[]; - //default is 0 - warningBuffer?: number; - successMessage?: string; - warningMessage?: string; -} - -export function useValidation({ initialValue = "", validationRules, warningBuffer = 0, successMessage, warningMessage }: UseInputValidationProps) { - const [value, setValue] = useState(initialValue); - const [state, setState] = useState('idle'); - const [message, setMessage] = useState(""); - - const validateInput = useCallback(() => { - if (!validationRules) return; - let errorCount = 0; - let errorMessage = ""; - - for (const rule of validationRules) { - const {isValid, message} = rule(value); - if (isValid) continue; - errorCount++; - if (!errorMessage) errorMessage = message; - } - - if (errorCount === 0) { - setState('success'); - setMessage(successMessage || 'Input is valid'); - } else if (errorCount <= warningBuffer && warningMessage) { - setState('warning'); - setMessage(warningMessage || 'Input is valid but with warnings'); - } else { - setState('error'); - setMessage(errorMessage.trim() === "" ? "Input is invalid" : errorMessage); - } - }, [successMessage, validationRules, value, warningBuffer, warningMessage]); - - return {value, setValue, state, message, validateInput}; -} \ No newline at end of file From 43f4bf3e752e41d364e9d14c9a9c0c3c7328492f Mon Sep 17 00:00:00 2001 From: nicosammito Date: Tue, 8 Oct 2024 20:10:24 +0200 Subject: [PATCH 25/67] implemented useForm hook and test component --- src/components/form/Input.stories.tsx | 109 +++---------------------- src/components/form/useForm.ts | 82 ++++++++----------- src/components/input/Input.stories.tsx | 78 ------------------ 3 files changed, 46 insertions(+), 223 deletions(-) delete mode 100644 src/components/input/Input.stories.tsx diff --git a/src/components/form/Input.stories.tsx b/src/components/form/Input.stories.tsx index 95f75d1f..4e03b334 100644 --- a/src/components/form/Input.stories.tsx +++ b/src/components/form/Input.stories.tsx @@ -1,112 +1,29 @@ -import React from "react"; +import React, {forwardRef} from "react"; import useForm from "./useForm"; -import Input from "./Input"; -import Card from "../card/Card"; -import Button from "../button/Button"; -import {IconEye, IconKey, IconLogin, IconMail, IconMinus, IconPlus, IconX} from "@tabler/icons-react"; -import ButtonGroup from "../button-group/ButtonGroup"; -import Text from "../Text/Text"; -import PasswordInput from "./PasswordInput"; +const TestC: React.FC = forwardRef((props, ref) => { + console.log(props) + return +}) export default { title: "Input", - component: Input + component: TestC } -export const Login = () => { +export const Test = () => { const [inputs, validate] = useForm({ initialValues: { - email: null, - password: null, - checkbox: true + test: "test@" }, validate: { - email: (value) => { - if (!value) return "Email is required" - return null - }, - password: (value) => { - if (!value) return "Password is required" - return null - } - }, - onSubmit: (values) => { - console.log(values) + test: (value) => !value.includes("@") ? "Hier ist was falsch" : null } }) - return - Login -
- - Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et - dolore magna aliquyam erat, sed diam voluptua. - -
- - } - right={} - {...inputs.email} - /> -
- } - {...inputs.password} - /> -
-
- - -
- - -
- -} - -export const WebsiteInput = () => { - - return - } - /> - - -} - -export const NumberInput = () => { - - return - } - leftType={"action"} - right={} - /> - + return <> + + + } \ No newline at end of file diff --git a/src/components/form/useForm.ts b/src/components/form/useForm.ts index 3a6ffb4c..3b6e9bec 100644 --- a/src/components/form/useForm.ts +++ b/src/components/form/useForm.ts @@ -1,85 +1,69 @@ "use client" -import {RefObject, useCallback, useRef, useState} from "react"; +import {RefObject, useCallback, useMemo, useRef, useState} from "react"; export type Validations = Partial<{ [Key in keyof Values]: (value: Values[Key]) => string | null; }> -export interface FormValidationProps { +interface FormValidationProps { initialValues: Values - validate?: Validations, - onSubmit?: (values: Values) => void + validate?: Validations } -export interface ValidationProps { - defaultValue?: Value - valid?: boolean - notValidMessage?: string | null - //ref?: RefObject, - required?: boolean +interface ValidationProps { + value: Value + valid: boolean + notValidMessage: string | null + ref: RefObject } -export type ValidationsProps = Partial<{ +type ValidationsProps = Partial<{ [Key in keyof Values]: ValidationProps }> -export type FormValidationReturn = [ValidationsProps, () => void] - +type FormValidationReturn = [ValidationsProps, () => void] const useForm = = Record>(props: FormValidationProps): FormValidationReturn => { - const {initialValues, validate, onSubmit = () => {}} = props - - const refs = Object.entries(initialValues).map(() => useRef(null)) - const [inputProps, setInputProps] = useState>({}) + const {initialValues, validate} = props - const validateFunction = useCallback(() => { + const [valuesState, setValuesStore] = useState(initialValues) + const inputProps = useMemo>(() => { - let submittable = true let inputProps: ValidationsProps = {} - let submitProps: Object = {} - - Object.entries(initialValues).map(([k, v], index) => { - - const inputRef: RefObject = refs[index] - const type = inputRef.current?.type ?? "text" - const currentValue = (type == "checkbox" || type == "radio") ? inputRef.current?.checked : inputRef.current?.value - - return { - name: k, - value: currentValue as typeof v || undefined, - function: !!validate && !!validate[k] ? validate[k] : (value: typeof currentValue) => null - } - - }).forEach((item, index) => { - - const message = item.value !== null ? item.function(item.value) : null - submittable = submittable ? message === null ? true : !message : false + Object.entries(valuesState).map(([k, v]) => ({ + name: k, + initialValue: v, + function: !!validate && !!validate[k] ? validate[k] : (value: typeof v) => null + })).forEach(item => { Object.assign(inputProps, { [item.name]: { - defaultValue: item.value, - notValidMessage: message, - valid: message === null ? true : !message, - ref: refs[index], - ...(!!validate ? {required: true} : {}) + defaultValue: item.initialValue, + notValidMessage: item.function(item.initialValue), + valid: !item.function(item.initialValue), + ref: useRef(null) } }) + }) - Object.assign(submitProps, { - [item.name]: item.value - }) + return inputProps - }) + }, [valuesState]) - setInputProps(() => inputProps) + const validateFunction = useCallback(() => { - if (submittable) onSubmit(submitProps as Values) + let values: { [index: string]: any } = {...valuesState} + Object.entries(inputProps as ValidationsProps).forEach(([key, value]) => { + const inputRef: RefObject = value.ref + values[key] = inputRef.current?.value + }) + setValuesStore(values as Values) - }, []) + }, [inputProps]) return [ inputProps, diff --git a/src/components/input/Input.stories.tsx b/src/components/input/Input.stories.tsx deleted file mode 100644 index 6c42d7d7..00000000 --- a/src/components/input/Input.stories.tsx +++ /dev/null @@ -1,78 +0,0 @@ -import React from "react"; -import Input, {InputWrapper, PinInput} from "./Input"; -import {useValidation} from "./useValidation"; - -export default { - title: "Input", - component: Input -}; - -export const DefaultInput = () => { - const rules = [ - (value: string) => ({ - isValid: value.trim() !== "", - message: "Email is required" - }), - (value: string) => ({ - isValid: value.includes("@"), - message: "Email is invalid" - }) - ]; - - const { value, setValue, state, message, validateInput } = useValidation({ - validationRules: rules, - successMessage: "Email is valid" - }); - - return ( - - { - console.log(value); - setValue(value); - }} - onBlur={validateInput} - /> - - ); -} - -export const DefaultPinInput = () => { - const rules = [ - (value: string) => ({ - isValid: value === "1234", - message: "Email is required" - }) - ]; - - const { value, setValue, state, message, validateInput } = useValidation({ - validationRules: rules, - successMessage: "Email is valid" - }); - - return ( - - { - console.log(value); - setValue(value); - }} - onBlur={validateInput} - /> - - ); -} \ No newline at end of file From 92bd38894b42fe5e32b4aa44773b80fb4ad37d80 Mon Sep 17 00:00:00 2001 From: nicosammito Date: Thu, 10 Oct 2024 07:56:34 +0200 Subject: [PATCH 26/67] fiy for do not use a hook inside a hook warning --- src/components/form/useForm.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/components/form/useForm.ts b/src/components/form/useForm.ts index 3b6e9bec..f1007878 100644 --- a/src/components/form/useForm.ts +++ b/src/components/form/useForm.ts @@ -28,6 +28,7 @@ const useForm = = Record>(props const {initialValues, validate} = props + const refs = Object.entries(initialValues).map(() => useRef(null)) const [valuesState, setValuesStore] = useState(initialValues) const inputProps = useMemo>(() => { @@ -37,13 +38,13 @@ const useForm = = Record>(props name: k, initialValue: v, function: !!validate && !!validate[k] ? validate[k] : (value: typeof v) => null - })).forEach(item => { + })).forEach((item, index) => { Object.assign(inputProps, { [item.name]: { defaultValue: item.initialValue, notValidMessage: item.function(item.initialValue), valid: !item.function(item.initialValue), - ref: useRef(null) + ref: refs[index] } }) }) @@ -61,7 +62,7 @@ const useForm = = Record>(props values[key] = inputRef.current?.value }) - setValuesStore(values as Values) + setValuesStore(() => values as Values) }, [inputProps]) From 972268a0f4279a5c7677a7da61cae2f321c53496 Mon Sep 17 00:00:00 2001 From: nicosammito Date: Thu, 10 Oct 2024 14:07:39 +0200 Subject: [PATCH 27/67] new input component --- src/components/form/Input.stories.tsx | 68 ++++++++++++++++++++++----- src/components/form/Input.style.scss | 31 +++++------- src/components/form/Input.tsx | 27 +++++------ 3 files changed, 80 insertions(+), 46 deletions(-) diff --git a/src/components/form/Input.stories.tsx b/src/components/form/Input.stories.tsx index 4e03b334..e70fc0c5 100644 --- a/src/components/form/Input.stories.tsx +++ b/src/components/form/Input.stories.tsx @@ -1,29 +1,73 @@ -import React, {forwardRef} from "react"; +import React from "react"; import useForm from "./useForm"; +import Input from "./Input"; +import Card from "../card/Card"; +import Button from "../button/Button"; +import {IconEye, IconMail} from "@tabler/icons-react"; +import Select from "../select/Select"; +import {Text} from "../../index"; -const TestC: React.FC = forwardRef((props, ref) => { - console.log(props) - return -}) export default { title: "Input", - component: TestC + component: Input } export const Test = () => { const [inputs, validate] = useForm({ initialValues: { - test: "test@" + test: null }, validate: { - test: (value) => !value.includes("@") ? "Hier ist was falsch" : null + test: (value) => { + if (!value) return "Test is required" + return null + } } }) - return <> - - - + return +
+ } + left={ + + } + leftType={"action"} + rightType={"icon"} + label={"Email"} + description={"Provide a valid email address"} + type={"text"} + placeholder={"test"} + required + {...(inputs.test)}/> +
+ + + + + Fruits + + + + + + + + + } + rightType={"action"} + label={"Email"} + description={"Provide a valid email address"} + type={"text"} + placeholder={"test"} + required + {...(inputs.test)}/> +
+ + +
} \ No newline at end of file diff --git a/src/components/form/Input.style.scss b/src/components/form/Input.style.scss index 445a332b..e9cf4dce 100644 --- a/src/components/form/Input.style.scss +++ b/src/components/form/Input.style.scss @@ -2,12 +2,9 @@ .input { - $padding: $xs; - @include box(true, $primary); display: flex; - z-index: 1; - align-items: stretch; + align-items: center; &:has(&__control:focus) { @@ -20,7 +17,8 @@ &__left, &__right { display: flex; - align-items: stretch; + height: 100%; + align-items: center; &--action { padding: 0; @@ -28,22 +26,20 @@ &--placeholder { @include box(false, $secondary); - padding: $padding; + padding: $xxs; } } &__left { &--icon { - align-items: center; - padding: $padding 0 $padding $padding; + padding: $xxs 0 $xxs $xxs; } } &__right { &--icon { - align-items: center; - padding: $padding $padding $padding 0; + padding: $xxs $xxs $xxs 0; } } @@ -51,7 +47,7 @@ background: none; border: none; outline: none; - padding: $padding $padding; + padding: $xs $xxs; flex: 1; box-shadow: none; font-size: $sm; @@ -63,28 +59,25 @@ text-transform: uppercase; color: rgba($white, .5); font-size: $xs; - //margin: $padding 0; + margin: $xxs 0; display: block; } &__description { color: rgba($white, .5); font-size: $sm; - margin: $padding/2 0 $padding; + margin: $xxs 0; display: block; } &__message { @include box(false, $error); - border-top-right-radius: 0; - border-top-left-radius: 0; - padding: $padding * 2 $padding $padding; - top: -$padding; - z-index: 0; + padding: $xxs; + margin: $xxs 0; display: flex; align-items: center; font-size: $xs; - gap: $padding; + gap: $xxs; > svg { width: $xs; diff --git a/src/components/form/Input.tsx b/src/components/form/Input.tsx index 0a8a4f12..b27e82f5 100644 --- a/src/components/form/Input.tsx +++ b/src/components/form/Input.tsx @@ -1,5 +1,5 @@ -import {Code0Component} from "../../utils/types"; -import React, {LegacyRef} from "react"; +import {Code0Component, Color} from "../../utils/types"; +import React from "react"; import {ValidationProps} from "./useForm"; import {mergeCode0Props} from "../../utils/utils"; import "./Input.style.scss" @@ -7,24 +7,21 @@ import InputLabel from "./InputLabel"; import InputDescription from "./InputDescription"; import InputMessage from "./InputMessage"; -type Code0Input = Omit, "defaultValue">, "left">, "right">, "label"> +export interface InputProps extends Omit, "label">, ValidationProps { -export interface InputProps extends Code0Input, ValidationProps { - - wrapperComponent?: Code0Component right?: React.ReactNode | React.ReactElement left?: React.ReactNode | React.ReactElement leftType?: "action" | "placeholder" | "icon" rightType?: "action" | "placeholder" | "icon" label?: React.ReactNode | React.ReactElement description?: React.ReactNode | React.ReactElement + color?: Color } -const Input: React.ForwardRefExoticComponent> = React.forwardRef((props: InputProps, ref) => { +const Input: React.FC> = React.forwardRef((props: InputProps, ref) => { const { - wrapperComponent = {}, label, description, disabled = false, @@ -33,7 +30,7 @@ const Input: React.ForwardRefExoticComponent> = React.forwardRef leftType = "icon", rightType = "action", notValidMessage, - valid = true, + valid, ...rest } = props @@ -42,17 +39,17 @@ const Input: React.ForwardRefExoticComponent> = React.forwardRef {!!label ? : null} {!!description ? : null} -
+
- {!!left ?
+ {!!left ? {left} -
: null} + : null} - | undefined} {...mergeCode0Props("input__control", rest)}/> + - {!!right ?
+ {!!right ? {right} -
: null} + : null}
From 57fa00e1ad3941fe7c75847635a9eeb2b327c76e Mon Sep 17 00:00:00 2001 From: nicosammito Date: Thu, 10 Oct 2024 14:08:11 +0200 Subject: [PATCH 28/67] fixing some logic bugs inside the useForm hook and export interfaces and types --- src/components/form/useForm.ts | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/components/form/useForm.ts b/src/components/form/useForm.ts index f1007878..61963125 100644 --- a/src/components/form/useForm.ts +++ b/src/components/form/useForm.ts @@ -6,23 +6,23 @@ export type Validations = Partial<{ [Key in keyof Values]: (value: Values[Key]) => string | null; }> -interface FormValidationProps { +export interface FormValidationProps { initialValues: Values validate?: Validations } -interface ValidationProps { - value: Value - valid: boolean - notValidMessage: string | null - ref: RefObject +export interface ValidationProps { + defaultValue?: Value + valid?: boolean + notValidMessage?: string | null + ref?: RefObject } -type ValidationsProps = Partial<{ +export type ValidationsProps = Partial<{ [Key in keyof Values]: ValidationProps }> -type FormValidationReturn = [ValidationsProps, () => void] +export type FormValidationReturn = [ValidationsProps, () => void] const useForm = = Record>(props: FormValidationProps): FormValidationReturn => { @@ -39,11 +39,14 @@ const useForm = = Record>(props initialValue: v, function: !!validate && !!validate[k] ? validate[k] : (value: typeof v) => null })).forEach((item, index) => { + + const message = item.initialValue !== null ? item.function(item.initialValue) : null + Object.assign(inputProps, { [item.name]: { defaultValue: item.initialValue, - notValidMessage: item.function(item.initialValue), - valid: !item.function(item.initialValue), + notValidMessage: message, + valid: message === null ? true : !message, ref: refs[index] } }) From cb8957a3c9f5ef3ecd46b72770aebcfcab62e1fb Mon Sep 17 00:00:00 2001 From: nicosammito Date: Thu, 10 Oct 2024 22:52:23 +0200 Subject: [PATCH 29/67] changing padding to xs --- src/components/form/Input.style.scss | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/components/form/Input.style.scss b/src/components/form/Input.style.scss index e9cf4dce..1ebf9790 100644 --- a/src/components/form/Input.style.scss +++ b/src/components/form/Input.style.scss @@ -2,6 +2,8 @@ .input { + $padding: $xs; + @include box(true, $primary); display: flex; align-items: center; From 6dadc66d0a302b7c63ed58355280e1a4d8f1c20f Mon Sep 17 00:00:00 2001 From: nicosammito Date: Thu, 10 Oct 2024 22:52:48 +0200 Subject: [PATCH 30/67] stretching left and right items to fit into input --- src/components/form/Input.style.scss | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/components/form/Input.style.scss b/src/components/form/Input.style.scss index 1ebf9790..f20b2189 100644 --- a/src/components/form/Input.style.scss +++ b/src/components/form/Input.style.scss @@ -6,7 +6,7 @@ @include box(true, $primary); display: flex; - align-items: center; + align-items: stretch; &:has(&__control:focus) { @@ -19,8 +19,8 @@ &__left, &__right { display: flex; - height: 100%; - align-items: center; + align-items: stretch; + &--action { padding: 0; @@ -28,20 +28,20 @@ &--placeholder { @include box(false, $secondary); - padding: $xxs; + padding: $padding; } } &__left { &--icon { - padding: $xxs 0 $xxs $xxs; + padding: $padding 0 $padding $padding; } } &__right { &--icon { - padding: $xxs $xxs $xxs 0; + padding: $padding $padding $padding 0; } } @@ -49,7 +49,7 @@ background: none; border: none; outline: none; - padding: $xs $xxs; + padding: $padding $padding; flex: 1; box-shadow: none; font-size: $sm; @@ -61,25 +61,25 @@ text-transform: uppercase; color: rgba($white, .5); font-size: $xs; - margin: $xxs 0; + margin: $padding 0; display: block; } &__description { color: rgba($white, .5); font-size: $sm; - margin: $xxs 0; + margin: $padding 0; display: block; } &__message { @include box(false, $error); - padding: $xxs; - margin: $xxs 0; + padding: $padding; + margin: $padding 0; display: flex; align-items: center; font-size: $xs; - gap: $xxs; + gap: $padding; > svg { width: $xs; From db4a943d5f62c9cc0688d9dc883677e70faebe54 Mon Sep 17 00:00:00 2001 From: nicosammito Date: Thu, 10 Oct 2024 22:53:04 +0200 Subject: [PATCH 31/67] fixing type errors and conflicts --- src/components/form/Input.tsx | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/components/form/Input.tsx b/src/components/form/Input.tsx index b27e82f5..7456c856 100644 --- a/src/components/form/Input.tsx +++ b/src/components/form/Input.tsx @@ -1,5 +1,5 @@ import {Code0Component, Color} from "../../utils/types"; -import React from "react"; +import React, {LegacyRef} from "react"; import {ValidationProps} from "./useForm"; import {mergeCode0Props} from "../../utils/utils"; import "./Input.style.scss" @@ -7,7 +7,9 @@ import InputLabel from "./InputLabel"; import InputDescription from "./InputDescription"; import InputMessage from "./InputMessage"; -export interface InputProps extends Omit, "label">, ValidationProps { +type Code0Input = Omit, "defaultValue">, "ref">, "left">, "right">, "label"> + +export interface InputProps extends Code0Input, ValidationProps { right?: React.ReactNode | React.ReactElement left?: React.ReactNode | React.ReactElement @@ -19,7 +21,7 @@ export interface InputProps extends Omit, "l } -const Input: React.FC> = React.forwardRef((props: InputProps, ref) => { +const Input: React.ForwardRefExoticComponent, "ref">> = React.forwardRef((props: InputProps, ref) => { const { label, @@ -41,15 +43,15 @@ const Input: React.FC> = React.forwardRef((props: InputProps - {!!left ? + {!!left ?
{left} - : null} +
: null} - + | undefined} {...mergeCode0Props("input__control", rest)}/> - {!!right ? + {!!right ?
{right} - : null} +
: null}
From 9ee0ac6db84ae84c4428df23afb20162cc819be4 Mon Sep 17 00:00:00 2001 From: nicosammito Date: Tue, 22 Oct 2024 15:44:17 +0200 Subject: [PATCH 32/67] adding wrapper styling option --- src/components/form/Input.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/components/form/Input.tsx b/src/components/form/Input.tsx index 7456c856..7707ca34 100644 --- a/src/components/form/Input.tsx +++ b/src/components/form/Input.tsx @@ -11,6 +11,7 @@ type Code0Input = Omit, "de export interface InputProps extends Code0Input, ValidationProps { + wrapperComponent?: Code0Component right?: React.ReactNode | React.ReactElement left?: React.ReactNode | React.ReactElement leftType?: "action" | "placeholder" | "icon" @@ -24,6 +25,7 @@ export interface InputProps extends Code0Input, ValidationProps { const Input: React.ForwardRefExoticComponent, "ref">> = React.forwardRef((props: InputProps, ref) => { const { + wrapperComponent = {}, label, description, disabled = false, @@ -32,7 +34,7 @@ const Input: React.ForwardRefExoticComponent, "ref">> = Rea leftType = "icon", rightType = "action", notValidMessage, - valid, + valid = true, ...rest } = props @@ -41,7 +43,7 @@ const Input: React.ForwardRefExoticComponent, "ref">> = Rea {!!label ? : null} {!!description ? : null} -
+
{!!left ?
{left} From e01df7162e753516644ae5a9d3943db40a99d4ac Mon Sep 17 00:00:00 2001 From: nicosammito Date: Tue, 22 Oct 2024 15:44:44 +0200 Subject: [PATCH 33/67] examples --- src/components/form/Input.stories.tsx | 135 ++++++++++++++++++-------- 1 file changed, 94 insertions(+), 41 deletions(-) diff --git a/src/components/form/Input.stories.tsx b/src/components/form/Input.stories.tsx index e70fc0c5..de3e18e5 100644 --- a/src/components/form/Input.stories.tsx +++ b/src/components/form/Input.stories.tsx @@ -3,71 +3,124 @@ import useForm from "./useForm"; import Input from "./Input"; import Card from "../card/Card"; import Button from "../button/Button"; -import {IconEye, IconMail} from "@tabler/icons-react"; -import Select from "../select/Select"; -import {Text} from "../../index"; +import {IconEye, IconKey, IconLogin, IconMail, IconMinus, IconPlus, IconX} from "@tabler/icons-react"; +import ButtonGroup from "../button-group/ButtonGroup"; +import Text from "../Text/Text"; export default { title: "Input", component: Input } -export const Test = () => { +export const Login = () => { const [inputs, validate] = useForm({ initialValues: { - test: null + email: null, + password: null, + checkbox: true }, validate: { - test: (value) => { - if (!value) return "Test is required" + email: (value) => { + if (!value) return "Email is required" + return null + }, + password: (value) => { + if (!value) return "Password is required" return null } + }, + onSubmit: (values) => { + console.log(values) } }) - return + return + Login +
+ + Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et + dolore magna aliquyam erat, sed diam voluptua. + +
} - left={ - - } - leftType={"action"} - rightType={"icon"} + placeholder={"Email"} label={"Email"} - description={"Provide a valid email address"} - type={"text"} - placeholder={"test"} - required - {...(inputs.test)}/> + type={"checkbox"} + description={"Your Email address for login"} + left={} + right={} + {...inputs.checkbox} + />
- - - - Fruits - - - - - - - - - } - rightType={"action"} + placeholder={"Email"} label={"Email"} - description={"Provide a valid email address"} - type={"text"} - placeholder={"test"} - required - {...(inputs.test)}/> + type={"email"} + description={"Your Email address for login"} + left={} + right={} + {...inputs.email} + /> +
+ } + right={ + + + } + {...inputs.password} + />
- +
+ + +
+
+} + +export const WebsiteInput = () => { + + return + } + /> + + +} + +export const NumberInput = () => { + + return + } + leftType={"action"} + right={} + /> + + } \ No newline at end of file From 2ea922db6254cad3fac8a01f0ad933d12e0c6758 Mon Sep 17 00:00:00 2001 From: nicosammito Date: Tue, 22 Oct 2024 15:44:56 +0200 Subject: [PATCH 34/67] styling --- src/components/form/Input.style.scss | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/components/form/Input.style.scss b/src/components/form/Input.style.scss index f20b2189..445a332b 100644 --- a/src/components/form/Input.style.scss +++ b/src/components/form/Input.style.scss @@ -6,6 +6,7 @@ @include box(true, $primary); display: flex; + z-index: 1; align-items: stretch; @@ -21,7 +22,6 @@ display: flex; align-items: stretch; - &--action { padding: 0; } @@ -35,12 +35,14 @@ &__left { &--icon { + align-items: center; padding: $padding 0 $padding $padding; } } &__right { &--icon { + align-items: center; padding: $padding $padding $padding 0; } } @@ -61,21 +63,24 @@ text-transform: uppercase; color: rgba($white, .5); font-size: $xs; - margin: $padding 0; + //margin: $padding 0; display: block; } &__description { color: rgba($white, .5); font-size: $sm; - margin: $padding 0; + margin: $padding/2 0 $padding; display: block; } &__message { @include box(false, $error); - padding: $padding; - margin: $padding 0; + border-top-right-radius: 0; + border-top-left-radius: 0; + padding: $padding * 2 $padding $padding; + top: -$padding; + z-index: 0; display: flex; align-items: center; font-size: $xs; From b9ee2aef455bb310bb2106aad98ae0cdc585e74f Mon Sep 17 00:00:00 2001 From: nicosammito Date: Tue, 22 Oct 2024 15:45:25 +0200 Subject: [PATCH 35/67] better performance of useForm hook and added onSubmit function --- src/components/form/useForm.ts | 55 ++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/src/components/form/useForm.ts b/src/components/form/useForm.ts index 61963125..7255e2e4 100644 --- a/src/components/form/useForm.ts +++ b/src/components/form/useForm.ts @@ -1,6 +1,6 @@ "use client" -import {RefObject, useCallback, useMemo, useRef, useState} from "react"; +import {RefObject, useCallback, useRef, useState} from "react"; export type Validations = Partial<{ [Key in keyof Values]: (value: Values[Key]) => string | null; @@ -8,7 +8,8 @@ export type Validations = Partial<{ export interface FormValidationProps { initialValues: Values - validate?: Validations + validate?: Validations, + onSubmit?: (values: Values) => void } export interface ValidationProps { @@ -24,50 +25,58 @@ export type ValidationsProps = Partial<{ export type FormValidationReturn = [ValidationsProps, () => void] + const useForm = = Record>(props: FormValidationProps): FormValidationReturn => { - const {initialValues, validate} = props + const {initialValues, validate, onSubmit = () => {}} = props const refs = Object.entries(initialValues).map(() => useRef(null)) - const [valuesState, setValuesStore] = useState(initialValues) - const inputProps = useMemo>(() => { + const [inputProps, setInputProps] = useState>({}) + + const validateFunction = useCallback(() => { + let submittable = true let inputProps: ValidationsProps = {} + let submitProps: Object = {} + + Object.entries(initialValues).map(([k, v], index) => { + + const inputRef: RefObject = refs[index] + const currentValue = inputRef.current?.value + + return { + name: k, + value: currentValue as typeof v || undefined, + function: !!validate && !!validate[k] ? validate[k] : (value: typeof currentValue) => null + } - Object.entries(valuesState).map(([k, v]) => ({ - name: k, - initialValue: v, - function: !!validate && !!validate[k] ? validate[k] : (value: typeof v) => null - })).forEach((item, index) => { + }).forEach((item, index) => { - const message = item.initialValue !== null ? item.function(item.initialValue) : null + const message = item.value !== null ? item.function(item.value) : null + submittable = submittable ? message === null ? true : !message : false Object.assign(inputProps, { [item.name]: { - defaultValue: item.initialValue, + defaultValue: item.value, notValidMessage: message, valid: message === null ? true : !message, ref: refs[index] } }) - }) - return inputProps + Object.assign(submitProps, { + [item.name]: item.value + }) - }, [valuesState]) + }) - const validateFunction = useCallback(() => { + setInputProps(() => inputProps) - let values: { [index: string]: any } = {...valuesState} + if (submittable) onSubmit(submitProps as Values) - Object.entries(inputProps as ValidationsProps).forEach(([key, value]) => { - const inputRef: RefObject = value.ref - values[key] = inputRef.current?.value - }) - setValuesStore(() => values as Values) - }, [inputProps]) + }, []) return [ inputProps, From 227bb02ec4b40baf01961bc9f5812c75335034dd Mon Sep 17 00:00:00 2001 From: nicosammito Date: Tue, 22 Oct 2024 15:46:09 +0200 Subject: [PATCH 36/67] removing checkbox --- src/components/form/Input.stories.tsx | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/components/form/Input.stories.tsx b/src/components/form/Input.stories.tsx index de3e18e5..544ae737 100644 --- a/src/components/form/Input.stories.tsx +++ b/src/components/form/Input.stories.tsx @@ -44,16 +44,6 @@ export const Login = () => {
- } - right={} - {...inputs.checkbox} - /> -
Date: Tue, 22 Oct 2024 16:40:51 +0200 Subject: [PATCH 37/67] removing ref because of type conflicts --- src/components/form/useForm.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/form/useForm.ts b/src/components/form/useForm.ts index 7255e2e4..4d29647a 100644 --- a/src/components/form/useForm.ts +++ b/src/components/form/useForm.ts @@ -16,7 +16,8 @@ export interface ValidationProps { defaultValue?: Value valid?: boolean notValidMessage?: string | null - ref?: RefObject + //ref?: RefObject, + required?: boolean } export type ValidationsProps = Partial<{ From 83dbad0c47869c2a4ccda29b5b572af58c781e47 Mon Sep 17 00:00:00 2001 From: nicosammito Date: Tue, 22 Oct 2024 16:41:10 +0200 Subject: [PATCH 38/67] adding input type checking --- src/components/form/useForm.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/components/form/useForm.ts b/src/components/form/useForm.ts index 4d29647a..3a6ffb4c 100644 --- a/src/components/form/useForm.ts +++ b/src/components/form/useForm.ts @@ -43,7 +43,8 @@ const useForm = = Record>(props Object.entries(initialValues).map(([k, v], index) => { const inputRef: RefObject = refs[index] - const currentValue = inputRef.current?.value + const type = inputRef.current?.type ?? "text" + const currentValue = (type == "checkbox" || type == "radio") ? inputRef.current?.checked : inputRef.current?.value return { name: k, @@ -61,7 +62,8 @@ const useForm = = Record>(props defaultValue: item.value, notValidMessage: message, valid: message === null ? true : !message, - ref: refs[index] + ref: refs[index], + ...(!!validate ? {required: true} : {}) } }) From eaf2e1a98b739b0747af7a64b23016d44c79644b Mon Sep 17 00:00:00 2001 From: nicosammito Date: Tue, 22 Oct 2024 16:41:29 +0200 Subject: [PATCH 39/67] type problems --- src/components/form/Input.tsx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/components/form/Input.tsx b/src/components/form/Input.tsx index 7707ca34..0a8a4f12 100644 --- a/src/components/form/Input.tsx +++ b/src/components/form/Input.tsx @@ -1,4 +1,4 @@ -import {Code0Component, Color} from "../../utils/types"; +import {Code0Component} from "../../utils/types"; import React, {LegacyRef} from "react"; import {ValidationProps} from "./useForm"; import {mergeCode0Props} from "../../utils/utils"; @@ -7,7 +7,7 @@ import InputLabel from "./InputLabel"; import InputDescription from "./InputDescription"; import InputMessage from "./InputMessage"; -type Code0Input = Omit, "defaultValue">, "ref">, "left">, "right">, "label"> +type Code0Input = Omit, "defaultValue">, "left">, "right">, "label"> export interface InputProps extends Code0Input, ValidationProps { @@ -18,11 +18,10 @@ export interface InputProps extends Code0Input, ValidationProps { rightType?: "action" | "placeholder" | "icon" label?: React.ReactNode | React.ReactElement description?: React.ReactNode | React.ReactElement - color?: Color } -const Input: React.ForwardRefExoticComponent, "ref">> = React.forwardRef((props: InputProps, ref) => { +const Input: React.ForwardRefExoticComponent> = React.forwardRef((props: InputProps, ref) => { const { wrapperComponent = {}, From 1ef59802d2b5a463a32b88cc4b3735f5a0652a9c Mon Sep 17 00:00:00 2001 From: nicosammito Date: Tue, 22 Oct 2024 16:41:45 +0200 Subject: [PATCH 40/67] first implementation of password input --- src/components/form/Input.stories.tsx | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/components/form/Input.stories.tsx b/src/components/form/Input.stories.tsx index 544ae737..95f75d1f 100644 --- a/src/components/form/Input.stories.tsx +++ b/src/components/form/Input.stories.tsx @@ -6,6 +6,7 @@ import Button from "../button/Button"; import {IconEye, IconKey, IconLogin, IconMail, IconMinus, IconPlus, IconX} from "@tabler/icons-react"; import ButtonGroup from "../button-group/ButtonGroup"; import Text from "../Text/Text"; +import PasswordInput from "./PasswordInput"; export default { title: "Input", @@ -54,16 +55,11 @@ export const Login = () => { {...inputs.email} />
- } - right={ - - - } {...inputs.password} />
From 357083b3da3450d12266097bd1b3d489eb9c2476 Mon Sep 17 00:00:00 2001 From: nicosammito Date: Sun, 27 Oct 2024 17:27:55 +0100 Subject: [PATCH 41/67] allow also array of elements on sides --- src/components/form/Input.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/form/Input.tsx b/src/components/form/Input.tsx index 0a8a4f12..0aec6ae7 100644 --- a/src/components/form/Input.tsx +++ b/src/components/form/Input.tsx @@ -12,8 +12,8 @@ type Code0Input = Omit, "default export interface InputProps extends Code0Input, ValidationProps { wrapperComponent?: Code0Component - right?: React.ReactNode | React.ReactElement - left?: React.ReactNode | React.ReactElement + right?: React.ReactNode | React.ReactElement | React.ReactElement[] + left?: React.ReactNode | React.ReactElement | React.ReactElement[] leftType?: "action" | "placeholder" | "icon" rightType?: "action" | "placeholder" | "icon" label?: React.ReactNode | React.ReactElement From 551f581553cd1bf8bf06a27f863a0794d470f686 Mon Sep 17 00:00:00 2001 From: nicosammito Date: Sun, 27 Oct 2024 17:28:35 +0100 Subject: [PATCH 42/67] adding possibility to control type and add right elements --- src/components/form/PasswordInput.tsx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/components/form/PasswordInput.tsx b/src/components/form/PasswordInput.tsx index 0b843e6f..ff17c4d8 100644 --- a/src/components/form/PasswordInput.tsx +++ b/src/components/form/PasswordInput.tsx @@ -1,10 +1,9 @@ import React, {RefObject} from "react"; import Input, {InputProps} from "./Input"; -import ButtonGroup from "../button-group/ButtonGroup"; import {IconEye, IconX} from "@tabler/icons-react"; import Button from "../button/Button"; -interface PasswordInputProps extends Omit, "wrapperComponent" | "right" | "rightType" | "type"> { +interface PasswordInputProps extends Omit, "wrapperComponent" | "type"> { clearable?: boolean, visible?: boolean } @@ -15,6 +14,7 @@ const PasswordInput: React.ForwardRefExoticComponent = React const { clearable = true, visible = true, + right, ...rest } = props @@ -27,10 +27,10 @@ const PasswordInput: React.ForwardRefExoticComponent = React else if (ref.current && ref.current.type == "text") ref.current.type = "password" } - const rightAction = clearable && visible ? - - - : clearable || visible ? : <> + const rightAction = [right] + visible && rightAction.push() + clearable && rightAction.push() + return Date: Sun, 27 Oct 2024 17:50:20 +0100 Subject: [PATCH 43/67] adding support for TextInput --- src/components/form/Input.stories.tsx | 5 ++-- src/components/form/TextInput.tsx | 37 +++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 src/components/form/TextInput.tsx diff --git a/src/components/form/Input.stories.tsx b/src/components/form/Input.stories.tsx index 95f75d1f..732bca2e 100644 --- a/src/components/form/Input.stories.tsx +++ b/src/components/form/Input.stories.tsx @@ -7,6 +7,7 @@ import {IconEye, IconKey, IconLogin, IconMail, IconMinus, IconPlus, IconX} from import ButtonGroup from "../button-group/ButtonGroup"; import Text from "../Text/Text"; import PasswordInput from "./PasswordInput"; +import TextInput from "./TextInput"; export default { title: "Input", @@ -82,14 +83,14 @@ export const Login = () => { export const WebsiteInput = () => { return - } /> diff --git a/src/components/form/TextInput.tsx b/src/components/form/TextInput.tsx new file mode 100644 index 00000000..0e5aee79 --- /dev/null +++ b/src/components/form/TextInput.tsx @@ -0,0 +1,37 @@ +import React, {RefObject} from "react"; +import Input, {InputProps} from "./Input"; +import {IconX} from "@tabler/icons-react"; +import Button from "../button/Button"; + + +interface TextInputProps extends Omit, "wrapperComponent" | "type"> { + //defaults to false + clearable?: boolean +} + +const TextInput: React.ForwardRefExoticComponent = React.forwardRef((props, ref: RefObject) => { + + const { + clearable = false, + right, + ...rest + } = props + + const toClearable = () => { + if (ref.current) ref.current.value = "" + } + + const rightAction = [right] + clearable && rightAction.push() + + + return + +}) + +export default TextInput \ No newline at end of file From 40f86f13cf95361a6bb865dacb6b2d4ce89712e4 Mon Sep 17 00:00:00 2001 From: nicosammito Date: Sun, 27 Oct 2024 18:46:15 +0100 Subject: [PATCH 44/67] feat: add EmailInput and function for email validation --- src/components/form/EmailInput.tsx | 44 ++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 src/components/form/EmailInput.tsx diff --git a/src/components/form/EmailInput.tsx b/src/components/form/EmailInput.tsx new file mode 100644 index 00000000..6429ce12 --- /dev/null +++ b/src/components/form/EmailInput.tsx @@ -0,0 +1,44 @@ +import React, {RefObject} from "react"; +import Input, {InputProps} from "./Input"; +import {IconX} from "@tabler/icons-react"; +import Button from "../button/Button"; + +/** + * This regex is based on the validation behind the type="email" validation of html. + * This can be used as the validation for email input + */ +const EMAIL_REGEX = /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/ + +interface EmailInputProps extends Omit, "wrapperComponent" | "type"> { + //defaults to false + clearable?: boolean +} + +export const emailValidation = (email: string) => EMAIL_REGEX.test(email) + +const EmailInput: React.ForwardRefExoticComponent = React.forwardRef((props, ref: RefObject) => { + + const { + clearable = false, + right, + ...rest + } = props + + const toClearable = () => { + if (ref.current) ref.current.value = "" + } + + const rightAction = [right] + clearable && rightAction.push() + + + return + +}) + +export default EmailInput \ No newline at end of file From 9931467fe05666c185e57bd23d747a1a1b7d7b25 Mon Sep 17 00:00:00 2001 From: nicosammito Date: Sun, 27 Oct 2024 18:46:54 +0100 Subject: [PATCH 45/67] test: replaced normal Input with EmailInput --- src/components/form/Input.stories.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/form/Input.stories.tsx b/src/components/form/Input.stories.tsx index 732bca2e..615b0ac2 100644 --- a/src/components/form/Input.stories.tsx +++ b/src/components/form/Input.stories.tsx @@ -3,11 +3,11 @@ import useForm from "./useForm"; import Input from "./Input"; import Card from "../card/Card"; import Button from "../button/Button"; -import {IconEye, IconKey, IconLogin, IconMail, IconMinus, IconPlus, IconX} from "@tabler/icons-react"; -import ButtonGroup from "../button-group/ButtonGroup"; +import {IconKey, IconLogin, IconMail, IconMinus, IconPlus} from "@tabler/icons-react"; import Text from "../Text/Text"; import PasswordInput from "./PasswordInput"; import TextInput from "./TextInput"; +import EmailInput, {emailValidation} from "./EmailInput"; export default { title: "Input", @@ -25,6 +25,7 @@ export const Login = () => { validate: { email: (value) => { if (!value) return "Email is required" + if (!emailValidation(value)) return "Please provide a valid email" return null }, password: (value) => { @@ -46,13 +47,12 @@ export const Login = () => {
- } - right={} {...inputs.email} />
From 25a3e3534649d959c76ec730c5f0ee69a10d9173 Mon Sep 17 00:00:00 2001 From: nicosammito Date: Mon, 28 Oct 2024 14:17:55 +0100 Subject: [PATCH 46/67] fix: when no ref is provided we should create our own in the component --- src/components/form/EmailInput.tsx | 2 ++ src/components/form/PasswordInput.tsx | 2 ++ src/components/form/TextInput.tsx | 2 ++ 3 files changed, 6 insertions(+) diff --git a/src/components/form/EmailInput.tsx b/src/components/form/EmailInput.tsx index 6429ce12..b1545e76 100644 --- a/src/components/form/EmailInput.tsx +++ b/src/components/form/EmailInput.tsx @@ -18,6 +18,8 @@ export const emailValidation = (email: string) => EMAIL_REGEX.test(email) const EmailInput: React.ForwardRefExoticComponent = React.forwardRef((props, ref: RefObject) => { + ref = ref || React.useRef(null) + const { clearable = false, right, diff --git a/src/components/form/PasswordInput.tsx b/src/components/form/PasswordInput.tsx index ff17c4d8..e63193e9 100644 --- a/src/components/form/PasswordInput.tsx +++ b/src/components/form/PasswordInput.tsx @@ -11,6 +11,8 @@ interface PasswordInputProps extends Omit, "wrapperCom const PasswordInput: React.ForwardRefExoticComponent = React.forwardRef((props, ref: RefObject) => { + ref = ref || React.useRef(null) + const { clearable = true, visible = true, diff --git a/src/components/form/TextInput.tsx b/src/components/form/TextInput.tsx index 0e5aee79..c21cb897 100644 --- a/src/components/form/TextInput.tsx +++ b/src/components/form/TextInput.tsx @@ -11,6 +11,8 @@ interface TextInputProps extends Omit, "wrapperCompone const TextInput: React.ForwardRefExoticComponent = React.forwardRef((props, ref: RefObject) => { + ref = ref || React.useRef(null) + const { clearable = false, right, From cd278ee9446ad7959b733604ac362e07b52b4565 Mon Sep 17 00:00:00 2001 From: nicosammito Date: Mon, 28 Oct 2024 14:18:24 +0100 Subject: [PATCH 47/67] fix: providing initial input props so ref will work --- src/components/form/useForm.ts | 37 +++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/src/components/form/useForm.ts b/src/components/form/useForm.ts index 3a6ffb4c..89c14698 100644 --- a/src/components/form/useForm.ts +++ b/src/components/form/useForm.ts @@ -26,13 +26,48 @@ export type ValidationsProps = Partial<{ export type FormValidationReturn = [ValidationsProps, () => void] +const createInitialInputProps = = Record>(props: FormValidationProps, refs: RefObject[]) => { + + const {initialValues, validate} = props + + let inputProps: ValidationsProps = {} + + Object.entries(initialValues).map(([k, v], index) => { + + const inputRef: RefObject = refs[index] + const type = inputRef.current?.type ?? "text" + const currentValue = (type == "checkbox" || type == "radio") ? inputRef.current?.checked : inputRef.current?.value + + return { + name: k, + value: currentValue as typeof v || undefined, + function: !!validate && !!validate[k] ? validate[k] : (value: typeof currentValue) => null + } + + }).forEach((item, index) => { + + Object.assign(inputProps, { + [item.name]: { + defaultValue: item.value, + //notValidMessage: message, + //valid: message === null ? true : !message, + ref: refs[index], + ...(!!validate ? {required: true} : {}) + } + }) + + }) + + return inputProps + +} const useForm = = Record>(props: FormValidationProps): FormValidationReturn => { const {initialValues, validate, onSubmit = () => {}} = props const refs = Object.entries(initialValues).map(() => useRef(null)) - const [inputProps, setInputProps] = useState>({}) + const [inputProps, setInputProps] = useState>(createInitialInputProps(props, refs)) const validateFunction = useCallback(() => { From 7ee0b94a81195b94c31427a00875114ef47d12d5 Mon Sep 17 00:00:00 2001 From: nicosammito Date: Mon, 28 Oct 2024 14:18:38 +0100 Subject: [PATCH 48/67] feat: new input component --- src/components/form/Input.stories.tsx | 13 +++----- src/components/form/NumberInput.tsx | 47 +++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 8 deletions(-) create mode 100644 src/components/form/NumberInput.tsx diff --git a/src/components/form/Input.stories.tsx b/src/components/form/Input.stories.tsx index 615b0ac2..af92fd04 100644 --- a/src/components/form/Input.stories.tsx +++ b/src/components/form/Input.stories.tsx @@ -3,11 +3,12 @@ import useForm from "./useForm"; import Input from "./Input"; import Card from "../card/Card"; import Button from "../button/Button"; -import {IconKey, IconLogin, IconMail, IconMinus, IconPlus} from "@tabler/icons-react"; +import {IconKey, IconLogin, IconMail} from "@tabler/icons-react"; import Text from "../Text/Text"; import PasswordInput from "./PasswordInput"; import TextInput from "./TextInput"; import EmailInput, {emailValidation} from "./EmailInput"; +import NumberInput from "./NumberInput"; export default { title: "Input", @@ -80,7 +81,7 @@ export const Login = () => { } -export const WebsiteInput = () => { +export const Website = () => { return { } -export const NumberInput = () => { +export const Number = () => { return - } - leftType={"action"} - right={} /> diff --git a/src/components/form/NumberInput.tsx b/src/components/form/NumberInput.tsx new file mode 100644 index 00000000..c7d9e742 --- /dev/null +++ b/src/components/form/NumberInput.tsx @@ -0,0 +1,47 @@ +import React, {RefObject} from "react"; +import Input, {InputProps} from "./Input"; +import {IconMinus, IconPlus} from "@tabler/icons-react"; +import Button from "../button/Button"; + + +interface NumberInputProps extends Omit, "wrapperComponent" | "type" | "left" | "right" | "leftType" | "rightType"> { + +} + +const NumberInput: React.ForwardRefExoticComponent = React.forwardRef((props, ref: RefObject) => { + + ref = ref || React.useRef(null) + + const { + left, + right, + step = 1, + ...rest + } = props + + const countUp = () => { + if (ref.current) { + if (!ref.current.value) ref.current.value = "0" + ref.current.value = (Number.parseInt(ref.current.value) + (step)).toString() + } + } + + const countDown = () => { + if (ref.current) { + if (!ref.current.value) ref.current.value = "0" + ref.current.value = (Number.parseInt(ref.current.value) - (step)).toString() + } + } + + return } + left={} + leftType={"action"} + type={"number"} + ref={ref} + {...rest} + /> + +}) + +export default NumberInput \ No newline at end of file From dae8965a656da37cd9c78f2d34f8264ac91bf218 Mon Sep 17 00:00:00 2001 From: nicosammito Date: Tue, 29 Oct 2024 19:58:33 +0100 Subject: [PATCH 49/67] changing regex to standard RFC type --- src/components/form/EmailInput.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/form/EmailInput.tsx b/src/components/form/EmailInput.tsx index b1545e76..422ec994 100644 --- a/src/components/form/EmailInput.tsx +++ b/src/components/form/EmailInput.tsx @@ -7,7 +7,7 @@ import Button from "../button/Button"; * This regex is based on the validation behind the type="email" validation of html. * This can be used as the validation for email input */ -const EMAIL_REGEX = /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/ +const EMAIL_REGEX = /(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])/ interface EmailInputProps extends Omit, "wrapperComponent" | "type"> { //defaults to false From d348076ba9ddaa4875b5d6099f4d0a50e7dda2c0 Mon Sep 17 00:00:00 2001 From: nicosammito Date: Tue, 29 Oct 2024 19:59:15 +0100 Subject: [PATCH 50/67] fix: fixing useForm behaviour on set of inputs with same target --- src/components/form/Input.tsx | 39 ++++++-- src/components/form/PasswordInput.tsx | 6 +- src/components/form/TextInput.tsx | 5 +- src/components/form/useForm.ts | 130 +++++++++++--------------- 4 files changed, 94 insertions(+), 86 deletions(-) diff --git a/src/components/form/Input.tsx b/src/components/form/Input.tsx index 0aec6ae7..559044ed 100644 --- a/src/components/form/Input.tsx +++ b/src/components/form/Input.tsx @@ -1,5 +1,5 @@ import {Code0Component} from "../../utils/types"; -import React, {LegacyRef} from "react"; +import React, {LegacyRef, RefObject, useEffect} from "react"; import {ValidationProps} from "./useForm"; import {mergeCode0Props} from "../../utils/utils"; import "./Input.style.scss" @@ -21,7 +21,9 @@ export interface InputProps extends Code0Input, ValidationProps { } -const Input: React.ForwardRefExoticComponent> = React.forwardRef((props: InputProps, ref) => { +const Input: React.ForwardRefExoticComponent> = React.forwardRef((props: InputProps, ref: RefObject) => { + + ref = ref || React.useRef(null) const { wrapperComponent = {}, @@ -32,23 +34,43 @@ const Input: React.ForwardRefExoticComponent> = React.forwardRef right, leftType = "icon", rightType = "action", - notValidMessage, - valid = true, + formValidation = { + valid: true, + notValidMessage: null, + onChange: null + }, ...rest } = props + useEffect(() => { + + if (!HTMLInputElement.prototype["setValue"]) HTMLInputElement.prototype["setValue"] = (element, value) => { + const valueSetter = Object.getOwnPropertyDescriptor(element, 'value')?.set; + const prototype = Object.getPrototypeOf(element); + const prototypeValueSetter = Object.getOwnPropertyDescriptor(prototype, 'value')?.set; + + if (valueSetter && valueSetter !== prototypeValueSetter) { + prototypeValueSetter?.call(element, value); + } else { + valueSetter?.call(element, value); + } + } + }, []) + + return <> {!!label ? : null} {!!description ? : null} -
+
{!!left ?
{left} -
: null} +
: null} - | undefined} {...mergeCode0Props("input__control", rest)}/> + | undefined} {...mergeCode0Props("input__control", rest)}/> {!!right ?
{right} @@ -56,7 +78,8 @@ const Input: React.ForwardRefExoticComponent> = React.forwardRef
- {!valid && notValidMessage ? : null} + {!formValidation?.valid && formValidation?.notValidMessage ? + : null} }) diff --git a/src/components/form/PasswordInput.tsx b/src/components/form/PasswordInput.tsx index e63193e9..896e0432 100644 --- a/src/components/form/PasswordInput.tsx +++ b/src/components/form/PasswordInput.tsx @@ -21,7 +21,11 @@ const PasswordInput: React.ForwardRefExoticComponent = React } = props const toClearable = () => { - if (ref.current) ref.current.value = "" + if (ref.current) { + ref.current["setValue"](ref.current, "") + ref.current.dispatchEvent(new Event("change", { bubbles: true })); + } + } const toVisible = () => { diff --git a/src/components/form/TextInput.tsx b/src/components/form/TextInput.tsx index c21cb897..d0775a1c 100644 --- a/src/components/form/TextInput.tsx +++ b/src/components/form/TextInput.tsx @@ -20,7 +20,10 @@ const TextInput: React.ForwardRefExoticComponent = React.forward } = props const toClearable = () => { - if (ref.current) ref.current.value = "" + if (ref.current) { + ref.current["setValue"](ref.current, "") + ref.current.dispatchEvent(new Event("change", { bubbles: true })); + } } const rightAction = [right] diff --git a/src/components/form/useForm.ts b/src/components/form/useForm.ts index 89c14698..7d394939 100644 --- a/src/components/form/useForm.ts +++ b/src/components/form/useForm.ts @@ -1,6 +1,6 @@ "use client" -import {RefObject, useCallback, useRef, useState} from "react"; +import {ChangeEvent, ChangeEventHandler, useCallback, useMemo, useState} from "react"; export type Validations = Partial<{ [Key in keyof Values]: (value: Values[Key]) => string | null; @@ -13,106 +13,84 @@ export interface FormValidationProps { } export interface ValidationProps { + checked?: boolean defaultValue?: Value - valid?: boolean - notValidMessage?: string | null - //ref?: RefObject, required?: boolean + formValidation?: { + onChange: ChangeEventHandler + valid?: boolean + notValidMessage?: string | null + } } export type ValidationsProps = Partial<{ [Key in keyof Values]: ValidationProps }> -export type FormValidationReturn = [ValidationsProps, () => void] +export type FormValidationReturn = [IValidation, () => void] -const createInitialInputProps = = Record>(props: FormValidationProps, refs: RefObject[]) => { +export interface IValidation { + getInputProps(key: keyof Values, options: { type: "input" | "checkbox" | "radio" }): ValidationProps +} + +class Validation implements IValidation { - const {initialValues, validate} = props + private readonly changeValue: (key: string, value: any) => void + private readonly initialRender: boolean + private readonly currentValues: Values + private readonly currentValidations?: Validations - let inputProps: ValidationsProps = {} + constructor(changeValue, values, validations, initial) { + this.changeValue = changeValue + this.currentValues = values + this.currentValidations = validations + this.initialRender = initial + } - Object.entries(initialValues).map(([k, v], index) => { + public getInputProps(key: keyof Values, options: { + type: "input" | "checkbox" | "radio" + }): ValidationProps { - const inputRef: RefObject = refs[index] - const type = inputRef.current?.type ?? "text" - const currentValue = (type == "checkbox" || type == "radio") ? inputRef.current?.checked : inputRef.current?.value + const currentValue = (this.currentValues[key] as null) || undefined + const currentName = key + const currentFc = !!this.currentValidations && !!this.currentValidations[key] ? this.currentValidations[key] : (value: typeof currentValue) => null + const message = !this.initialRender ? currentFc(currentValue) : null return { - name: k, - value: currentValue as typeof v || undefined, - function: !!validate && !!validate[k] ? validate[k] : (value: typeof currentValue) => null + defaultValue: currentValue, + formValidation: { + onChange: (event: ChangeEvent) => { + this.changeValue(currentName, (event.target as HTMLInputElement).value) + }, + ...(!this.initialRender ? { + notValidMessage: message, + valid: message === null ? true : !message, + } : { + valid: true, + }) + }, + ...(!!this.currentValidations && !!this.currentValidations[key] ? {required: true} : {}) } - - }).forEach((item, index) => { - - Object.assign(inputProps, { - [item.name]: { - defaultValue: item.value, - //notValidMessage: message, - //valid: message === null ? true : !message, - ref: refs[index], - ...(!!validate ? {required: true} : {}) - } - }) - - }) - - return inputProps - + } } const useForm = = Record>(props: FormValidationProps): FormValidationReturn => { - const {initialValues, validate, onSubmit = () => {}} = props - - const refs = Object.entries(initialValues).map(() => useRef(null)) - const [inputProps, setInputProps] = useState>(createInitialInputProps(props, refs)) + const {initialValues, validate, onSubmit} = props + const [values, setValues] = useState(initialValues) + const changeValue = (key: string, value: any) => setValues(prevState => { + prevState[key] = value + return prevState + }) + const initialInputProps = useMemo(() => new Validation(changeValue, initialValues, validate, true), []) + const [inputProps, setInputProps] = useState>(initialInputProps) const validateFunction = useCallback(() => { - let submittable = true - let inputProps: ValidationsProps = {} - let submitProps: Object = {} - - Object.entries(initialValues).map(([k, v], index) => { - - const inputRef: RefObject = refs[index] - const type = inputRef.current?.type ?? "text" - const currentValue = (type == "checkbox" || type == "radio") ? inputRef.current?.checked : inputRef.current?.value - - return { - name: k, - value: currentValue as typeof v || undefined, - function: !!validate && !!validate[k] ? validate[k] : (value: typeof currentValue) => null - } - - }).forEach((item, index) => { - - const message = item.value !== null ? item.function(item.value) : null - submittable = submittable ? message === null ? true : !message : false - - Object.assign(inputProps, { - [item.name]: { - defaultValue: item.value, - notValidMessage: message, - valid: message === null ? true : !message, - ref: refs[index], - ...(!!validate ? {required: true} : {}) - } - }) - - Object.assign(submitProps, { - [item.name]: item.value - }) - - }) + let inputProps: IValidation = new Validation(changeValue, values, validate, false) setInputProps(() => inputProps) - - if (submittable) onSubmit(submitProps as Values) - - + if (onSubmit) onSubmit(values as Values) }, []) From 41f7f44a89f06a62cc43b97f1fdf47c958a12468 Mon Sep 17 00:00:00 2001 From: nicosammito Date: Tue, 29 Oct 2024 19:59:30 +0100 Subject: [PATCH 51/67] feat: new RadioInput --- src/components/form/Input.stories.tsx | 64 +++++++++++++++++++++++++-- src/components/form/Input.style.scss | 51 +++++++++++++++++++++ src/components/form/RadioInput.tsx | 36 +++++++++++++++ 3 files changed, 147 insertions(+), 4 deletions(-) create mode 100644 src/components/form/RadioInput.tsx diff --git a/src/components/form/Input.stories.tsx b/src/components/form/Input.stories.tsx index af92fd04..c1d0dcce 100644 --- a/src/components/form/Input.stories.tsx +++ b/src/components/form/Input.stories.tsx @@ -9,6 +9,7 @@ import PasswordInput from "./PasswordInput"; import TextInput from "./TextInput"; import EmailInput, {emailValidation} from "./EmailInput"; import NumberInput from "./NumberInput"; +import RadioInput from "./RadioInput"; export default { title: "Input", @@ -19,7 +20,7 @@ export const Login = () => { const [inputs, validate] = useForm({ initialValues: { - email: null, + email: "nicoq@", password: null, checkbox: true }, @@ -54,7 +55,7 @@ export const Login = () => { type={"email"} description={"Your Email address for login"} left={} - {...inputs.email} + {...inputs.getInputProps("email")} />
{ label={"Password"} description={"Your password for login"} left={} - {...inputs.password} + {...inputs.getInputProps("password")} />
+ +
+ + } \ No newline at end of file diff --git a/src/components/form/Input.style.scss b/src/components/form/Input.style.scss index 445a332b..3cab13f4 100644 --- a/src/components/form/Input.style.scss +++ b/src/components/form/Input.style.scss @@ -92,4 +92,55 @@ } } +} + +.radio-input { + + $padding: $xxs; + + background: backgroundColor($secondary) !important; + border-radius: 0 !important; + border: none !important; + align-items: center; + box-sizing: border-box; + gap: $xxs; + padding: $padding 0; + + .input__control { + + $size: $sm; + + position: relative; + flex: none; + box-sizing: border-box; + padding: 0; + margin: 1px 0; + width: $size; + height: $size; + + appearance: none; + outline: none; + + background-color: transparent; + border: 1px solid borderColor($secondary, true); + border-radius: 50%; + + &:checked { + border-color: borderColor($info, true); + + &:before { + content: ""; + position: absolute; + left: 50%; + border-radius: 50%; + top: 50%; + transform: translateX(-50%) translateY(-50%); + width: $size/2; + height: $size/2; + background: backgroundColor($info); + } + } + + } + } \ No newline at end of file diff --git a/src/components/form/RadioInput.tsx b/src/components/form/RadioInput.tsx new file mode 100644 index 00000000..67fce21f --- /dev/null +++ b/src/components/form/RadioInput.tsx @@ -0,0 +1,36 @@ +import React, {RefObject} from "react"; +import Input, {InputProps} from "./Input"; + + +interface RadioInputProps extends Omit, "wrapperComponent" | "type" | "left" | "leftType"> { + text?: string +} + +const RadioInput: React.ForwardRefExoticComponent = React.forwardRef((props, ref: RefObject) => { + + ref = ref || React.useRef(null) + + const { + text, + value, + defaultValue, + ...rest + } = props + + + return + +}) + +export default RadioInput \ No newline at end of file From 6bc4ee455d947c142bd27a21b9654a2fcf58de22 Mon Sep 17 00:00:00 2001 From: nicosammito Date: Tue, 29 Oct 2024 19:59:56 +0100 Subject: [PATCH 52/67] fix: vulnerabilities --- package-lock.json | 510 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 478 insertions(+), 32 deletions(-) diff --git a/package-lock.json b/package-lock.json index 850e61e2..a023fe02 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2091,6 +2091,24 @@ "resolved": "https://registry.npmjs.org/@daybrush/utils/-/utils-1.13.0.tgz", "integrity": "sha512-ALK12C6SQNNHw1enXK+UO8bdyQ+jaWNQ1Af7Z3FNxeAwjYhQT7do+TRE4RASAJ3ObaS2+TJ7TXR3oz2Gzbw0PQ==" }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, "node_modules/@esbuild/android-arm": { "version": "0.18.20", "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", @@ -9847,10 +9865,11 @@ "dev": true }, "node_modules/cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -11156,17 +11175,18 @@ "dev": true }, "node_modules/express": { - "version": "4.21.0", - "resolved": "https://registry.npmjs.org/express/-/express-4.21.0.tgz", - "integrity": "sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng==", + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz", + "integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==", "dev": true, + "license": "MIT", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.6.0", + "cookie": "0.7.1", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", @@ -17073,9 +17093,9 @@ } }, "node_modules/postcss": { - "version": "8.4.38", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", - "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", + "version": "8.4.47", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz", + "integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==", "dev": true, "funding": [ { @@ -17091,10 +17111,11 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { "nanoid": "^3.3.7", - "picocolors": "^1.0.0", - "source-map-js": "^1.2.0" + "picocolors": "^1.1.0", + "source-map-js": "^1.2.1" }, "engines": { "node": "^10 || ^12 || >=14" @@ -19350,10 +19371,11 @@ } }, "node_modules/source-map-js": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", - "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } @@ -20504,33 +20526,35 @@ } }, "node_modules/vite": { - "version": "4.5.3", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.3.tgz", - "integrity": "sha512-kQL23kMeX92v3ph7IauVkXkikdDRsYMGTVl5KY2E9OY4ONLvkHf04MDTbnfo6NKxZiDLWzVpP5oTa8hQD8U3dg==", + "version": "5.4.10", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.10.tgz", + "integrity": "sha512-1hvaPshuPUtxeQ0hsVH3Mud0ZanOLwVTneA1EgbAM5LhaZEqyPWGRQ7BtaMvUrTDeEaC8pxtj6a6jku3x4z6SQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { - "esbuild": "^0.18.10", - "postcss": "^8.4.27", - "rollup": "^3.27.1" + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" }, "bin": { "vite": "bin/vite.js" }, "engines": { - "node": "^14.18.0 || >=16.0.0" + "node": "^18.0.0 || >=20.0.0" }, "funding": { "url": "https://github.com/vitejs/vite?sponsor=1" }, "optionalDependencies": { - "fsevents": "~2.3.2" + "fsevents": "~2.3.3" }, "peerDependencies": { - "@types/node": ">= 14", + "@types/node": "^18.0.0 || >=20.0.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", + "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.4.0" @@ -20548,6 +20572,9 @@ "sass": { "optional": true }, + "sass-embedded": { + "optional": true + }, "stylus": { "optional": true }, @@ -20559,21 +20586,440 @@ } } }, - "node_modules/vite/node_modules/rollup": { - "version": "3.29.4", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz", - "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==", + "node_modules/vite/node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", "peer": true, "bin": { - "rollup": "dist/bin/rollup" + "esbuild": "bin/esbuild" }, "engines": { - "node": ">=14.18.0", - "npm": ">=8.0.0" + "node": ">=12" }, "optionalDependencies": { - "fsevents": "~2.3.2" + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" } }, "node_modules/wait-on": { From 0a35bf8a8d63d023be07264c7f3dfac9565888c9 Mon Sep 17 00:00:00 2001 From: nicosammito Date: Thu, 7 Nov 2024 15:45:48 +0100 Subject: [PATCH 53/67] fix: type errors with useForm --- src/components/form/useForm.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/components/form/useForm.ts b/src/components/form/useForm.ts index 7d394939..b01751f9 100644 --- a/src/components/form/useForm.ts +++ b/src/components/form/useForm.ts @@ -30,7 +30,7 @@ export type ValidationsProps = Partial<{ export type FormValidationReturn = [IValidation, () => void] export interface IValidation { - getInputProps(key: keyof Values, options: { type: "input" | "checkbox" | "radio" }): ValidationProps + getInputProps(key: Key, options: { type: "input" | "checkbox" | "radio" }): ValidationProps } class Validation implements IValidation { @@ -40,19 +40,19 @@ class Validation implements IValidation { private readonly currentValues: Values private readonly currentValidations?: Validations - constructor(changeValue, values, validations, initial) { + constructor(changeValue: (key: string, value: any) => void, values: Values, validations: Validations, initial: boolean) { this.changeValue = changeValue this.currentValues = values this.currentValidations = validations this.initialRender = initial } - public getInputProps(key: keyof Values, options: { + public getInputProps(key: Key, options: { type: "input" | "checkbox" | "radio" - }): ValidationProps { + }): ValidationProps { - const currentValue = (this.currentValues[key] as null) || undefined - const currentName = key + const currentValue = ((this.currentValues[key]) || undefined)!! + const currentName = key as string const currentFc = !!this.currentValidations && !!this.currentValidations[key] ? this.currentValidations[key] : (value: typeof currentValue) => null const message = !this.initialRender ? currentFc(currentValue) : null @@ -76,9 +76,9 @@ class Validation implements IValidation { const useForm = = Record>(props: FormValidationProps): FormValidationReturn => { - const {initialValues, validate, onSubmit} = props + const {initialValues, validate = {}, onSubmit} = props const [values, setValues] = useState(initialValues) - const changeValue = (key: string, value: any) => setValues(prevState => { + const changeValue = (key: keyof Values, value: any) => setValues(prevState => { prevState[key] = value return prevState }) From 1fae539bd7604c6bac7b0493aa855b6f53f69739 Mon Sep 17 00:00:00 2001 From: nicosammito Date: Thu, 7 Nov 2024 16:10:35 +0100 Subject: [PATCH 54/67] fix: type errors --- src/components/form/Input.stories.tsx | 2 -- src/components/form/Input.tsx | 31 +++++++++++++-------------- src/components/form/PasswordInput.tsx | 8 ++----- src/components/form/RadioInput.tsx | 4 ++-- src/components/form/useForm.ts | 10 ++++----- 5 files changed, 24 insertions(+), 31 deletions(-) diff --git a/src/components/form/Input.stories.tsx b/src/components/form/Input.stories.tsx index c1d0dcce..7ba59bab 100644 --- a/src/components/form/Input.stories.tsx +++ b/src/components/form/Input.stories.tsx @@ -52,7 +52,6 @@ export const Login = () => { } {...inputs.getInputProps("email")} @@ -88,7 +87,6 @@ export const Website = () => { extends Code0Input, ValidationProps { description?: React.ReactNode | React.ReactElement } +export const setElementKey = (element: HTMLElement, value: any, event: string) => { + const valueSetter = Object.getOwnPropertyDescriptor(element, 'value')?.set; + const prototype = Object.getPrototypeOf(element); + const prototypeValueSetter = Object.getOwnPropertyDescriptor(prototype, 'value')?.set; + + if (valueSetter && valueSetter !== prototypeValueSetter) { + prototypeValueSetter?.call(element, value); + } else { + valueSetter?.call(element, value); + } + + element.dispatchEvent(new Event(event, { bubbles: true })); +} + const Input: React.ForwardRefExoticComponent> = React.forwardRef((props: InputProps, ref: RefObject) => { @@ -42,21 +56,6 @@ const Input: React.ForwardRefExoticComponent> = React.forwardRef ...rest } = props - useEffect(() => { - - if (!HTMLInputElement.prototype["setValue"]) HTMLInputElement.prototype["setValue"] = (element, value) => { - const valueSetter = Object.getOwnPropertyDescriptor(element, 'value')?.set; - const prototype = Object.getPrototypeOf(element); - const prototypeValueSetter = Object.getOwnPropertyDescriptor(prototype, 'value')?.set; - - if (valueSetter && valueSetter !== prototypeValueSetter) { - prototypeValueSetter?.call(element, value); - } else { - valueSetter?.call(element, value); - } - } - }, []) - return <> @@ -69,7 +68,7 @@ const Input: React.ForwardRefExoticComponent> = React.forwardRef {left}
: null} - | undefined} {...mergeCode0Props("input__control", rest)}/> {!!right ?
diff --git a/src/components/form/PasswordInput.tsx b/src/components/form/PasswordInput.tsx index 896e0432..68b8e218 100644 --- a/src/components/form/PasswordInput.tsx +++ b/src/components/form/PasswordInput.tsx @@ -1,5 +1,5 @@ import React, {RefObject} from "react"; -import Input, {InputProps} from "./Input"; +import Input, {InputProps, setElementKey} from "./Input"; import {IconEye, IconX} from "@tabler/icons-react"; import Button from "../button/Button"; @@ -21,11 +21,7 @@ const PasswordInput: React.ForwardRefExoticComponent = React } = props const toClearable = () => { - if (ref.current) { - ref.current["setValue"](ref.current, "") - ref.current.dispatchEvent(new Event("change", { bubbles: true })); - } - + if (ref.current) setElementKey(ref.current, "", "change") } const toVisible = () => { diff --git a/src/components/form/RadioInput.tsx b/src/components/form/RadioInput.tsx index 67fce21f..27e312e6 100644 --- a/src/components/form/RadioInput.tsx +++ b/src/components/form/RadioInput.tsx @@ -13,7 +13,7 @@ const RadioInput: React.ForwardRefExoticComponent = React.forwa const { text, value, - defaultValue, + initialValue, ...rest } = props @@ -27,7 +27,7 @@ const RadioInput: React.ForwardRefExoticComponent = React.forwa left={null} ref={ref} value={value} - {...(value === defaultValue ? {defaultChecked: true} : {})} + {...(value === initialValue ? {defaultChecked: true} : {})} {...rest} /> diff --git a/src/components/form/useForm.ts b/src/components/form/useForm.ts index b01751f9..2b3100af 100644 --- a/src/components/form/useForm.ts +++ b/src/components/form/useForm.ts @@ -14,10 +14,10 @@ export interface FormValidationProps { export interface ValidationProps { checked?: boolean - defaultValue?: Value + initialValue?: Value required?: boolean formValidation?: { - onChange: ChangeEventHandler + onChange: ChangeEventHandler valid?: boolean notValidMessage?: string | null } @@ -30,7 +30,7 @@ export type ValidationsProps = Partial<{ export type FormValidationReturn = [IValidation, () => void] export interface IValidation { - getInputProps(key: Key, options: { type: "input" | "checkbox" | "radio" }): ValidationProps + getInputProps(key: Key, options?: { type: "input" | "checkbox" | "radio" }): ValidationProps } class Validation implements IValidation { @@ -49,7 +49,7 @@ class Validation implements IValidation { public getInputProps(key: Key, options: { type: "input" | "checkbox" | "radio" - }): ValidationProps { + } = {type: "input"}): ValidationProps { const currentValue = ((this.currentValues[key]) || undefined)!! const currentName = key as string @@ -57,7 +57,7 @@ class Validation implements IValidation { const message = !this.initialRender ? currentFc(currentValue) : null return { - defaultValue: currentValue, + initialValue: currentValue, formValidation: { onChange: (event: ChangeEvent) => { this.changeValue(currentName, (event.target as HTMLInputElement).value) From a462fcbf3187b20e4f808bb8f4d5e52c66043399 Mon Sep 17 00:00:00 2001 From: nicosammito Date: Thu, 7 Nov 2024 16:12:48 +0100 Subject: [PATCH 55/67] fix: changed to new value method --- src/components/form/TextInput.tsx | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/components/form/TextInput.tsx b/src/components/form/TextInput.tsx index d0775a1c..980ae1aa 100644 --- a/src/components/form/TextInput.tsx +++ b/src/components/form/TextInput.tsx @@ -1,5 +1,5 @@ import React, {RefObject} from "react"; -import Input, {InputProps} from "./Input"; +import Input, {InputProps, setElementKey} from "./Input"; import {IconX} from "@tabler/icons-react"; import Button from "../button/Button"; @@ -20,10 +20,7 @@ const TextInput: React.ForwardRefExoticComponent = React.forward } = props const toClearable = () => { - if (ref.current) { - ref.current["setValue"](ref.current, "") - ref.current.dispatchEvent(new Event("change", { bubbles: true })); - } + if (ref.current) setElementKey(ref.current, "", "change") } const rightAction = [right] From 3d284615d90794b6c6159b9b8f126ea9c286eb2e Mon Sep 17 00:00:00 2001 From: nicosammito Date: Thu, 7 Nov 2024 16:13:01 +0100 Subject: [PATCH 56/67] fix: type errors --- src/components/form/NumberInput.tsx | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/components/form/NumberInput.tsx b/src/components/form/NumberInput.tsx index c7d9e742..08d0896e 100644 --- a/src/components/form/NumberInput.tsx +++ b/src/components/form/NumberInput.tsx @@ -13,8 +13,6 @@ const NumberInput: React.ForwardRefExoticComponent = React.for ref = ref || React.useRef(null) const { - left, - right, step = 1, ...rest } = props @@ -22,14 +20,14 @@ const NumberInput: React.ForwardRefExoticComponent = React.for const countUp = () => { if (ref.current) { if (!ref.current.value) ref.current.value = "0" - ref.current.value = (Number.parseInt(ref.current.value) + (step)).toString() + ref.current.value = (Number.parseInt(ref.current.value) + (step as number)).toString() } } const countDown = () => { if (ref.current) { if (!ref.current.value) ref.current.value = "0" - ref.current.value = (Number.parseInt(ref.current.value) - (step)).toString() + ref.current.value = (Number.parseInt(ref.current.value) - (step as number)).toString() } } From 4b631e8597e31a07ced9c38053929f2a2353de7d Mon Sep 17 00:00:00 2001 From: nicosammito Date: Thu, 7 Nov 2024 16:14:31 +0100 Subject: [PATCH 57/67] fix: change to new element key value --- src/components/form/EmailInput.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/form/EmailInput.tsx b/src/components/form/EmailInput.tsx index 422ec994..7092dcda 100644 --- a/src/components/form/EmailInput.tsx +++ b/src/components/form/EmailInput.tsx @@ -1,5 +1,5 @@ import React, {RefObject} from "react"; -import Input, {InputProps} from "./Input"; +import Input, {InputProps, setElementKey} from "./Input"; import {IconX} from "@tabler/icons-react"; import Button from "../button/Button"; @@ -27,7 +27,7 @@ const EmailInput: React.ForwardRefExoticComponent = React.forwa } = props const toClearable = () => { - if (ref.current) ref.current.value = "" + if (ref.current) setElementKey(ref.current, "", "change") } const rightAction = [right] From 665bdb7642bca053426743a211a8c577cb050340 Mon Sep 17 00:00:00 2001 From: nicosammito Date: Thu, 7 Nov 2024 16:30:00 +0100 Subject: [PATCH 58/67] fix: remove options from getInputProps --- src/components/form/Input.stories.tsx | 50 +++++++++++++++++++++++++-- src/components/form/useForm.ts | 6 ++-- 2 files changed, 49 insertions(+), 7 deletions(-) diff --git a/src/components/form/Input.stories.tsx b/src/components/form/Input.stories.tsx index 7ba59bab..96ef5bec 100644 --- a/src/components/form/Input.stories.tsx +++ b/src/components/form/Input.stories.tsx @@ -10,6 +10,7 @@ import TextInput from "./TextInput"; import EmailInput, {emailValidation} from "./EmailInput"; import NumberInput from "./NumberInput"; import RadioInput from "./RadioInput"; +import CheckboxInput from "./CheckboxInput"; export default { title: "Input", @@ -134,19 +135,19 @@ export const Radio = () => { value={"dynamic"} name={"test1"} text={"Dynamic"} - {...inputs.getInputProps("test", {type : "radio"})} + {...inputs.getInputProps("test")} />
{
+} + + +export const Checkbox = () => { + + const [inputs, validate] = useForm({ + initialValues: { + test: null + }, + validate: { + test: (value) => { + if (!value) return "Error" + return null + } + }, + onSubmit: (values) => { + console.log(values) + } + }) + + + return
+ + +
+
+ + +
+
+
+ } \ No newline at end of file diff --git a/src/components/form/useForm.ts b/src/components/form/useForm.ts index 2b3100af..487d0eed 100644 --- a/src/components/form/useForm.ts +++ b/src/components/form/useForm.ts @@ -30,7 +30,7 @@ export type ValidationsProps = Partial<{ export type FormValidationReturn = [IValidation, () => void] export interface IValidation { - getInputProps(key: Key, options?: { type: "input" | "checkbox" | "radio" }): ValidationProps + getInputProps(key: Key): ValidationProps } class Validation implements IValidation { @@ -47,9 +47,7 @@ class Validation implements IValidation { this.initialRender = initial } - public getInputProps(key: Key, options: { - type: "input" | "checkbox" | "radio" - } = {type: "input"}): ValidationProps { + public getInputProps(key: Key): ValidationProps { const currentValue = ((this.currentValues[key]) || undefined)!! const currentName = key as string From 81e7ab8b658822530065b40b6135c08a318d1b05 Mon Sep 17 00:00:00 2001 From: nicosammito Date: Thu, 7 Nov 2024 16:30:15 +0100 Subject: [PATCH 59/67] feat: new CheckboxInput --- src/components/form/CheckboxInput.tsx | 36 +++++++++++++++++++ src/components/form/Input.style.scss | 52 +++++++++++++++++++++++++-- 2 files changed, 86 insertions(+), 2 deletions(-) create mode 100644 src/components/form/CheckboxInput.tsx diff --git a/src/components/form/CheckboxInput.tsx b/src/components/form/CheckboxInput.tsx new file mode 100644 index 00000000..71038bf9 --- /dev/null +++ b/src/components/form/CheckboxInput.tsx @@ -0,0 +1,36 @@ +import React, {RefObject} from "react"; +import Input, {InputProps} from "./Input"; + + +interface CheckboxInputProps extends Omit, "wrapperComponent" | "type" | "left" | "leftType"> { + text?: string +} + +const CheckboxInput: React.ForwardRefExoticComponent = React.forwardRef((props, ref: RefObject) => { + + ref = ref || React.useRef(null) + + const { + text, + value, + initialValue, + ...rest + } = props + + + return + +}) + +export default CheckboxInput \ No newline at end of file diff --git a/src/components/form/Input.style.scss b/src/components/form/Input.style.scss index 3cab13f4..3cebe35b 100644 --- a/src/components/form/Input.style.scss +++ b/src/components/form/Input.style.scss @@ -97,6 +97,7 @@ .radio-input { $padding: $xxs; + $size: 0.9rem; background: backgroundColor($secondary) !important; border-radius: 0 !important; @@ -108,8 +109,6 @@ .input__control { - $size: $sm; - position: relative; flex: none; box-sizing: border-box; @@ -142,5 +141,54 @@ } } +} + +.checkbox-input { + + $padding: $xxs; + $size: 0.9rem; + + background: backgroundColor($secondary) !important; + border-radius: 0 !important; + border: none !important; + align-items: center; + box-sizing: border-box; + gap: $xxs; + padding: $padding 0; + + .input__control { + + position: relative; + flex: none; + box-sizing: border-box; + padding: 0; + margin: 1px 0; + width: $size; + height: $size; + + appearance: none; + outline: none; + + background-color: transparent; + border: 1px solid borderColor($secondary, true); + border-radius: calc($borderRadius / 3); + + &:checked { + border-color: borderColor($info, true); + background: backgroundColor($info); + + &:before { + content: ""; + position: absolute; + left: 50%; + top: 50%; + transform: translateX(-50%) translateY(-50%); + width: $size/2; + height: $size/2; + clip-path: polygon(14% 44%, 0 65%, 50% 100%, 100% 16%, 80% 0%, 43% 62%); + background: rgba($white, .5); + } + } + } } \ No newline at end of file From e50b190443a7489322a8a2a8b374dc6ffac2b140 Mon Sep 17 00:00:00 2001 From: nicosammito Date: Mon, 25 Nov 2024 17:52:33 +0100 Subject: [PATCH 60/67] fix: change to a new value system on form validation to remove the native change event --- src/components/form/Input.tsx | 23 +++++++++++++------ src/components/form/TextInput.tsx | 2 +- .../form/{ => radio}/RadioInput.tsx | 2 +- src/components/form/useForm.ts | 11 ++++----- 4 files changed, 23 insertions(+), 15 deletions(-) rename src/components/form/{ => radio}/RadioInput.tsx (94%) diff --git a/src/components/form/Input.tsx b/src/components/form/Input.tsx index 2f519281..ce442c45 100644 --- a/src/components/form/Input.tsx +++ b/src/components/form/Input.tsx @@ -1,5 +1,5 @@ import {Code0Component} from "../../utils/types"; -import React, {LegacyRef, RefObject, useEffect} from "react"; +import React, {ChangeEvent, LegacyRef, RefObject, useEffect} from "react"; import {ValidationProps} from "./useForm"; import {mergeCode0Props} from "../../utils/utils"; import "./Input.style.scss" @@ -20,10 +20,10 @@ export interface InputProps extends Code0Input, ValidationProps { description?: React.ReactNode | React.ReactElement } -export const setElementKey = (element: HTMLElement, value: any, event: string) => { - const valueSetter = Object.getOwnPropertyDescriptor(element, 'value')?.set; +export const setElementKey = (element: HTMLElement, key: string, value: any, event: string) => { + const valueSetter = Object.getOwnPropertyDescriptor(element, key)?.set; const prototype = Object.getPrototypeOf(element); - const prototypeValueSetter = Object.getOwnPropertyDescriptor(prototype, 'value')?.set; + const prototypeValueSetter = Object.getOwnPropertyDescriptor(prototype, key)?.set; if (valueSetter && valueSetter !== prototypeValueSetter) { prototypeValueSetter?.call(element, value); @@ -51,11 +51,21 @@ const Input: React.ForwardRefExoticComponent> = React.forwardRef formValidation = { valid: true, notValidMessage: null, - onChange: null + setValue: null }, ...rest } = props + useEffect(() => { + if (!ref) return + if (!ref.current) return + if (!formValidation) return + if (!formValidation.setValue) return + + // @ts-ignore + ref.current.addEventListener("change", ev => formValidation.setValue(rest.type != "checkbox" ? ev.target.value : ev.target.checked)) + }, [ref]) + return <> @@ -68,8 +78,7 @@ const Input: React.ForwardRefExoticComponent> = React.forwardRef {left}
: null} - | undefined} {...mergeCode0Props("input__control", rest)}/> + | undefined} {...mergeCode0Props("input__control", rest)}/> {!!right ?
{right} diff --git a/src/components/form/TextInput.tsx b/src/components/form/TextInput.tsx index 980ae1aa..25895702 100644 --- a/src/components/form/TextInput.tsx +++ b/src/components/form/TextInput.tsx @@ -20,7 +20,7 @@ const TextInput: React.ForwardRefExoticComponent = React.forward } = props const toClearable = () => { - if (ref.current) setElementKey(ref.current, "", "change") + if (ref.current) setElementKey(ref.current, "value", "", "change") } const rightAction = [right] diff --git a/src/components/form/RadioInput.tsx b/src/components/form/radio/RadioInput.tsx similarity index 94% rename from src/components/form/RadioInput.tsx rename to src/components/form/radio/RadioInput.tsx index 27e312e6..a039dfa1 100644 --- a/src/components/form/RadioInput.tsx +++ b/src/components/form/radio/RadioInput.tsx @@ -1,5 +1,5 @@ import React, {RefObject} from "react"; -import Input, {InputProps} from "./Input"; +import Input, {InputProps} from "../Input"; interface RadioInputProps extends Omit, "wrapperComponent" | "type" | "left" | "leftType"> { diff --git a/src/components/form/useForm.ts b/src/components/form/useForm.ts index 487d0eed..57e19ab0 100644 --- a/src/components/form/useForm.ts +++ b/src/components/form/useForm.ts @@ -13,11 +13,10 @@ export interface FormValidationProps { } export interface ValidationProps { - checked?: boolean - initialValue?: Value + initialValue?: Value | null required?: boolean formValidation?: { - onChange: ChangeEventHandler + setValue: (value: string) => void valid?: boolean notValidMessage?: string | null } @@ -49,7 +48,7 @@ class Validation implements IValidation { public getInputProps(key: Key): ValidationProps { - const currentValue = ((this.currentValues[key]) || undefined)!! + const currentValue = ((this.currentValues[key]) || null)!! const currentName = key as string const currentFc = !!this.currentValidations && !!this.currentValidations[key] ? this.currentValidations[key] : (value: typeof currentValue) => null const message = !this.initialRender ? currentFc(currentValue) : null @@ -57,8 +56,8 @@ class Validation implements IValidation { return { initialValue: currentValue, formValidation: { - onChange: (event: ChangeEvent) => { - this.changeValue(currentName, (event.target as HTMLInputElement).value) + setValue: (value: string) => { + this.changeValue(currentName, value) }, ...(!this.initialRender ? { notValidMessage: message, From a1edd340d8866bb898e6017394268ee0fb5c234f Mon Sep 17 00:00:00 2001 From: nicosammito Date: Mon, 25 Nov 2024 17:53:16 +0100 Subject: [PATCH 61/67] feat: new RadioGroup component and RadioButton component to create radio inputs in various styles --- src/components/form/Input.stories.tsx | 64 +++++++++++++++++++++-- src/components/form/Input.style.scss | 12 +++-- src/components/form/radio/RadioButton.tsx | 42 +++++++++++++++ src/components/form/radio/RadioGroup.tsx | 61 +++++++++++++++++++++ 4 files changed, 172 insertions(+), 7 deletions(-) create mode 100644 src/components/form/radio/RadioButton.tsx create mode 100644 src/components/form/radio/RadioGroup.tsx diff --git a/src/components/form/Input.stories.tsx b/src/components/form/Input.stories.tsx index 96ef5bec..d0d91d00 100644 --- a/src/components/form/Input.stories.tsx +++ b/src/components/form/Input.stories.tsx @@ -9,8 +9,10 @@ import PasswordInput from "./PasswordInput"; import TextInput from "./TextInput"; import EmailInput, {emailValidation} from "./EmailInput"; import NumberInput from "./NumberInput"; -import RadioInput from "./RadioInput"; +import RadioInput from "./radio/RadioInput"; import CheckboxInput from "./CheckboxInput"; +import RadioGroup from "./radio/RadioGroup"; +import RadioButton from "./radio/RadioButton"; export default { title: "Input", @@ -109,11 +111,11 @@ export const Number = () => { } -export const Radio = () => { +export const RadioExample = () => { const [inputs, validate] = useForm({ initialValues: { - test: null + test: "dynamic" }, validate: { test: (value) => { @@ -205,4 +207,58 @@ export const Checkbox = () => { -} \ No newline at end of file +} + + +export const RadioCard = () => { + + const [inputs, validate] = useForm({ + initialValues: { + test: "dynamic" + }, + validate: { + test: (value) => { + if (!value) return "Error" + return null + } + }, + onSubmit: (values) => { + console.log(values) + } + }) + + return + {({activeRadio, setActiveRadio}) => { + return <> + setActiveRadio("dynamic")} color={activeRadio == "dynamic" ? "secondary" : "primary"}> + + + + + Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt + ut + + + setActiveRadio("hybrid")} color={activeRadio == "hybrid" ? "secondary" : "primary"}> + + + + + Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt + ut + + +
+ + +
+ + }} +
+} diff --git a/src/components/form/Input.style.scss b/src/components/form/Input.style.scss index 3cebe35b..5aa115ba 100644 --- a/src/components/form/Input.style.scss +++ b/src/components/form/Input.style.scss @@ -8,6 +8,7 @@ display: flex; z-index: 1; align-items: stretch; + cursor: pointer; &:has(&__control:focus) { @@ -94,18 +95,18 @@ } -.radio-input { +.radio-input, .radio-button { $padding: $xxs; $size: 0.9rem; - background: backgroundColor($secondary) !important; + background:transparent !important; border-radius: 0 !important; border: none !important; align-items: center; box-sizing: border-box; - gap: $xxs; padding: $padding 0; + gap: $xxs; .input__control { @@ -143,6 +144,11 @@ } } +.radio-button { + padding: 0; + display: inline-flex; +} + .checkbox-input { $padding: $xxs; diff --git a/src/components/form/radio/RadioButton.tsx b/src/components/form/radio/RadioButton.tsx new file mode 100644 index 00000000..b27d94f9 --- /dev/null +++ b/src/components/form/radio/RadioButton.tsx @@ -0,0 +1,42 @@ +import React, {RefObject, useEffect} from "react"; +import Input from "../Input"; +import {Code0Component} from "../../../utils/types"; +import {useRadioGroup} from "./RadioGroup"; + + +interface RadioButtonProps extends Code0Component { +} + +const RadioButton: React.ForwardRefExoticComponent = React.forwardRef((props, ref: RefObject) => { + + const {value, ...rest} = props + + const radioGroup = useRadioGroup() + ref = ref || React.useRef(null) + + //update store of radio group + useEffect(() => { + if (!ref || !ref.current || !radioGroup) return + ref.current.addEventListener("change", ev => { + radioGroup.setActiveRadio(String(value)) + }) + }, [ref, radioGroup]) + + return + +}) + +export default RadioButton \ No newline at end of file diff --git a/src/components/form/radio/RadioGroup.tsx b/src/components/form/radio/RadioGroup.tsx new file mode 100644 index 00000000..01705de3 --- /dev/null +++ b/src/components/form/radio/RadioGroup.tsx @@ -0,0 +1,61 @@ +"use client" + +import React, {useMemo} from "react"; +import {ValidationProps} from "../useForm"; +import {InputProps} from "../Input"; + +export interface RadioGroupContextProps { + validation?: ValidationProps + activeRadio: string | null + setActiveRadio: (radio: string) => void +} + +export interface RadioGroupExoticProps { + activeRadio: string | null + setActiveRadio: (radio: string) => void +} + +export interface RadioGroupProps extends Omit, "wrapperComponent" | "type" | "left" | "leftType" | "right" | "rightType" | "children"> { + children: React.ReactElement[] | React.FC +} + +const RadioGroupContext = React.createContext(null) + +export const useRadioGroup = () => React.useContext(RadioGroupContext) + +const RadioGroup: React.FC = (props) => { + + const { + children, + formValidation, + initialValue = null, + required, + label, + description + } = props + const [radioStore, setRadioStore] = React.useState(initialValue) + + const setActiveRadio = (radio: string) => { + formValidation?.setValue(radio) + setRadioStore(radio) + } + + const child = typeof children === "function" ? useMemo(() => children({activeRadio: radioStore, setActiveRadio}), [radioStore]) : children + + return + {/** TODO: add label and description **/} + {child} + {/** TODO: add error handling **/} + + +} + +export default RadioGroup \ No newline at end of file From e0896fc04b58f20764b7043d73d8512205fda4fc Mon Sep 17 00:00:00 2001 From: nicosammito Date: Tue, 26 Nov 2024 14:52:18 +0100 Subject: [PATCH 62/67] fix: errors --- .gitlab-ci.yml | 2 +- package-lock.json | 6 +-- src/components/card/Card.stories.tsx | 1 - src/components/d-screen/DScreen.stories.tsx | 1 - src/components/form/EmailInput.tsx | 2 +- src/components/form/Input.stories.tsx | 54 --------------------- src/components/form/Input.tsx | 2 +- src/components/form/PasswordInput.tsx | 2 +- src/components/form/radio/RadioInput.tsx | 2 +- src/components/form/useForm.ts | 2 +- src/components/quote/Quote.stories.tsx | 2 - src/components/tooltip/Tooltip.tsx | 2 +- src/utils/utils.ts | 2 +- 13 files changed, 11 insertions(+), 69 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index d3e9edc2..08f9efb3 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -50,7 +50,7 @@ storybook:test: if [[ $exit_code -ne 0 && -d "__snapshots__/__diff_output__" ]]; then echo -e "\e[0Ksection_start:`date +%s`:glpa_summary\r\e[0KHeader of the summary" echo "Storybook tests failed." - echo "Check for rendering differences at http://gitlab.com/code0-tech/development/pictor/-/jobs/$CI_JOB_ID/artifacts/browse/__snapshots__/__diff_output__/" + echo "Check for rendering differences at https://gitlab.com/code0-tech/development/pictor/-/jobs/$CI_JOB_ID/artifacts/browse/__snapshots__/__diff_output__/" echo "If the changes are intended, update the snapshots by adding the 'regenerate-snapshots' label." echo -e "\e[0Ksection_end:`date +%s`:glpa_summary\r\e[0K" fi diff --git a/package-lock.json b/package-lock.json index a023fe02..9b69f582 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10066,9 +10066,9 @@ } }, "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, "dependencies": { "path-key": "^3.1.0", diff --git a/src/components/card/Card.stories.tsx b/src/components/card/Card.stories.tsx index 1d15bff2..4111bd87 100644 --- a/src/components/card/Card.stories.tsx +++ b/src/components/card/Card.stories.tsx @@ -91,6 +91,5 @@ export const CardNews: CardStory = { color: "secondary", outline: false, gradient: true, - gradientPosition: "top-right" } } \ No newline at end of file diff --git a/src/components/d-screen/DScreen.stories.tsx b/src/components/d-screen/DScreen.stories.tsx index 1f11c04b..9b3f470c 100644 --- a/src/components/d-screen/DScreen.stories.tsx +++ b/src/components/d-screen/DScreen.stories.tsx @@ -1,7 +1,6 @@ import {Meta} from "@storybook/react"; import React from "react"; import DScreen from "./DScreen"; -import Badge from "../badge/Badge"; import { IconBrandAdobe, IconDatabase, diff --git a/src/components/form/EmailInput.tsx b/src/components/form/EmailInput.tsx index 7092dcda..d0b4b7e4 100644 --- a/src/components/form/EmailInput.tsx +++ b/src/components/form/EmailInput.tsx @@ -27,7 +27,7 @@ const EmailInput: React.ForwardRefExoticComponent = React.forwa } = props const toClearable = () => { - if (ref.current) setElementKey(ref.current, "", "change") + if (ref.current) setElementKey(ref.current, "value", "", "change") } const rightAction = [right] diff --git a/src/components/form/Input.stories.tsx b/src/components/form/Input.stories.tsx index d0d91d00..cfe2de40 100644 --- a/src/components/form/Input.stories.tsx +++ b/src/components/form/Input.stories.tsx @@ -208,57 +208,3 @@ export const Checkbox = () => { } - - -export const RadioCard = () => { - - const [inputs, validate] = useForm({ - initialValues: { - test: "dynamic" - }, - validate: { - test: (value) => { - if (!value) return "Error" - return null - } - }, - onSubmit: (values) => { - console.log(values) - } - }) - - return - {({activeRadio, setActiveRadio}) => { - return <> - setActiveRadio("dynamic")} color={activeRadio == "dynamic" ? "secondary" : "primary"}> - - - - - Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt - ut - - - setActiveRadio("hybrid")} color={activeRadio == "hybrid" ? "secondary" : "primary"}> - - - - - Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt - ut - - -
- - -
- - }} -
-} diff --git a/src/components/form/Input.tsx b/src/components/form/Input.tsx index ce442c45..6713ddfc 100644 --- a/src/components/form/Input.tsx +++ b/src/components/form/Input.tsx @@ -1,5 +1,5 @@ import {Code0Component} from "../../utils/types"; -import React, {ChangeEvent, LegacyRef, RefObject, useEffect} from "react"; +import React, {LegacyRef, RefObject, useEffect} from "react"; import {ValidationProps} from "./useForm"; import {mergeCode0Props} from "../../utils/utils"; import "./Input.style.scss" diff --git a/src/components/form/PasswordInput.tsx b/src/components/form/PasswordInput.tsx index 68b8e218..ca7e0934 100644 --- a/src/components/form/PasswordInput.tsx +++ b/src/components/form/PasswordInput.tsx @@ -21,7 +21,7 @@ const PasswordInput: React.ForwardRefExoticComponent = React } = props const toClearable = () => { - if (ref.current) setElementKey(ref.current, "", "change") + if (ref.current) setElementKey(ref.current, "value", "", "change") } const toVisible = () => { diff --git a/src/components/form/radio/RadioInput.tsx b/src/components/form/radio/RadioInput.tsx index a039dfa1..db0819da 100644 --- a/src/components/form/radio/RadioInput.tsx +++ b/src/components/form/radio/RadioInput.tsx @@ -27,7 +27,7 @@ const RadioInput: React.ForwardRefExoticComponent = React.forwa left={null} ref={ref} value={value} - {...(value === initialValue ? {defaultChecked: true} : {})} + {...(initialValue && value === initialValue ? {defaultChecked: true} : {})} {...rest} /> diff --git a/src/components/form/useForm.ts b/src/components/form/useForm.ts index 57e19ab0..d96370d8 100644 --- a/src/components/form/useForm.ts +++ b/src/components/form/useForm.ts @@ -1,6 +1,6 @@ "use client" -import {ChangeEvent, ChangeEventHandler, useCallback, useMemo, useState} from "react"; +import {useCallback, useMemo, useState} from "react"; export type Validations = Partial<{ [Key in keyof Values]: (value: Values[Key]) => string | null; diff --git a/src/components/quote/Quote.stories.tsx b/src/components/quote/Quote.stories.tsx index d3c6a0a0..5db7aadb 100644 --- a/src/components/quote/Quote.stories.tsx +++ b/src/components/quote/Quote.stories.tsx @@ -51,7 +51,6 @@ export const QuoteWithLogo: QuoteStory = { gradient: true, borderColor: "secondary", firstGradientColor: "secondary", - gradientPosition: "bottom-left", inlineBorder: true } } @@ -74,7 +73,6 @@ export const QuoteWithoutLogo: QuoteStory = { borderColor: "secondary", firstGradientColor: "secondary", gradient: true, - gradientPosition: "bottom-left", inlineBorder: true } } diff --git a/src/components/tooltip/Tooltip.tsx b/src/components/tooltip/Tooltip.tsx index 721ec3ec..230c9587 100644 --- a/src/components/tooltip/Tooltip.tsx +++ b/src/components/tooltip/Tooltip.tsx @@ -1,4 +1,4 @@ -import React, {cloneElement, ReactElement, ReactNode} from "react"; +import React, {ReactElement, ReactNode} from "react"; import {getChild, getPositionAroundTarget} from "../../utils/utils"; import "./Tooltip.style.scss" diff --git a/src/utils/utils.ts b/src/utils/utils.ts index 076fe32f..9c517248 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -1,4 +1,4 @@ -import React, {CSSProperties, ReactNode, useState} from "react"; +import React, {CSSProperties, ReactNode} from "react"; import mergeProps from "merge-props"; import {Code0Component, Code0ComponentProps} from "./types"; From 79e34ece3713eb73b0a10f33c5e5942d1c75775c Mon Sep 17 00:00:00 2001 From: nicosammito Date: Tue, 26 Nov 2024 15:02:25 +0100 Subject: [PATCH 63/67] fix: switching to new CardSection component --- src/components/form/Input.stories.tsx | 53 +++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/src/components/form/Input.stories.tsx b/src/components/form/Input.stories.tsx index cfe2de40..e57e9340 100644 --- a/src/components/form/Input.stories.tsx +++ b/src/components/form/Input.stories.tsx @@ -13,6 +13,7 @@ import RadioInput from "./radio/RadioInput"; import CheckboxInput from "./CheckboxInput"; import RadioGroup from "./radio/RadioGroup"; import RadioButton from "./radio/RadioButton"; +import CardSection from "../card/CardSection"; export default { title: "Input", @@ -208,3 +209,55 @@ export const Checkbox = () => { } + +export const RadioCard = () => { + const [inputs, validate] = useForm({ + initialValues: { + test: "dynamic" + }, + validate: { + test: (value) => { + if (!value) return "Error" + return null + } + }, + onSubmit: (values) => { + console.log(values) + } + }) + return + {({activeRadio, setActiveRadio}) => { + return <> + setActiveRadio("dynamic")} borderColor={activeRadio == "dynamic" ? "info" : "primary"} color={"secondary"}> + + + + + Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt + ut + + +
+ setActiveRadio("hybrid")} borderColor={activeRadio == "hybrid" ? "info" : "primary"} color={"secondary"}> + + + + + Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt + ut + + +
+
+ +
+ + }} +
+} From 352019a5b6327d0f4eebd93d3d9280fb96ac8559 Mon Sep 17 00:00:00 2001 From: nicosammito Date: Tue, 26 Nov 2024 15:02:54 +0100 Subject: [PATCH 64/67] fix: made sure that the dimensions stay the same --- src/components/form/Input.style.scss | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/components/form/Input.style.scss b/src/components/form/Input.style.scss index 5aa115ba..fc574369 100644 --- a/src/components/form/Input.style.scss +++ b/src/components/form/Input.style.scss @@ -117,6 +117,7 @@ margin: 1px 0; width: $size; height: $size; + aspect-ratio: 1/1; appearance: none; outline: none; @@ -132,6 +133,7 @@ content: ""; position: absolute; left: 50%; + aspect-ratio: 1/1; border-radius: 50%; top: 50%; transform: translateX(-50%) translateY(-50%); From 66222ba5788be901fdbaa205bb6e95ef9b9111bb Mon Sep 17 00:00:00 2001 From: nicosammito Date: Tue, 26 Nov 2024 15:08:52 +0100 Subject: [PATCH 65/67] feat: test radio functionality without radio input --- src/components/form/Input.stories.tsx | 52 +++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 2 deletions(-) diff --git a/src/components/form/Input.stories.tsx b/src/components/form/Input.stories.tsx index e57e9340..454270c5 100644 --- a/src/components/form/Input.stories.tsx +++ b/src/components/form/Input.stories.tsx @@ -14,10 +14,10 @@ import CheckboxInput from "./CheckboxInput"; import RadioGroup from "./radio/RadioGroup"; import RadioButton from "./radio/RadioButton"; import CardSection from "../card/CardSection"; +import Flex from "../flex/Flex"; export default { - title: "Input", - component: Input + title: "Form" } export const Login = () => { @@ -261,3 +261,51 @@ export const RadioCard = () => { }} } + +export const RadioWithoutInput = () => { + const [inputs, validate] = useForm({ + initialValues: { + test: "dynamic" + }, + validate: { + test: (value) => { + if (!value) return "Error" + return null + } + }, + onSubmit: (values) => { + console.log(values) + } + }) + return + {({activeRadio, setActiveRadio}) => { + return <> + + setActiveRadio("dynamic")} maw={200} borderColor={activeRadio == "dynamic" ? "info" : "primary"} color={"secondary"}> + + Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt + ut + + + setActiveRadio("hybrid")} maw={200} borderColor={activeRadio == "hybrid" ? "info" : "primary"} color={"secondary"}> + + Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt + ut + + + + +
+
+ +
+ + }} +
+} From c048abec532ae58058d0a410ba73a77b5536fc6a Mon Sep 17 00:00:00 2001 From: nicosammito Date: Tue, 26 Nov 2024 15:50:20 +0100 Subject: [PATCH 66/67] feat: new switch input --- src/components/form/Input.stories.tsx | 43 ++++++++++++++++ src/components/form/Input.style.scss | 71 +++++++++++++++++++++++++++ src/components/form/SwitchInput.tsx | 35 +++++++++++++ 3 files changed, 149 insertions(+) create mode 100644 src/components/form/SwitchInput.tsx diff --git a/src/components/form/Input.stories.tsx b/src/components/form/Input.stories.tsx index 454270c5..932db229 100644 --- a/src/components/form/Input.stories.tsx +++ b/src/components/form/Input.stories.tsx @@ -15,6 +15,7 @@ import RadioGroup from "./radio/RadioGroup"; import RadioButton from "./radio/RadioButton"; import CardSection from "../card/CardSection"; import Flex from "../flex/Flex"; +import SwitchInput from "./SwitchInput"; export default { title: "Form" @@ -309,3 +310,45 @@ export const RadioWithoutInput = () => { }} } + + +export const Switch = () => { + + const [inputs, validate] = useForm({ + initialValues: { + test: null + }, + validate: { + test: (value) => { + if (!value) return "Error" + return null + } + }, + onSubmit: (values) => { + console.log(values) + } + }) + + + return
+ + +
+
+ + +
+
+
+ +} diff --git a/src/components/form/Input.style.scss b/src/components/form/Input.style.scss index fc574369..20cffc30 100644 --- a/src/components/form/Input.style.scss +++ b/src/components/form/Input.style.scss @@ -199,4 +199,75 @@ } } +} + +.switch-input { + + $padding: $xxs; + $size: 0.9rem; + background: transparent !important; + display: inline-flex; + align-items: center; + padding: 0; + border: none !important; + + .input__control { + + position: relative; + box-sizing: border-box; + padding: 0; + width: $size; + height: $size; + + appearance: none; + outline: none; + + background-color: transparent; + border-radius: 50%; + + &:checked{ + + &:after { + -webkit-transform: translateX(22.5px); + -ms-transform: translateX(22.5px); + transform: translateX(22.5px); + -webkit-transition: .4s; + transition: .4s; + } + + &:before { + background-color: backgroundColor($info); + -webkit-transition: .4s; + transition: .4s; + } + } + + &:after { + width: $size; + height: $size; + background-color: $white; + border-radius: 50%; + position: absolute; + content: ""; + -webkit-transition: .4s; + transition: .4s; + } + + &:before { + background: backgroundColor($primary); + position: absolute; + border-radius: 50rem; + width: $size * 2.5 + $padding; + height: $size + $padding; + top: -1 * $padding/2; + left: -1 * $padding/2; + content: ""; + z-index: -1; + -webkit-transition: .4s; + transition: .4s; + } + + + } + } \ No newline at end of file diff --git a/src/components/form/SwitchInput.tsx b/src/components/form/SwitchInput.tsx new file mode 100644 index 00000000..7b9cbd2e --- /dev/null +++ b/src/components/form/SwitchInput.tsx @@ -0,0 +1,35 @@ +import React, {RefObject} from "react"; +import Input, {InputProps} from "./Input"; + + +interface SwitchInputProps extends Omit, "wrapperComponent" | "type" | "left" | "leftType"> { + +} + +const SwitchInput: React.ForwardRefExoticComponent = React.forwardRef((props, ref: RefObject) => { + + ref = ref || React.useRef(null) + + const { + value, + initialValue, + ...rest + } = props + + + return + +}) + +export default SwitchInput \ No newline at end of file From c168f7c90b83a56c92777495f8446bf125378a2d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 26 Nov 2024 14:57:21 +0000 Subject: [PATCH 67/67] Update image snapshots --- __snapshots__/form--checkbox-chromium.png | Bin 0 -> 5882 bytes __snapshots__/form--checkbox-firefox.png | Bin 0 -> 8630 bytes __snapshots__/form--checkbox-webkit.png | Bin 0 -> 5886 bytes __snapshots__/form--login-chromium.png | Bin 0 -> 16952 bytes __snapshots__/form--login-firefox.png | Bin 0 -> 25412 bytes __snapshots__/form--login-webkit.png | Bin 0 -> 16879 bytes __snapshots__/form--number-chromium.png | Bin 0 -> 5381 bytes __snapshots__/form--number-firefox.png | Bin 0 -> 7942 bytes __snapshots__/form--number-webkit.png | Bin 0 -> 5651 bytes __snapshots__/form--radio-card-chromium.png | Bin 0 -> 10208 bytes __snapshots__/form--radio-card-firefox.png | Bin 0 -> 18817 bytes __snapshots__/form--radio-card-webkit.png | Bin 0 -> 10704 bytes __snapshots__/form--radio-example-chromium.png | Bin 0 -> 7597 bytes __snapshots__/form--radio-example-firefox.png | Bin 0 -> 11346 bytes __snapshots__/form--radio-example-webkit.png | Bin 0 -> 8064 bytes .../form--radio-without-input-chromium.png | Bin 0 -> 6588 bytes .../form--radio-without-input-firefox.png | Bin 0 -> 14643 bytes .../form--radio-without-input-webkit.png | Bin 0 -> 6800 bytes __snapshots__/form--switch-chromium.png | Bin 0 -> 5738 bytes __snapshots__/form--switch-firefox.png | Bin 0 -> 7920 bytes __snapshots__/form--switch-webkit.png | Bin 0 -> 5765 bytes __snapshots__/form--website-chromium.png | Bin 0 -> 6556 bytes __snapshots__/form--website-firefox.png | Bin 0 -> 8423 bytes __snapshots__/form--website-webkit.png | Bin 0 -> 6439 bytes 24 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 __snapshots__/form--checkbox-chromium.png create mode 100644 __snapshots__/form--checkbox-firefox.png create mode 100644 __snapshots__/form--checkbox-webkit.png create mode 100644 __snapshots__/form--login-chromium.png create mode 100644 __snapshots__/form--login-firefox.png create mode 100644 __snapshots__/form--login-webkit.png create mode 100644 __snapshots__/form--number-chromium.png create mode 100644 __snapshots__/form--number-firefox.png create mode 100644 __snapshots__/form--number-webkit.png create mode 100644 __snapshots__/form--radio-card-chromium.png create mode 100644 __snapshots__/form--radio-card-firefox.png create mode 100644 __snapshots__/form--radio-card-webkit.png create mode 100644 __snapshots__/form--radio-example-chromium.png create mode 100644 __snapshots__/form--radio-example-firefox.png create mode 100644 __snapshots__/form--radio-example-webkit.png create mode 100644 __snapshots__/form--radio-without-input-chromium.png create mode 100644 __snapshots__/form--radio-without-input-firefox.png create mode 100644 __snapshots__/form--radio-without-input-webkit.png create mode 100644 __snapshots__/form--switch-chromium.png create mode 100644 __snapshots__/form--switch-firefox.png create mode 100644 __snapshots__/form--switch-webkit.png create mode 100644 __snapshots__/form--website-chromium.png create mode 100644 __snapshots__/form--website-firefox.png create mode 100644 __snapshots__/form--website-webkit.png diff --git a/__snapshots__/form--checkbox-chromium.png b/__snapshots__/form--checkbox-chromium.png new file mode 100644 index 0000000000000000000000000000000000000000..bf1049273b99243eab1f303bc3c53635abd0544a GIT binary patch literal 5882 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 W_Tn9#W*E(EfQg~SjcR@O`2PYzmuTDo literal 0 HcmV?d00001 diff --git a/__snapshots__/form--checkbox-firefox.png b/__snapshots__/form--checkbox-firefox.png new file mode 100644 index 0000000000000000000000000000000000000000..321b967d29aac2ab85a7b6d040bb344e002b459d GIT binary patch literal 8630 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 aVb5->lch;n&c^@H2B<4*D^)34hW-ajc7Q+t literal 0 HcmV?d00001 diff --git a/__snapshots__/form--login-chromium.png b/__snapshots__/form--login-chromium.png new file mode 100644 index 0000000000000000000000000000000000000000..4996c24d572e04dba2201b1101bd2de62b8cf784 GIT binary patch literal 16952 zcmb`v1ymf(x-L9O2<`+45ZrapAR!P49^8VvyL*6v1P|^I2=49-!QI_0xVyvce0!h& z-fy41&OLXXf32_rL(|<=Z*|pU)xq+g#Lfw^9(}GDO>m5Fmo*HGrN6Gl#41MvQq0Aax4&j;y zoV0|r!&EVY>5U_eu1n4%k1jK}Zr7<*rdxwl9Q25^9Z$qZa-ZiqG2HDh%@af)s@S0|N2;ySaiuY;o_6Kp@^Py&#Ys zC<+F&3Zj4m{elri0DXb`h6)0`#3TfP(8<6c5b^)zz^t8W3Ow3PGZk~majF-k-@j3< z=X0Wf5)q?M>JK57lQvvo5iYMK6HM2w4RDw$C_BZ>1Lq0?HAp$uD)1=bf;}{@N8I^^YfkKdD z=d#aXpC~#HMI@?umY1qAyY+b(_ob&K-#RG>WB`YQ6deMF2ip$>es13jE5^zM^-*fn zfd;fSzX)9H;0R{5M3uY-VJcP67?(>$|Lz~8QrgxtvKDpgqAFq2%#tD55na5Yc#Asw`H3>H6JeU3?*?$hlRepL*pr3dFQ+b zD;aILoy1|fRePASg*T|mfNN8?U`Bj&aPZc1%fQm|rHI+>S=V#V^X*CU3N8Xy_X)37i?j!K`3V=l<(>4xb@Mw3<5-1Z3T&8DaAPzwKj z&5SPJ$t@3J=7H4`|NS*Gygv$lX*!>~kDi`9Mbv?};dOU7-r8&5lOJ2hzW0k3HPlpv z{R7ibsH>~7@$ML99x8%iaV^FdbGr0xFt@c1D=u=GcGKll!dHZsUy0GTmzpr1FY;Q+ zA=7Gc!Ce%P(Qa8hk<63nlBVaI8CK0j8Vx3K;E+3AT3pTshocR_1qmZXY;SFmLAHic!Z912PVeAnrk1Du zFcpg^3$zeGC&8vh`N~p|?|qzmJWHGc{+Nn%c!-%0csvm^JG-n58sbm1A`&z)pUO!< z>5ivis6|sjm{O9GXDR7fpFSeKJwS(iAJ{zW>Jj~wgAK}}NRJvD9}mL(TxT;h8+^Vs z^hr*ddhuv@*ajkRYAUxX0Q%wvTrpM9F*tV@D2M0D?9Z`$WAI!hP{orT3`~&(79GbX z!NH+b#LV#51Fpw&@v*7-^1Y#3Bbv?iyb((XtM1+RVybB@8>6lncd`QBckSC5BnJlv zx9g#{*N2|g+r!NKt~RHSH4P1it207uLPGVrj*oYT{Y~z;omMd71C6sivi;yRo^6Nn^*+&e2hhxyM-6i)`An zm&PYbj~9=Ut&Em;0+0UKhA8^vqR-t8IRaS_vV~ zt}^W%Y*y#-muQ!=A3o3|gi1(BdFcM9O^Gp4PM$PvFJSd@CXERUP)M~w=6#6&r*x1U59a&8}e(z5Pu9p>y zl(H7A!ql)zY&xMuR#*3&Y;zfg*f1ek@1AzvH+y37Ll5zg1CfvzbY=p9iK^(ED$n}t zRDLro?co6LbQF0^9|ME5gF_{ve|}L>t8ZCQ67;eQjZZsBhURd0?9I~}M6rObj837~ z7&h}{Enq%3_Z4KcG(l(5VoI@~)1*qseK9dXh>}a?1LhH9f^Btmb)@!yt3a=4Ys4p%}d0y<8XUgB)3q9=p+Fn7$NWl~- zYkg8QG<1|5!nv|kE{Iim-CtD+w&HF|xVpO9?Xb0lH(XCyDLaQA9v<_ML9SXJi9~=q z-~M{+TPvYICgAt}#|%cQkn5aDRTbgL4^Q$*2Cr;Ib1`GdPZ7f#4WNck3IMoqHP`? zYU7H%DE*WW=YDq)I2>^_ICz0yXZ?e|u(tLc4{P2JyWzHguZP@CiUp_>npc*K6^^0y zb~_u9(C-o_;VBH=OUsDe5O$kw@8ggPQi1#y=lxQ7y7^k~jbtvyk+h~klYQ80|0x5M znh^F66?109Pdmpin{~=0sF17tpy)eJgiY60`}2H^eY<7RT=GS||@QwvnD+k`x44<>Og~PcPQ%wg4#e6|*ZFa%Og0Xz(#xTZ&B5jt0 zFi_kYZ>& zXDcwoK?qrS)^g1o>(qR&kE*5`Qduh0ixu+R1b+ASn%%ss(lE3r{8*%-+w%F)p<&P@ z^w^o$$MbD?uq|@l@V$BociqB<6W{B-42xR!HVlA#hWgJjZS=I$KeVR@~)z zc_VskdzE0gx(Hbwiv2>}H{B$^f3c(1tUQ*xzd(r49Q|~M5JEULkWk7`{3)6WZhKo! zCK8N|tupw7qcwRb{znEk4z>zG(BoF!@onzKKANHF54w;nI+|cX(&$`sV*JRatEi~4 z&Q5s9=&xU^NfY=p#o8K*m3MnJDI|y58!WGV!lmNIH^`CNN!qR|iE%Oz`64ktYgQJP z+m*`DI5!EpG^GtqOB#=#c#_kp`1c=P)oa1epgFzO1{ZMJ?RR^#m%F#w;W>SW`%@td z>cKzt5zz;3TBT`;J!&XSMuxJ(pmx1pohF8z^#^bxpeT1*K8z*;=JYgL=D znHYvQ>u$m)JE2piMt33Pkjlkq+veZ?VTF_{>0?MJ3S6XKr@CNS%2X==XVO=;63CIU0-G?Otf4)yoPO4x;eY;o&r2Ud!~-RkUY zc+`$W-%uk5LXrGB@eCmjo=O#h@Qyp^Q(+-EN0A&8u`|o`C7FJ00@>o{@Z`tD8~8(k zj{QrZqQFq3h@zvXZ{s29U@J?=r5oSBRKy)}`00NX_)FzsE%Hqm2~R+q85@DLlo|>= zEaba7(|Wa^pJq?)Yo?}tAN-dtlsg1L^T$53&9HDi%w8Db-TE=+MoW!c*huM#i9eJX zX06nePdsBQ%#}8CW#a}%T#w%sLr*sVR5idTwLI6FK=!S1-eYUg_6Oxxxp=kM=F_bK zcwx7eW#Gp#&V`xAjOOOlF6j{Z5DN<{sOvG72pyNKriuzpjAYuUna6uBxJLxYXjkYA z0F_$q=2@bt#0;XkEHcntjLbBALL z9Z)_!>b=NT&1;6bUave~X)wvP$}&H+z)p-;n^a95y5!|rxE#%&bzIYib?bj(Hd4hC z;I#|f_sCl-(IPWZRE#Eiogt#r*;S}AP+92=3uD5qS*p|0#l=d&JroHLw@gu&Sa!75 zcm&WY#=r170}?{$IJlyi3~V!$vhzwjN#tf(hkGh$oz8yE!i}(|EBPGD`e{aFrEZh+Eh&h; z=_g&IeU#ctX%fDJjj8Qsp@!nG>+9 z_mC*ftfPN064hPx)pLld#&_4bjQAA;nLCs6$_}CWkWIh zhsT{=T<+rys>C0H1ifI=e=M|D?xCjWg!2#k{iE%zt$h4V_QWIo{i29N>1oHVxP8vj zZx7e|!peSz<*Nzmmov42Z4Pm`yA&wsq;U!hDvTA>U!@@NqmuK#k2Vq)chz6h3TWe{ zE>mVApTIA@DpfJfQvB4X))-{jk|m$0y?XjxJ5A7Wdk9SQ)xpv6XxW|D zg|t+YXx0ZFR_$@GU-(@0qustx;|D&NX_NL#8nPlCxigra+FZ1fu zgaoYSo87&Y3RU=umuc>iX#I12T>~CyDXcY>aQ;g?l z8DtbH4?MArQC~m3FdZ$VHIyE>*+TtH5cJmhK&>s%8z~-m5Fi=k>y?~q_Jz4P_EQz| z(wcm7ke$1r^#L7EtG?ZyJxCu9j~ZGOFoB0Fmt1eIZt#+!-tKaKpA}dp;L!+C*T}b8e;fzxw>JuL(A$N^p_fqvPIm_ku-0#~} zPB@WKSn9Gpky1JB?ZcSbOrf#m1##e`Tv?0>6At%6xpS|0o8-xBW6_!4^orn3nalnU z_A8f4-k_ck1tWN7wE#>8dX2c)R0yWWL;ae`CCL^)7E@6+gmn#PuS_^J7E*|e19X~L zPThuTEE3-ra8hxzfwhkhi%73YmCDLZMNJK*vU7%f6WIg$+3AuseM}#~p=fDoJtPzv z;-+VK0vQlvqoQ7^ADhlqis8^};W`mK2JubSLdxVgRHS&iw8JPU%^HXx@}8b*vO|(_ zQZ?51G(2li&uj8~2KqIWZuqAui;6%7MeIUVsr>XXytw5EO$C}Akj+X(-LFdHz5K->+KezNWO!2foc&tm+7d75Drky|G0jE97o_^ z*DpS1t#GnGF5#=wwxU z{{glhZHh38x3DenAuGbdb=N&_j=v`B7yr2Qp;4?iTl5f+xh0NY08dXcEaB?1^YtU@ zmLiZF)vCuay!g{L=_)%0TAV^vxz1~-Kbkd+r3M`SBO zn2?1{iuSTttm@?vQDpoI;*Wn$ip#u&i(l~#m3z}7Iwoe&1mz#6gnwiV(*LV)aqYRZ z3cDp4ze2#mFGp>vHtN*@#Oe#jQ4+ZF!ph~l?FTz8ChXt`ZYpJM!q&e!r_+QWpwwU1 zJGnr;k)FlvL2tb%7bjN>jiv1ctly`E3a{IBVA;P?QEX2zLAslf7n2g1l0urmS;_q~ zK#=*qeB3DS<3AmDT6E3P z)-Glh#J-y*f^pT+esqvrj&Y<>l2E%GmJz}H2%c{loIO=$iV&Jb1gMYNlr=b2* zlfAxK5n+X0Yd7JS-*b02dWKa?S-p=RyBpM}Vk;6sVQL8;I~N1wTBBYphpz_F70=j3Ut+Qy}$N#&to zZB3t>C&(Bt@c_DVDJvc#JpQmQ+TDz#=J87@9`;=QU=qybzc1Bz8_fhW*(KL-IVm)- z5nzzpC*gnhY_n-lY`mra4EIZ!M}va0(t<@G?h_0M0tS8n+q0&@{yGmT(`@*&h%TMe z#`L|rIXN5=;^zf}`E16Le{_Aeut-0cui@g7WsF*V6%V@%ruz{wux+2Ivg{2U2r;q@ zgC;F)i8sR3*q8!hGBRu$5>-L}87C;kZh~`Zp{Ug}VZk43QVRwI-!-EU)bqi``D!qY zXTXfOe`u(|bDR9$pL2tVkWf}eMvr}iTS@BK&s`c?1NY%o4OEvYa$U&FY+N0dl!6*3KBmzoThk;BQ!7 zSLX+dkUyWy+&el{-Yj^5a;Zrp!Dh*&MJ2kmUJ4()V{9o>vbZusYJP8SGU+JFC@3o# zp0{{LCI2x^7;#qsmu4D=Z&CIv*t-FZ6%PulBTkDwONN`dNJ z%eL8{9{W5$4JNr8zHVb1yoQr&c>yZ#Ja&|Mx_IMz?$H9(#X}bR>`^FBmraLE&RM2c zJ7p0gl>;T*8cdp6n$lF~tSc!An2CS^QQ%Bq(14RJ`eM4>UsNUO0_uWh@VVGh z$=|=n84WSBu`wvEsdlm9{L2g!xHZfs)5>-1R4Pe`yy1uQkT_|(idmDY7~C#m<8Pu_ z4UVSx`1mDdpL+%~Vq&INgfOd)U_i6qw2dTAOrzKZtj5h0Nd>*aFewD799ayf54>7@ zR(scC1_z5&nHd?9Q2=$`sKeIi;dDjF$cHV3*>psULNes`a)1?`UFiGos$M##)P>2( z1I_YX^8roU7Kg{Xk{=~YE%)Vs^wN9<*b2BbqC}+wOiOB|t)sniz90~Lw1&#b>My)f z>9(be|EB%&@5aZ8mUxgno!7J4J(yzxOXMHQT%09Jks2#&8J)h6AVYLCjxI1VY<;hn z0VR+2mE#kOgOTPQkJf5K*G$3+j}@KVh{WSr=m!}UmICFo;ir}ow+!xWyq;HzA08)=xJ48ud)|>O=W<5Z!pf?&z`gSC%An{C*OAArScxigoRk&!eN0cd z`z?o}5*Pd$)ZzA{v^2j+J|Ok|U6Z4P{84~`*>h^42xH!4R7{z{cq-_uxEM8M=qRV9 z#d{1&T?WjrLd*r@UWJpkZK z2Rl3M_FjuqyH13IgIy@03=C4}Z{E$#6tO1j%GYEzx3q+2<-f$Ruw80o#0{ynUa2=3 z>UZ2`iCh4h>Tt9;fi5j6UgF_fAE;64EjCNINl)5X&TkpELt zaV@F=VQa~=_VRKsynD^Q2S*0(A^oY@?g`nk_Mm6s8cT#I{Bzzwy+gzNrUM|{T^|d6 zt~c|!d4=fz!yNeNR(7SjVEmendj%yqDT!X`sGMJbwDL*vr!s@SN%?1Mo4TG|C+50!%#|AF(8LP|1SWaZ>C+Vm!kjVlS|*w9Wi?HlifDpD)_RXY=^LK*2T3f1Hfg ziOc3jt*^J+N7{%m8~h)lS<(mDYs0!Z^W>+2jOX2JIag_EPvGC!gFE1_JOMiLkcsqa z><_dcB1LWyX3M%cKyHhZ(qi$K<@fuEmRpgyoWRb>S$w?DTBgnjK>5#?fG1>Wxt}C- zd9`zHx^-4(f!fimlbj_{HY2Uzw2BJ9Hf=Gv!D7IPzJGsLRM;OY75JVEGqiIp@1C6? z?8ArLu2B52w0vb?X2WJf-Jf}lDFSX_vXja`MCQoOys71!to%=qbL}W)x2_pxf1nx)qvQ;ajOru z&(q&^B=lxc2fz=ip=R{-xc?|VxQ74M<-kf~4#gIF369usY1&xpXgryCB!25v*_`zo zTPdmNKe7PfJi0W9?faLcZ@n1)RsRZlNNVs=q97QT@3t`?H8xLv=W}4Sc{hH&ykc6% zZ>M$O5_#^2A|SMy2~YN|nzLli%DHK&pdcAo3m;A%k?P67kD^!d{_1axztHPX6&h>I z@%e!`Qkd1smi?PS?=T6;z5!YqfLHXQJxc$Qi;(}{vj73J-aU|9`h*y=MR-X?Trqd^ z`~leazu91DaFN9*GDRt(q^M#2*tqw@#f(Ndt?L%7xnKI9$$~_K6Rx5;B|Rh(V%Q85 z6$=0+K=3S=za|JkGH$d;Hvv+p8vL*Gf&Cf{Yn%48)ac&pHH6k}umIItBjTWD5E;Uv z&GqPadS$U2vo&@wU;s>6>05-tfegM-&|h6+>(FrxpIk|PM@Wp{do@S71V zAdpe}0t9JWF_wB7HimbnAOw+d-+02E;St&i@q+9-S6*X6|Hy6sJ4+G3E2PIRNNGKk zjE9^;?B%#AY(BVgbxPSh-Au_y%BKDO}_a4B9J5LXPB84 z1!zJlb;OteH6X+5OqU?&>5%7`g^ooO5s#JW?y~i;hwWfO?rA`e?NhmTaxOLY;;s|P zZxz&B(E~H;E7+%P8OHtdpg<&uP|o{2`d_ zY{extFUdLi49F!b^E^R+zDrm8{uQ(F-0<+xQ?9vsCbYRl5U#HeN#IX2#2+XF6g1DX zYibPpqSwVE_pGKRpp6R)mWa+Q0TJW=d2HOSPi7osc8zQi?ve|W8Y6yOXchw zjmuf_gA%uBq>b1TBy6-=NjBnamOsyrEqm_$=K3wR-=83z6HVX>`cgnW9Hn0~Z!*}c zNcY>%7XX)5+@y?wY_U?e-^U=$bZ@E2eNAe|c-yauU=qiHg3pvLYc*%rn?ZR`P|zC`OtU|C$Q{b|ruXzGuhqHqR(#ryaCpt#H{}XHuwWDqP4Qv8HjSc1)!vhWk zXc zXUKxSq4>Qgi<7#wNX>I$M^!5HpPUC=YS|n`@Ji!vxX72V4h_UT_D}OKLGaNMcJAe@ z)?z4;QGWXB4pLd~5#PvxzF}ob#KuMs?latY3!%V^0PyUUTvpjE9Gmu9z4}i{tdpxK zNZUR6m-l4KmWr_q)a&ljAU7ZVM8zB#g}lzyTB1wkNj7_J-#q!6>>daR_u1cA5 zy}P^f##yqd>*M^askt&aJ2*iGVtYKnBP0k?X4rhb%Xp(t!0l*q1b{N3+ikT^d5*)W z8cW(OfnttHy@_gU{EUp}1FTSBb@^P@^rMcfbR1c(8syHAMpOmP!hl8c4^7;Lk~WuEC)`P zfkH0J&&o>W%>#5Qzt-v-GwkEY6aXYI_FX5kDL$#>INaK20n3*&6i3c@@a z*GbMr^0#Xe^!9!f&LcqhT3tYt+m=*yR{c3#nL!va$AT+J*wDa0L}9F1iFO174Gjm< z^dzaIZT*;B!`O4xwn4t1!Kr|o^f0l(V4m#K@D1>J98Fovv>G@~BEw-Q5C$AT%_zI?g&~b@^|Y78Vw}J3CKZ(3x6jJvo;Oj#G%eokW3huTkZn zP)&YA0~f0=f`~*)At?a?kTx)>>N2UipPrpqNQloRS$G*G!D+i}Mcgy=^HuB7<;6vC zR~8WYfcC(A+4Wn=%XtL2B^6?w`K;5!EMeY6gUMmY--#}WT-kf02PiE-qk;4cFb9hR zL*y5IK){Dx!UB5wKIS27gpSoLF_h1m^Efy-FVO&dI@SIj@TU3FXg{So@}&u9&>vp5 zPmsds1p@qh!uMh5+6FgR)Ny;5g@xs_ZcRiIAR2b1;#_*P0E1Cb(DBT4m@VleY@U6a7IWHU3+AJ!+bu>xW5qhr>JI0&(mpSP5l4wqY4{#c4F&N^`E?b(?&`tF) zs;Zo+B$I}o#NU9v{4ltdnbxQ}zr6DU3_);f>F1i_e6!M}BTU5dD6A?)dO6vt>e}j} zDS96zOp!E_CCysZx#C*D+xyeGCD~4w9bcUh$*blRbyunZW(R0)HFH)~CfoSHDzvq_ zR#8-|UaZElGF#nn77DilR$@c#uxEF?J0DKF=alWSA_gUn8{iWHU^^xG$@y*7KdAcn zLXmE*mAyz-|0V^|UIxJ222*%Efe~()M+UjON8^p)d2-^a&V-tuuD<{rlEE@H7PT_< z3ZtH3X28BTBj)qE`F&E}XL~p_WPOg0%c7&GrFjknO`eagk8vQLotzGbdqeT@SBYq_ zASIIjLI&s(`+tdI{--%-wQFx`05D=7XlSTup=W!;D^Eu)*S$6)+# zsD0``sr~C*&f)#C*2&pfEv0j#{m|Ed_mLzsKk*Y#X_0g{{!MO2N3}M$+${Y)+35bu z;f$ui*egaxO(l6=ai&+Uu9u{O9(;EFTSIY(nH;7pKs+zLSTT?44ZllJ!Rz>f0p5p> z;2+)}5pSL4aufk&5-{M(=MHq{7Z&oaU*lxTS8s0~B9a5b$N30)r4{$iNzi9inwU7X z;-QfdF~m8m+P&98wY4r}|A&0AaycIQ`A`1wfAf0%?SS2|o z77Xm{9-&Q`wjLeMHgxgwUYv^SN>JSZkwxLU9e^QvdS-|r4VVNV|2sDSyY9!Qgf`C7 z3FCw1s**A_TTb+<-dE17Tq-}O3d?j#TpF}Ys;JAOf4qqwasYU;&+WML z*AB^ODoF$(?RL)Pi3w9S0%wh+wR@y5Z+t9$KbO?{!34DF{gFgtzvmk)j}Ph&nV_7T zMF$i7L%jCU`CHb7gq)L&&28(Vi_20iKDHR@acCm$skVv>WLenQ5>rw(?06fS?g9BD zY|$!5YR#!Jta}ZhdRBME%Je|uhHR0kNiZrCv4)9b$;P$Zs%O)wFIzF51Mb(iT`|?r zxsVNmB$@7qe-ij}N76`f3M6-8(vJrI{U$Y(kbiRcug7u^+s}75(?h<3ziM)F9)XP7 zV#~E%PsET+J$%YIx1*|#kB^PGxSF`<_Fz)OpA;`=UEprjo1!k@5?feyID{d=On*`M zK>?`M;6&JSF-#RVY5}dcvV|^bo8!<&lo@-av8Nj$LHz*b%&O<78c4BC?mqd zR!9(^%0omjZAw0pm}va8pEV-VsIv(d_2(FI(HBYwmE$&j#b*0YoPPG-ar%D|`7uQR zU6I3~N_VA6oT3e>eJIsfMs`9~C9cm%F>k{8*=Oi|D*)6>S8%uBlwDoloOvWoytFPM zG2fl{^J@dfm*c_gTxBKxve&*banGSkPe(@Sh8;Ra&*S5&1rlBsm!>%%dDt&G^tbY`E7TplSNaZ8(i6!;s&xx#$%S(bmID|o8DCH+ z$YOg*r7-t@qW&sUDT+5X-iL=Bw5ru=@jy9)6+!#TAKe2 z+W)un{@<2dWz3Qt-XgWjey0*sh)oE(V*!bxpSThGRtrx>U+0iPVghDyHG68x!T3p_qVFVNXRUC<9RzqD2f7sK>iP!wAFOp;yFUNIoH>Yo!WcpSbP?PiGVG^mb z?)vx}>)v|Y{!K-&lX}+!|D}(NA&)d`S$R_P9B#$v1;~!AAp*QLoKoX19XDmc@9}%` zHt|=kF0UvdfLsoQ<9*IX%09~cWYXL@~vD zfB9r%216DWHdqbhIRVrc5YRoTY^|m?a_gvuaEFG)nFEBMuAf*x5esRa@33DBcR zhH7mpuKP4tj6cm1C1DqmRaCZOYrXrCpfF!6E+y{+;#=ZUlx-VyjBt}Z#Q{dO^?HJi z^4#t#+DJ{G)2rduhix?=bpGnMt+)M>xbJpH2ZMn2ug&Yr+}xlRM=@LF@=)Z$dxSkSvL-%?t%FB70IB+zZSt zqN(K4>P^@e8u>08i#Z|RSr{MJ0)mQxZ{<~8JWR!Hhr+YshG07lTgd`c;&@nnS;2Iu~>u74jr1{QwA|AUz>$BSZ#q^N4cAED&vT1FtQ-hYMn(0d6 z6be=lm_unKwGjxy)^@C&l_c9?IW&ab&h6TPg@EvQ-uayO6ZFlmYS*=gsTSJ$lX`vS z;YilR!&S}KRjpN?N~^-5t$WC_mCtTb*3Cvms8QvSPAsk7(sk;GetlC@Yo&#=%cqaJ zWo@!<%{sO=rNc(xCZx!vqu7BQXpMxiVocw9okc?EcPZ+@5#&IotTh-VIdRXKxB;H! zx#y3MG2Q3erSiDcxX7+Y^NO6UtLuS9TDntVfJ@EqVx#{ql1=FTT}h`-Dy1R7Bcfw) z-Ut@Q3>X81Kg0K`W(s?V;Wcv3qK)h9;U`F@@xb;3Co`Z6;E#-1#FS}4KSWKAj_wrC zaR5Ws(z7mI(0hr~iaW)c1>XZn((2Vkral5!VJ z(RXy@#?TH=O$!A7r~#}h68^eWUZ42BKWSUP_vMD$fN6Cjpu^tRH>TZe$IQ>q!KitC zYpT0YtWZibIllO|jLi3$)s;W3^DrfHe%?c8zG`hDAP=|+w_~+3dE8AWZ2aM+Z2G(9 zrJe;BqpoX@(?>A!jJSKM;*jiX!ryYPs0>m-)Nd=3Q=!O+Rz4(=x|QTx$nQkC+ZlPD0`zfF$suLub5eEEcbz2?uBR&9%z-8l0)zT zHA&?K2D;YTyj5x>IN}YzClJ29xq<=xTF$QTMFu4@{6|m@Gc#ZL`jQK8X*z34nG8w+ zhja2|B>~C}&rg_LJ4WkOGeU&7dw|Vt$!}q98MBe4`@P>+?A21yWxy`S496y^H^%?e z^PQ)$Bv{l-8+DTr>~$>##}+QOseOcYqrYBqdX4a#6`XxC2QTBQu8fZ6;{mpu{EUML zY(0tXYK~exyr2!DS3yoEdZ{=5?MS10r#e@Wp53Z2?MW1|Z_|Oe=hpJgmp<~d{hw{G zQp_x|kyzAvDJ}hg;3`~4`R`a!Kg@UOUv|T9UkXNFyO+yR;8@7gVN>T&iI+2ZK0q^G zz-Fozy$apX?R^P)r$3UuG;CvY+)CO`bg}UPQnJQdI+l&-b}!Ms`iKemW`$hzQgPU) z&D5Yyyr4&?$yJhb-wbw~7J{=Ur+yBpl0QPK)PEtQe$Z@lg526{UNmKL>~scK2O+UV z0kAL_h}XyC(-~ez36o*=Z#p!j_TX@UK+v`Z$^Vgz@o)C1=JzB0;$@3^|D6hpt}9Us z5*(Olrugt-pW3`E<%~~q{wPx%kyWzCqy^AKAT*t#<_`LW#3^2ZXY5fR9Hj4BOv(ez ze91&k(Qq!EzTPsxmRAu>q!SHE*e+bRMm8GUZ(v;5oY{$Yd(^kG;gShyz>dvCWvZkU zF!fox_>cBecY1>18IF~VlE9g1n8c7~#Nevf#MqT<(l>0u60twmo$-JR-{9m8ya@IZ ze4A$5E*i|{Z1GMH>q`M5j(+<^!6UqbLM|+hY+Da692*`|bau?i9U^U_Jefr7+2qY6 zDG?~kX3vL;Q2P6q^GUFl(Ti16k+e%(MEG3`w5y4qfwDl9#jdN?l333Hx;zhD>;aVq z9h(pwd=bvPAYSrn{{DbwAQqC%c7^3!-)Pfa+9wZfq}uW%j3pJ$061B5dwv=rK+ zccm5MK50-_@Vla^Tx9GbPrNm9Zm%667+>(Vn7Rws#ZXK~?vL7&pu!)-b&o}fVkNVU z2ULynOfhY)H>S6~hF?N=_v1@@r;N!VR_OPK^WuXQgD+W+1?>+NSAOV=Yvl0JYtTeB zE_OcN_0$Z>D$I+j0ym&%`SIgcnXdcKf|kRf68`Q_Gp}E^wz|bzT53x7TcP*h(?&3C zp5aRmNJbZ1y7$Yt)@$je@*Z5dxx}kc7hpfU8XV0{Yjyrv)yk@r(pc48XgkWr$p>Bw zH$(wk&)UYjOW((ivK@_+oWOXZAt{>)1w5zvX)#PBsT@%zRa$DE>bj59 zpZ!I4X(U&SKUWPU|4_cmT}b;Be^`$w64G<=5xYJP<;$sii_QuOA<*Wf$2-m%8h$~_ zbp&RY*DTn5R3k@YGRlQa+^M@8Gi-%W$Z(hhqtInxw>fSZh;db0VOI#KROJ$B>#dK*^y4_xWbp6ZEe_7qe+AOTOvRbN_w+1Kj)6H8Bf6&h+Ql z+}wO-?v#`ZvzX|*k|F_*O%Zrg9`mm~OJ>MIawaNm0dQ*dwWvVz9>QjXv+6%~hun5G zPCEI4s%EWtNS8tnEWXX)Jtz)z3LAk=I40@HW!CmnHmp*chi`SC-cQnDg+t+C)MP+6 zgdVXcjkkBSeB8~XAwj($vX9L=M7fn?rfBO}7e?`vF^G(>0fQL+(Wo^I%=e-X+fO8{Pn5t9 ztwIX)Cuhr&1pU_7 zMXH*RU=)6vH@4F7WjMjycCfHvGUg&NHFemNQ_deLHl*i`;6?>+z~(Er{`5}t)l YH`vqJ6qad$S3!Uz#XgCais<;v_!$A=85sEafr<=# zg6tWLgn&SeAoKD4S697*W)xQ<^@NgUq)_Sa(MZ9m^1}i~KV@p#1?HBW51m~`&eB?3 z9<~;f+`xx}Y18cs)@35R%Mj~S_GyN#RL5ZfnK!-_XQj4_5Z~-jf+qH44)n8%^)Qzoj4*Lt}*cI z`zabLY_wA=W3&@$ip0~Mgy6`hi}^bm>2#AbP|Le7m z6*JjemCYeB-Wn)y6*coeV-VNPW5xjku;CD9nIXa2Ct3KfK&qwgn zQ+<_RD>D|9OhkmmZU@@qr%|%ulhKg4q{R+mn5#NaJR{j`7>yaT`N$U{7aSK(tDf_Q zu~n9QSXKs@K;|#hk5f_cfx2HdoFyYuXY4d&LlG_QkiSB+Csjwy9rTT8OsN{xz6`qR zKFuJX7!h|%@H~6tDys3tVWfEccXY>|+Z*YR-sQ$rt*`Pg%3uAPs0CukLW<0L`(_?&MgMl= zLyY)IW{m>~F4M=a?xt=d4ynK2e)U=)Al3sgq>BJU)AAu;L#qA7JsXYRzIhw#m=dLS z6Zrh~-~!dFcS#;>NlyLmo@_yx0_`Jxw~Xhlu|SinRIaTUHEjNNC&t109xZ0I|5lC3 zOX|O#Xz^V<4cZXPof)yOF6L+=2R!i+!)Sf%q$A!MV}$W(d!iZsSb37noUbIyE&#(ST`bSa237=c0~a&`DgnFK95m8(KXiE1FKzf8y#*LC}m)^e|Muon%G_T zr}ZAL^&e_e1soN<@A)2;v%TOo*33I|wTVR<-q=;&yy<6eSJi>In$h9Kjq*!|~|lm0Qi=DYq=P7uuOdf^B>@GD|& za73%xf@Yj5+3-Prbg!$cOBSROqto*3lUj)e<3NI{H=f%zwpdLnl62ckUoHBdB$dY87OJCH&x7B+I+(-qtv>i0u92VqHDd|uyoj)vKDYT^jqH|$ropo2_qgt zI`=uBe0_aaY0EG8@6@D<7vpcXUZ1CM+8O9;R)VveZij{6ejXq)nZHsw*)8OvqveuY zyxS>_aQ!KtF02S{xeC{*cTjye61z{-X>`t}ocDQvi;=&-REH+A>C+xH--52My>8B; zAFo@zY3Ru@Z*xg}XzJ_hDHEQ|(ExRV9Aq=kulaCx;X^ub9sz&cWTm+i^SKnuF&(kt z+&jQAKHtSc9@h4`Q2NvbTQ9i%)~sHzwh&yp)XUax3F>a_@KXWoMl8A z`_If9A#PW}?I&USO-zl>2k}1lKCP{Vw|R>`8BNEqxC)C&!6XsO5^k$$@x|MtC7Ji2 zEaBU;LYJ3RsGvX|?85oOxXn7cCnMJ~;!sNESMxp@tK5L?&7LQ)x$aG+o#;PaGn&s- z)ZcB^KEmrbydO4~)I!+B?gz6ubs1j+TgF_dR0s%iY3#>rc%;oe9mi*v9OH&1HTJ_8G2+sA z`8=?2y>c~^BE4okbra7wfFb>=><%ZRDQ*4xvpjO?ZszfwemsZc<~XNYzpH@revYQB zsdc5zpUjrKxz@*KIz~oSS5@Q^IS}@5(|`ziUkh4XURY{kB4bZfh69F8*GYAS+o`jz z&t0O^poT}d(;%+8(jIhgGK|Zfzig9VitlGCzrF14WFe#VTy?^B{u{^QP}an3cJ(>Z ztpI82byP?My9e##sFZ&1&!YsW#Nq69-oO_2_Hb)yi_W_97FDFr`Y4L=pXG-JGI|w< z3fsPP5tJOMC{{4z(g552XHKVkuF%FbpQ)UmdxBte$6gU;D|WQ66u!|Un-;Vi4p{<@ zk8e~)RZi|IOXXx_WE6P(;q<`al>p)pTN*hTnfcwH+y2%197gRZZ`XcuRy2r& zo8*Wi1F=A){Lc6k9I^hd;7GVhy@$&i^b{I^X#V`kK>z;~&7~E17#SF5*ID1adv`Je z>5hm~K%DjS`;gIdf`Ffo=?j6l#$~nC5TQE~UAR^;Sbnl7032f9hMaoAv21+l%{d>q z|1vCbpx&|Ni^=_Y>0)%0=$%f9zEa^`z`_K(nX;JqRMGEuI#=1(ET7$JE)5kD49xt; zZ(U}=c|AhbQR8cIadBtYZlAqxQ#2WlHant(Gk?zy4-CKbNLAZ7cZL5Y{?pH_q1lUZ zT39+1%~QzNJDSbN6r5?HM8RqNeSgm7&pImRCcZpuzR9hC+iY4ql2Vkxdba8Z+GRw{ zqxVrZc?SumwVnH^;@tk3Yu>@{-oGWV`C<=K8KseE=EPF99Kooq=^kxy=8}&lgqyN$ z7e_B`E8c?ST@Htllm-WnCgxjS5E?R@%d#Hig8I0`IcCV->Z#8{6MJQHoOc!`IH=dg13NweWw_4>w! z4C4V6dsI{uUj__tD%?Jcj!Hryp`o!7L6Q9h@q0rf%I+8Y49`){_Qws7hS`wgDsIxJu|ERjz?ekx)L#3xWfO&cKR$zNH? zNf)~tXc7?;LW8c`&EwY3ephbhhPvBDbcH1(ll+muQHl>EDeVnB*QQe|ebKI8^DQ0- zEwhw-ZYQpe?>-vu-d`pq3fy#8Ff>=UFK*FFVaH=%R`K9)-{9i7CWF;|c6X!(TluV} zUq_JBC+}&(rL^Z<%nFUHlH54v`Rv0(+j+bMica}?Q)|eO+ryKTQvQ0~P0P@-DeXiInqIyLlc%c`l>gimbMbw5vzPhzn=V+r;1J(=C(GVu*XU|8Mv3t8$Q_r9p_Sw9eK)^C|L_=UZy zkWxc7Fy$?bJR`>@##m`O#Njvg@x}Sf)~m#&d*>QFY+IOB^Iv<+SDn9^f_+@~M10vA zzHDJvY&Yh1`;~`^!K^gbA8IVy+C<07jZl&vchooF<&B)4<&_wfrAE2}b2H0(2soFk zpXAoVwSv{`83!L4I1Re8^qRO2&NB}~2zq2y>|^kRewdFl3}6urM%?(pNWOw4f8l*2 z3`Q&x5sp?AJJt7D`$XH%c%ExX)O5!#32wgk)jGZ2z;PS@rSOzsFHEX=2DHVd@Lh66 z8FiSa+@2knw@g#(y(uH-kn*>m=dSM4WzEjdm(GA$QH@-*bjjh5%q6hQO(xH~z#Ty^ zEsxlm-q_|-m+I?Jp_G(hHg@gL)|QuZY`SN7T|`VwvJtzi^*a?cP}t&b_E2Ro*xo>0a{KulTJ*xrz|m zTv4Ma1-uj4CFt^$GJa-!^3h}sRQfEOeaan1)Ok?0~tpvwZj z6<3tEqGo$o*K{+z&^awzB`6H?R_yo;W8_7eMXhX^@%cJ{&@~ya65|YFr_XKhGPWo2Sg8`y8~Jl|L_bUAA72&d?CzyPdU z@njMxKrEVB&-J`F+%!v#P)BMT?KfyxO zr@e&DQ*v9=y;I8Pp#5o;U1u523~1RKt!f((q&t!Qc8;|UwES3gH<1qqywmhdzzn>+ z1wsbz?wD zqy)5hRq)Bt=*u3=)vBs3-FQW9i`69`??kPBgcgU1XXgDLeNOTzr^Q(KoaCL>AUsn{ zITf|?+|%cN(y%_0^^MCKI-4Y^Py&O-!70Pw6xRz-cm4JpkYV*Fjc*O^5NGR#mg)3DK%~Pni7R%?o zi<8{KZo|WpN6nvFG0vJTlJY+fmRx%6{LR|@x&^@+mW$KvE_L7`aFia}_ z86??At-`k_IX71;72nS-(YW;7ai7;Q*z6i(%^yvDB%F;fqS?l!xVpR9k;|)Av}&k? zHluMNd8gh~3^2HtkhPj*h4OmB(r1s=eeN6TBll))@x9}#<@Wq+Xs3U z)~Q_2C(!r@``Th(<|E4wB(O{*r`fiI&POnl>R;{*xL#LGZisGL3jSTtZ+%_#chiES z5&hISEz>rKAn(eLW%6-_nO2B7s035pE0Eo2d2YZ$7vAIn7p-n;KrccX?AI>jJkHFj zBfyl$1;KD^T?c=y#Z6bRGQIv@0&f>rl+HH=&-`@@9l1~~oFdEMEy`>0^4RhJ3~x%} zIJLgkj9V5D?6g!Sslo-RLzgU!Gbqq^KL!J&r#dz{$_tmXld5u z@J~Dea_mW>s>2fZCN!>DNFr#-TO>jsuMo3Lbn%3~q2^h}yz6_A7f&Z#kJ_1bqS-;I z=R%T>Rj1CX$gnAxdKRo2IMr&o^{Vm&xhsX;gMvbF7PH26)L$aB1vPAPsm13J#6=dm z8p$ zy24t#{I{U)69G?E5Iyp{!{;|$z8ikNtc0851SVepun8HUP?SYn-}zSunjwN%2BGGG zV!g@77~D<$Q$c;gmKeWl8&VZnkUy7|qO6EKY3k%EoGb>roE5NDEy6~3nx`Gc>YH%<3nUjSeVPUO-N;|Rh zct%UXzU$c}m0~)9{y{P3((Y847VV%$0mOtu!zN%u-uCY7lP<>H%u7o{FDEN%pCjY8 z8LG_!bT86g4~&Zj3r@m9Mo{-ALlK5pW}~XaZzMxu_dOiOkq|x`4Tovv*34qv3`J5n zL=QlAYFr?VqzHbJNjke}n2TIVff66x@4!?nHYP#3XT_FGGyt(^uEIb7#E;MI;kWqU# z*4!a_M#yQ=@h=VOClr!UC76x4UG zYo62Yk~=$sNT{7rv`&$)espirc%sdOTb(2?w7T{NRe4ifGtItw=s9# zm945=p_f`zlX;eLVZAWw2#xX0H`i@&=1vi!p4YC~x0`QWgbn@Vv|W)de~xzvF9S(% z>7Q=+1#Hl;+n0C=yJP5DtZHma5?gw{PI$qqKr@@Yx5=V35>lEed*LlHNN9x!;~BL< zJw;d`H6gMLt3J1dyS}+#$8godeV9;Xn>Uxp^d>%m?X!H%V*>@Yl4%={+N0{Nv3$&Z zF|W-pVQWn$wxUNsPN?l&u8r#JLY-U!+h?ZByMNy%-i7^ExEGg0SUi}=w|Idcdv3sG z+lI{wN0L;I`8$DgdX~u1V7lpR@C*j&GJSwuaBv~J^Sm^{4dI7vrC=qcEq4Mi^Tg|t z=VHs9GDh@zMrO3#PU(m15?5;b+#QEZ6aLlN(~8(Mo@;qxF)#EzJ%TjE&4dGLzY&35 zvY6A#I-cXOPLpGDr04s_9RC#8_Bzi^Yjn~_!Fk0YCaIg>SRI)0;!D$;yuAzK&XhJ* zK}PE{VjE)k2~i~B3J)GW!WvfjyZ!gkIxcH&=(?eH=_)s4)i9&igYRmlZKv$effVZ^ z^$H(c^+LN1PmRQ$_t3}SXUOk}?PxW2c3~f4eIXwo$c!o*B0cPI7tI`WK~ylF$UgV{ zd!uMsdZq`u>2@KD?Zcf3S6%TkW4h?5XTbVdjZ7D&T?E-P6( zBk9dtJsEpyP7uDX3%h+Q2lCZ%?-DjpO^_C32|uBT=s5}AsNl{881fB?s&QdR8s}tBWwOCSlKhS_ND|0`4-A|9p6(uJ5(OGzg@-NDF?rMi`># zA2B46UvDp-oE8+H#G2F8(%sHeLPNTCP$n+0e#?(`P&})0z~6X1WpYSmnu_E3%shz zzyL{#*!|9&)+HHPb=1sOI8VTb5PwtVRT_vNSsNA_$WVLQ^zd z7!^ePoN5O;k5*aOWr4F~*2<_3s%gYdeVXsyF2)7JV98XNC8mWZa>t9w`cn}Gy9mo~ ze886K-p){gF1oRaD>wAS7f|s8@3Y=A{3tAKsdDU@7ASChd2zK;_A2HOL({nl?X~w- zaYV_b84e#t*o+MSXGYjQc>^J_nCHf*pn7y}do-{44n zc%P&9;BpL8g_6qSkLS+vCo>Z8N6&A0B;NgB1F$j7)sYXUweuBG(SEwp6c9Pg&WI(_ z$oF0&`_SLHz$dBpm}GG;!bsQ>aj11hzVJ)PN4r^KjA1$LPqYa4kTZxb?>U`w+@klH z`}9VGHlUm3b6L-NS7?1UCdpKp23ugh?gUPqq}#s+h+5$qHOF68X}TcvAEXf4fQ!Xhp*C0 zZ%tCFV|CM=Fx1NcOe&3_Bc_@b$jp~IO}UACEGaEAkR+r*>Xp|YQatEc2aoP;2i$R$ z4)eDz^sfVzsArkI?+RJ>bR}c;cbM=nTpy9qDE=O&PG!Pf;~LO0IGOfmtKoEd)uDNIfmiFm*}z1GsCLSt zF}u-&kBcYNFCI>aW5*xFKTPBOBD`LsMi&sM<>8scCukV&^WQ7&3SUcwTvcfgl3uNK zFIY143zoDDV-2}tQWPlM1F zhqI@6k2eLm-F*1uXE9hjOt4!P8`E*jj0F!Z zYdSoGDMb|j0Ra)2sKHW9(Ju<8Je}hiQIU4TeO*MEAQBD<;)YQlRjf74^eDNXxyXiJ zoNvt<#xI^|!1Ihj9CU#|c!;IJG#$}}Pl>errMt!*NusA8Nj;2_UyIDM80b>#XIxp} z1KTQ2?OqpQ+~M$~;G2|eiJjk;~G6qUD4LZcgV z`>v@Ye&`>bw8q-oPtY&>;vTn3M<~vn5RkP*P=bkaPdAo6=uOA*#Zg1RF)_4wT(*6RdGJ;% ze!?h&qq864elOC#9h@AvjV!#LW!RnN{x`aiU42OPL-tfMs=cNP2pj7sk)??ST4gOe z^y1Tn^pWHKwv1-AMOw&Npq~P^kt9wcU4(4F2vcWF8#XJUOBT(F-!WnA=pxZ#X|yFB+Rh@K|Uv{Am}k-q~zUiyOEL)=^{5J8yzpow;D(+ zj=^wG^WaXVL?p@5EA-mNxe_aHZgdNqIN5fbw%1f=bPhYC7y7(LYrwdkm*MFKcih~W zU4)Qvc;lIpvgLlm`Z81K;u7}@Q+uZw&9QP*q3abP$|@?&4e@)=0&1PY+UUx|?ovi@ z0{bn&YQ<|ByYh&KYm#(!Hbux?QQrG}>apPKRlqlQx9UQhBc3&xwd#i}*QiIt_>(eB zyFp9X{=WCWO|omE^1AxOzEc5-XK#!>Cq^dt@cpU=mDis=Mp`J~{#MQHvwwf;=l1WU zjVb(R#DE22+xA>Lm02i2a5{V(*pi$T@Mvc(o6^o8#fUTf}*JkIqPFn(vz6 zH?zEu7lDZwm0m(3?^ruoq30K=jjJ*poL*<6DDv#&wq4%Vw!jwUNAiKX6ZDYcZ`58O z=C>2cDR|B$3D}!_r9)!XI|+95V?){78;E1>n7isB$
`|B#?v?|b1OlNVydp1~QOO_@!qs2#ydR!YQ`wb9`h+NaK`rOFUgL>wy8 z*YR1?0W<1#k}kxRdB;Bv-+?ul)l2kFN$GkUq!^zCFDLl=5aDeau&jh_#3IM~vNvi; zEkb7SaZtIYa$7IlHNQ4nE;A!DqumBU>!( zr`Y{lY(>i}pw)>8+>|5CaY~2}Pc*ouK!l?YMt#3lyP*6x!MT9z?|}-(yvRCV)M*rc z&<|c5r#}>BUv$wZx8k^kk@;4`i)IWAwXV?p(J)YdCs1Rf`uU@=e01rcBljHCuCd~a z^E>9CEl4D4>rLxgdGZd9P5->ZPhFAxjH>}B&b_<(u!bq#E>!4-QMbh2TOC@_(PIyd zzF-!>-{uN|0`;9zk-6AXj2nLuSdKDCWm$?dGQz@@GqA|Hqv-`_Vl(s&4zV(>al!Jh z+r`35iRBMhn327~13gx?+Xpbr#AkjA?WSfN4vd3~B@rZ!I9S~{D<2#8aX5?g>Vgt> zbdc_jT$2o&mNoRVUUOhmv-Z|i$m*A<%@gUbO{52OP=UIgngUXtUbdRG@_`RO=pb_< zvCc!TZw$K=kzO~`#FL%~H{3wIB7F8*a9iMW_sUS_>xTT`E=!Y- z0DO#u_3DFsO&h0w6wXu*ks1+5r5qngr-CP15S_t9rxZj2Zu-Wa^qeMW`MXNsP4|Jm zSboo3b-VrS*;`4<=)m6dahJ1gyqgLeOTVT@hS76kCVaScVR`bAk3lTB8>)Tyr8x9I z0cR0fk6};Ni(3b^l7gw$Rh6Nm${&P44o0GC|Jt^)*!jSHK``rzds_yiwVJjotX0oh6+G-;Q&eiE)%6E&5d6EB<9GBYAqZfpLJ^1A_u-RczW`!?VoT$-m$J5fcumCFAnK`O5Kd zV=!N=(3lRo%9bq<2*JvpERV=4)bQ^{hap;px_O1Z^yM&CpC^!AXdu5jy) z>EPq`+YD%Wr(*T6?jcb3zvBi8;NckU#Hvb$Gb)ms!qiHp7A#9d!L}c?Ug0|~n);Px zEjaDjEwwa%YjoC>R!;RWcmxT!9tWF0FWHcTiUee=+x=tN;G&v?x+Cd69^9<2u_?SB z+G!}hNJUm(s&*`O#c-MnmBdM|%TBXQtU%bf*RD$$(wBUYt*rY76>WF8 zXTMm~c7;)Z?ukJ~{SHF*Y(C}&MP&^)YY_eTdDzSssGNEjnHuvvWw66$6uS|9cYP&^ zJTmg#{dUaS21lHIOYKb)FpcPce4{eJAM`e#?4B~vWs7`Hs%1|sq2Y)r$WM_>mq<0} z6q5{=W==tV2Zp@8)B8eA)1xDV)fLjKaXPUTPWYv)WY7F7*LsrNpKbF*p77j%U)*^_ zebvLAM~MN<^MD?AOcY!=CmBh}B;xKo`6u+Wzr)oX!!hJ^pN0cZ(qX>NW5^hkvl-d3 z8=7X}ON$jvKWLZ8ZIk+1Q&Tf}*E|fZ!r!oXR$9@<*pO)C@r*g{yyJ`4B1~x*di?`U z3SBN0ps{9N;G<%IO8O5^2@C6(O8Xjsm9gM^hF%%zf|1-jkxHJYAC+KlCu~gQ^#>P!4UBFS#`wkSqZJW-7BX;uL^Z231 z;r2q`d+C>goZI%w?S@NhnwQj(*hA;HzJY-_p!@vx@j5t0B1iEfq)59~bKhsH>>n4l zfDV@!b{AB;7!QN}6ygWi67PQjY_|QyYNe^78I6a=ybQOm$-LI@Di_m@AfzuI(>YE2 zI=j32flTskQj+H87U5XmM;R}k+;%LWNp_$>vWRXhQs;uompWo3IKqc1rvZVgP> ze2l-|VWVJw#<306!NP)Irrs!Of5GF=-R;>a;KfQoxYoVv@uo~B7!?x0zO}KDIL^$%!okd1_Vo~GoI31J z_ciuLl5zd?MAQBJ`RCo$TE9@Fo2)LCo$rLL@*_6raH+Kx-Bsqg97xRFuF)ftcSQB# z0arr_I92u_qoCt-pl<#j=5znI6GX#_OwOms+lYz5{m$G(*3(l2Xv)^i0XgYUg|8y; z>8bd7J%vqKu^Jd z=F`)4%3U7n%2S&E5D!*hM|b@CHK*xh7gMuP6RemfNDG{$7)mU-RuVp{TDQe09R?P6 z{$xx?57Rhhx*THU(<<{Rt4Pw-1uQ*Kn~o%Cx&?Qnrp`-K$EvEn13dt=Dss#nHk)Ti zU;LOenPjOu8At=jY=Qvhz3T5DeqIPEQJB4cjT;%fgud6jA` zYP80ULoHhBbLH(OU?~U1W1UFfo)kn#`uzEG>bn$keLZ)cTj%w%Z>HT*nTf%|f$cInQb$lJ5~a(hPApnhv} zv(Mwm`;D}>&}V`P=bc#Q$x}k@Z+Ci*|!n2|%Bn zF^%4eYtuyn@ID$*;GhBw(4**!gE{G%&~YZOV3qVS6j31|DPF5-!;@=;bYVTJU#bj> zm29AgYc{??{& z5rw9DD7WI7w3lY4O_T8*5qRDQU|!KS;I`q>A`dhkd73#;MrPQR))ONk5x94pyPWTK zk%7A5$nzW&(Z!!$5F{|;qiVpybz9ee@MHmTvSgL&S)?=<|%y&VISO@MjiXV+N6h}ivKuT$D!H*F#rx*pvE zr=>qS;ZOW=W3N%KI~6i67wc2HK{Nl_hUhmm`mNulN*0Vu?#mW0r>upB1}0bs&9(@V zWxN0?lSM-XDw%LyE4OWo#U_G=H1(gS#e9}y)N=v;i8)36igNwR{|`0lLs6}matu=# z91~9avjD-oS6{D|$(nhN#cR6XwRL_P0eq_rS^ z9`jhk+4IJw;g*4eQF*WAsDkQyApV_dLv>Lg^%q-9yK*bZP1mQ15vBJ4TY8hdk@>j{ zf}rz0H9*BLXhOeTr|QJBSZ&GMXIVP(b;rVvYozrULMh~4aW~%J z6;#7%ze;+#tnuP7wB7$^AXOkE0j<*emo_s3z`b;~cY66MfxV-mT8FInyCI82Wd?@I z^-K!ez&{QnnI?k-`m62QM+k{zy1mKrI3;4_B#E^3i_r_Xp=AHNA~Umj{!cH;HCSde zjPUYub19gK$zXq7)IqNR(E?q5b&E#891~DK=ch)O#?^6(IIb>g<{06cKx$kJeT zj}wl$0J4%mKA#8KdUkDMZU`Cd0-(8t;}8(jzXN-+3gLn2q5^OzOHwOtz{xkPzfG=h zDA>p|c)X982JK4EzEV|eeCavz(i|*nTiN~Y(euSuTxs06wya1gP1p!qqS5{Gko9tR z0Kta1FLkCB8n?)fArUmI~Wmh^vD4aTB=KzDp1 zrcT1YLMIk;FvA{ z;<08Fs0!DHa~QoQBSUHKkB86nI(bm)~H(T zX%}>Ae?JH-+_#raw>yphvffPp`Sa(uG1eZ9vtG4GnU9UFi)rj@mMEvsrsYmU7+f-4lcBI1TCz zc~ED+qX}w+0%*}Pt2*+mpmOn@o8#6}xg*XcFL)o7%N*5ru&=R$SMj>oJsv_l8CNhU>#gEHlB&OdU|?Z z7huZ$0qQo^(Z5o`#qkNOXk3!=tEIn zpmze~gUZm3a&leJ z3*r!BW$4TpQu&8o>nGv!!oo2r$&y9;`h#`J-Uuf?b#s^`sCii>@d*eNS_VRY0JW{L zP~aO95+ZfTvyp#g&3A%)3Qc&9r^KRM9{oFrfXMx?Unu=9?nlD^)eZU~E^k#uM^7)% zA_>&!3|G-@KmI-2FGd^)qaou(XNs~w&2`rg^d#0oF&IULjex~2h!=-|3#ESQGd^ra z6K~GzR43SuX_ZW=bce+tpz$+&x7xRFNF83nAA@;vNvMP7hfgo{+$f)LiV0NTY4`Fm zX?61}Z6L`k)o-Qw6rfYOZ);8vBtz-T})!tV?mx&r^q#^PEg$J3aXLKiHr-$&a+AzyZoqdW< zz2~I;rGbomN=@;hpe^7z09^6f_0_b`hDslX?b#%tUt;5oj~1W1q+wW+Bc>I#mXhcz4QDjw|II$lQAkn4e@VcyHJlD# z+DbmfWh(m=2F5S#Au>l!2qR&Y8P1rSEzzYAaNJDAb4RaSV_ij~Q>Fz@lU~_ll>VbU zvFG13ObStDt%6`y-3r-@1Cck)?k#NIq!ANhQn_mu=*1*rt1 zP-Duf_E48j^2tox_yDXN!Q&$v%$I z4b&Y+M7#-<9P=?UCXWviv2kg%xL_nbL9g8+^Oel@`v_@m3KPi%A^94sMVc4MrR<`j zdMvk`man``D4%ezQ?5o*ptM~lTl*x_#sMsR1}wZ|xn&z(nz%oP#ywE1q6xZK@BhwD zJKmowcBIisxA;5Gbp6)@rb%ZoO@+k$lAUdv(n5(Bg#sPmfUn8TUUA4@nSjA6(3fKP z!oElr>3~EEK<9<3m;%UNTWR*DL&(fw$T(!wb2W$WE(LJZ!mfK`)(AI~eOjgw@$+$k zcObDUZ4s4lwpwE0v&r!gMi*Uu_WZVAsB%;A5WzOirwn?Jx2Z8yHkWOxzV=1({UW=@ zdD$;>4xvN*bU=Izz(D)C6b;`F^5s_C-4voV^80kld9Qj`)*^)nVe`3iJ&g&a?O48% zf2E)+{o8%QG{@p|moU1=i{`ug+Xz$5C1JY*!OriMNC;vQ)WD&v6 zwWV){^R*@&$pXVSSP;)|+2|o5T9G9H)w1hT*TW)n6z$X5B&Sg>tS~k;HkLii$S$8m zwbuLbg{D^2cue z9@uE<%mP#cdgQTQ8nmEsd}3I5isVCMcsOR?K(Qx-MINpj5SkFsrqQUs+5QaN`-EEo zcyB!L-likZN3fzAFKvaYG50Z`Iro*t6UX0xAfrX98PqizOrupg#r3ARXfq;XV4x2b zM2y9b$v)fa113zjEQ=s?Q?`rf7hc^jT|*fRh+QaA`HTFY=3?Ooz|#!*r^){Y1^_Db zj(?x~{qL#J{~K!YKQ6R8M~Mvj4;SG7MMD3C0alE(+{|Le9hU*n2OvN;zOB)9Snb?7 zN%y)7*@*=-mrE=z-xE{ zWYYY}+2#kUu8_<~x~@q(3C7S7P(o9u2|7i)pYNLcP0K&wS(GB~Fv__K6UU^7KVRbx z(XCs&4+5Vc#IbSP-#epl)r)Xt`2^BV?Y58pqBkq zi|%k#&C|`_Cx1FF2evZ2Xn{j5GyW^Wr2hvRJ_QMLhWAOXF&Law@{$V-=^Ls3*2hG< z8$r(VV-G$q{NM>lcgUVC{Q4Q?@c5j7UQA3sflb@!LBwHQdFWPE3P38~WJ}>BPE0UV z81FFk4fe+JT5I(K+_a6LqeKc{>$#eEzE|Yyq8%^ao9*DB+v$l!D*B z0s-lbnA?tK(rJ5MY;ICR@mQV`&dz9Mis#)ZiAyk>cNF&)z?5YK6v_fOuVvnnSntih z5@{g+o6dJxsU;xpHvS~F2Nba+L_`#O-*)c_Odj&|WfT=7L)RUdVl$*W0??|uJj*IYM&~bg`YZ}D;L{yrHN;UUbS6TX&KOIalN~~$_@P& z)%MXR=`xu$PuT77zyP1<98kO&2i-UVMH6iqHz1+=JpaT$ll*a@2Qd04l023ifaj z$udM+;_w`K!@ zO@0@#R?nT#wvl-`UF@xIhya{5xv3FsAuAheHC@(qRi(mS9xNjT?`x&<(Eve~M6ZL^ zP;d^}tes+U2of%qK1oW--d|*HmNm=U z?=L~e?$FRsoQTK8K;(gkF(75P@re`!Kv*@5YqV>5ufD{u`6^{}*v!0(Nh0uIVf4H1 z=My4+H+#RS$Oo2dtY&EPl+t)wU5LPxk1&i~@JyYm%|e59!Wiho=)2tU_}AL!I(zOb zB7|-(fCnJpKowQ41(ibu_z&bQo^|Bf{FOwqzV=l9CpRA9m_`I zNfO@VU!#x?`KN!}jo+(q+8h2}B@zvzj7BcU$4C9}bnkM=$NXY$U4qz@*K;Tz9ADS` zAtJAH9ofMvPmunwQjpIw9y@xakY9WLD)jW+=)=e$=(Vkg7V$8RUkk#|w| zXv%S6R>xz#U(!~AsUL1zayhI}?Hn9nz-j<}m+ zujYH3V=->b+v@b=MMb=0!wUZ7=@OQ{FDIrbiZmo*vR^C(9due%TB~i zg@irP5vy2n8-+?r1infv5N&ZJ-+V}KAaw|)ZF};Vru;ttR7Q|5Xb*H|d? zp%zx9?Axt-JigQ$T6Dr$$yU5YOH3v{Qv*YSG52GER|}AufmP5#tMm5CnsIZXz5h3$ z1@%E!`38MMP|jbingbH-Da$~R$fN1%*UCkd5I+RrUfiGd4nEZ#MTer{&%z>hVFKLf z#fx^+WZtS~AP}rW4tjeddD!S{tKVR71Ed|>(O4^NnjZkdl;yB9F`oa zFCQEnIF_5Y_tuaZDEjT!%1%&8SdLj)5MBHJZcr{ARcHKjtzX$+cx#{!BWz>2VD*{2 z3pDL*cbJe`KW(r{CTE%L+Y;?mAVIg}B>h@9%3J;T3?4Zf)^{}dR~Ovs*tGFgiTH`? zqYVuuE(PtUMIxVX?IIfZ32_aL<291B=%AYxx!u4PfBK+CsY9MYm~coANFC;@{mOiN zzuOaD;-3&EurU?j@XUgw?{&Xin&Mtk!)kM}xGn z%z>aQF?%&I-{mUz78x4k8dCLg)=Izb)L?TVk}3pL)2LXv_qpq^%d@@(RjaGMRX=DC zL}=Q^$KUtZy>RQ0j{QE(n?i%+3|3QAj_L)>`t_4mYtUR}I_TyP1c66ts;U}KhFEt*T@GL`%bHkeVd3-=v&g^>@!)+yaAbMwQ`JGEe=t(+;qpED@Kb&-OEmt_^ z1WxmH*Ng1OMCsJf+O$*M;}uUK0bYrur%M3`E!j#wBfsMWf%}J+d)dRoV|*f!U2l6} zt;I)4g4WC0`VBQ`BoD9beRYnrjwpt5#W|Gwd$YbC%Bs&2Sa8A`oXb@yj{QVSxmYmx z5K6rS9pGhsHz0J+VfkJ73}^f4kcG;OHiJE?FoGYLxEbJwjVTpI>=Y_~1qE9=v3Wyw z^P$1@!-dYf@!lWl;`_{gXDFPc0}msKxSCKhad@4`9Z2}aqnV_W2u-v zVF}G_liqdo*MEYX8feO{OAmb_F~m^mW1=;GS~Uec%?EU(!=2)j-BusCKH>ESDuABx$L%) zbTO5RjB=0j+%KVze7(ItAofQhZPJx~1g_2Ml6dkCP|e}^W{%Z2t$-4=;7Wkts_o-CeCBnIx~VW_fd4kYOdyJnK* z_!z1mgfaZ%tUgWbSwWcnxvyWeIts@=JK~j#lNrn?|0tcY1kc7Cil4gE%G2Ue~4ELV(VZqc{1tH_E$8Q$jjC!JUT2Us>D zh*sx!IpaC-aG@d?g4Rn-D&4yyl5TERgDINOguc~fxxH`yUzn(}BxR9i)1O!=00Y4?kPb zt#sPzzIP6~&7|9_O6;BcDs`}4!vB?+LRj!7>_x*qEog1x>Ga7sK4q~6@0cJH9mEk6 z4GyV7cUo2s_=Z}k500-S?oq5XH@dC!Oel-25dap;we%-R%uP2irI zl*rgO!9TTALR%_8QCL`&_oY(HF#WuPbF^8lME>~f#y*Jk=hC$fQM*?Dx+sqpsx7wY^_dJgnY7QuA;(vM}(Hgs=7I^WR^=g7k;MX zlZUNOE$SZT6LxtykD{tYLsJE<1WkUOkgA5LpRE;at~Es{^#cUiU;2HaFj8K|r3M%3 zRsZ(K&MY-j$$#yFXh;0X%pq1v3sB#uO8z%yfMsqT_N)OV^@uO`^X2U4%nJ|ta9OK6 zudQW*tIr}i?vkYh`d?=p5SQhG1G@p2=GBL*OB9L_siP6;DYLm3WK8L=`00eLrSRgZ zSXnEzTrx@6?>lbE(j788=(PXb9JUhq1Z{>UUTtRy8wJGTp0s93D}Ca4GzebFh56s! zKR6iDx_Xts#cA$+3XW@J$KSSY3kr>P$24+B%>1NSCZ15vv$=K_vemRuLv7@KwXJ{x^7WKuYw;FqlNNJ^M5sf|8;id zjW?A|<(q7|Kx3+}Sa_lCac^ol45b>+Bo*+QSrHYcM^G2oB;{dYAI_}gJv!dxh1I>) zD@hQ{iA*XePRL=a zc{dLW@UZW^vQj+&|1}?syZet`ktUw6@y%d6%wQJGM#!q!F1$f+$(pb0)Zws%tf%)G zqUWC2@R@tHgF__X5t&mEBt#1$bf=~bE|`MpGhSb9GQf^F5Oc)M`6em8HK%b;j(AimgX zl^!A|F#QbkDF~!`)wp1V8i6H@(un$ZB?w*P%rKkTK)bZJxAOHS)VOyV+rwAQtGstx zeA3Itgz+qI5ailQR}?ZViMC$*;5vgSdmIJW@*Rhv%-Hv?$!vFs`d_XV^8V+EE1Qo( z8Pcj!SFT>nUG7#o0IL-)8D-t(;zXKTyA#4P;QJogrodyXnIEZaF zSd*ZyJB)~qhy|UsJgoLkt`EA5^E>VM7`(Mi$skjdD_~t~bQv@*>YIH9(Nj^7#dug@ zL_od+d9;7cZm!OPXEpP={^b3H2>RVg>A+B3TU%&%PfsTCH3-j{BX4^6qx=eDZ7~O= zV=;}JE;wX!-HJ_$h1kdh_i0;B-qT{DRhjcHUmx!iSMNf=D=q4a&#d+7tVyc!BID@= z9vMFoX$vDQus9Z~F$-KV&W~?Yx$~UozG#T|kGWn@VU;BP%FS%de~=q&Ia~jPpGWUa zs-B{`?M57OFu+{#d`(OC-KsoA1nt3oXOL%EZ|dVH6V^J$6+)S3YYnO;1rVFxBbRmC58X%SBB@GVq>XW#G*R- zOTx3WMhn-lQ%|HiNP&##qpS zx|#mZ_9k?@PV@4gKwL~yZTk7m1o43&;hzN)IfenvP6QpK=G%3kH zk`3a}q5Sxh2vLvX=!g^1y0{gs7t6MZrG7EUjiIdajJm4^AcTNhprR;B5<&=FZO@6p*$^lsnB4z(dBq{dG_;v-QQu@~6g z<=OUdNWVTy5l>vM@k%RVoOMW*=mv2#L$GPLa1bH&6ul#7VIO?9>gMuHxHdipYs zW&A%!SjQeWK@+LuoFU-z{FSXxAY^;o%`r7T1zBGWe4SR6#$9$76H8}C zOYa{Il@J8%+Yfm_rxZamv}uRJFPAqtNgN{&i|t3rf(n1kdBX#9(ywx7TezQIU32xvz!;rMwfPajv*DD1DG;2QMr};5foJ;ZnmzxWO)tC?fp@W%pUNoy zn1pqoE!V=4gmf3Y+J6Wz9On#fZYJ%YzPnn9mzg)f%7|r36{94B9_V~M@nks_ZQu@{ zH2LTSoxNbjmI~q8^p=J3WllbgfS2t5B|g?oJ@1)VdUAKg$Nr)cfyovS41gSND`D0J zX4Hpq%3cuhoeE4v*g|`h+3FMGZ{vnhy!S1QzVEi|;}lm4Hhq@RK7pAaa>Bxa^(spC zWABRGx&sk#NuQ0vwZl^HYBGW~tc?pLh*Y&`%J3dr@?Uqy)ugI}L^jO)`t`K$^FhnPG%@{69L{6LFX>#e zL`py6&c9+YEXp`X$QF^43WV>j6lH5UpuWtW17-W+jgS&_^e)QOn?==MwF}1I7;$41 zxL!A03fV-&#l$3zOO6eUBd8%z%XJBsl z;XLuLl8&baWSQ5p1fk4@C$jbu&8|?*X%bK9auxYsk(wA73^MbEAN@@=qywpj%avTh%RIt{wlQ>d03#^qQO&0a9+(-AA{O5j7xSf7V2h+klkv^B;yPbVb5bw zdOItXjES}D*m}Ryn({Tv&(K#&3)Ntkkp$F41$kdjP6~N^_Hns5*Cl;+yN&_PBh?1Z zN(~Y{q-OEOw_5%59I92EcY}tV!b|V%xC{MaY7Kw-*K2jz_p@_oNznJ~aDIn&(GX0Z z`*w%Z^6zFhnfyKNRO-TYISdU6n!{2){om`9RAUNe>~FW_6eXE;c?AU$&cdXbPqJ+9@kkXKD>WAzPOH9b&;ws=;kK~lp zNS>Ih@9iVqWVWgKq>zKs+pO6Cc}&WZi~SZJ-tcU+E|6#@$SpWxTR>1C^(=7v!4VpC z=i_&Gg8H6M9r_{oUObPt>zpp8)C6`J!iHy3DI(@*=*kHR$$reJ<-hUw%EDK-9Kj& zU^gosIEW9|)lQz?qHoMe*w-lakw;Si8Ny7iIMzkAiJ{T2M~LHnsixj zs^fRms8k$nvZphvI=c%u87Xu6$vJpvXTRQf%9@xHN#0wHE-VNfm=vq^VLfpgsZUJu zw=gf1N-BQW)7xL3wVp`g5ougr@FdMu?6|3Nmuf@$W^fPWXrh*B^n;ofgMw|9tkC9> zVEoW~5tG`xemB8>*G>##5B%d<5`v$trg^OWf^#HRtnbHS)vL~L0jWRef$7#knt)K{ zMm2HL`mb)%n$<5s8De&|^P`U{7aE7oS_5N@#Y!%f<2%j{`wKkOA{ZPuYVSIn@344$ zoi`&vE9G?AgK2u0`dq2wT8y7lWhC-evGVLoa-K1#ipZ>pwX; z+3s}VjMU9>o4@&)))NG9SF{8m(dn!#O7LMzjFZ3y(Jl**Gl(o)ePb0Daq{xzz4g3k zxriBepP%^PQ;-Q=c4=fbcChUrqeZv;8iluS$eq+XjLCh{c_DI)9kp71SfyE<9I+H0 z?>86H;&C?5@Xa=0Fwo0oUuBhPXY%4E!$^JGSstwz1$Oj zPz1O?*vI{y5;lr*cd_j*%=N<=sN(H6lU{>Uqq~-?b0Ybz=G8Ry;lATo9NW5GXExZI+K$sZ&mzh$3kb>x5f<}7K>`{NZ0}F-wJ19kgU5=*;dmjl%zwt5d-Z`J zk`~@8FRxwd{XR&bMty^o4CP?lzIT;g7HnLFUA{O2 zT{m%&%-uR?sF!3ZTqf;n*27!5BfhLO6pk3N4nK#zMGa^a@%YH&nS`Mm63>Ht%|3J0 zlN5kmzM`GCh&s@GFs0*D5^j6Alc%eaJPwaek^5;tMQLTi&W<&Dk9nw6Ut6TANg7?S zW}HA>xCwXGUB{onfCfwID_8I~ao-UDNLHN>m+)U($0FcevMS&spaJcL;HQWjKl2Em zpAOK}B)v>La{+r0JUw{v`aE<;i-Zi`E*pyaXRV%oAD|gp=&BFWZiP?8d3Pe6# zmdB*H%JKuF7zplXr!Z4er;?LS=v;ECd|HafKIo$UG@-Wx(inJwEMV&T8?g?hChn@& zO$?Rm_Heyt)_&2S{2b!hnR;uqMh^yG@@f@xS!o3CAWn)J{6wPKR8N?m#-!RpwqYL? z1wwti?M?i(l)=EXt>Gev$UV>@81jXKVnRfB+sB!YsBMPobq|qxdflzQW0dBBtIJvs z`DZxU)loZRm4AyssG}RKvEdYj%KfP{_p;ssk}k5!&a#UYq$DUv3=|NFB^5jR_p1x$ z)u7dPJ#Pu{CEh4KB6y{%9MS0d6!p~4Hjn!K!dn@lvKUiJFs)ToPSfQX<2q5PoiRQd za0B=DOa^^~dMR|+?LQu{h3}##GmC%^7R%YoVa$AE=QVn(o&5$<%~9<%aMN@;QGkJM8**$%ZkR z=~8^6x^_u7P)2m}mioCKP~dENq?`hrE!E*0v77~gC0*Z!RJ*%1jI@(&puQA11cy%= z(s71&aG2|?iL;)Ukg5Jy>Qc zI7FK4AMb*5jB0_Jtm?b*A~hJqi$kOyyVXCyj3aP#Hg%yt3+EVh1cUT<6h44wh6>;i zZjFWCJuoO=8w~1i`SbyYaJj(!nR@d-i3Wp`iO(+I&XRe@-n`cVz8&KVTuoQCLd7=p Fe*hykV+jBN literal 0 HcmV?d00001 diff --git a/__snapshots__/form--login-webkit.png b/__snapshots__/form--login-webkit.png new file mode 100644 index 0000000000000000000000000000000000000000..df4cb3a0644cc62ba56fcde4dc91bc6d9686bdb5 GIT binary patch literal 16879 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 znk25�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 literal 0 HcmV?d00001 diff --git a/__snapshots__/form--number-webkit.png b/__snapshots__/form--number-webkit.png new file mode 100644 index 0000000000000000000000000000000000000000..37b99078f3b90f40e84ad116377c198b48060559 GIT binary patch literal 5651 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 E0b{7$3jhEB literal 0 HcmV?d00001 diff --git a/__snapshots__/form--radio-card-chromium.png b/__snapshots__/form--radio-card-chromium.png new file mode 100644 index 0000000000000000000000000000000000000000..f3973d070416f2388fa4f77d2211816177c2dc01 GIT binary patch literal 10208 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 Y(;Ez8iXH%99R$*RqW8G!;q$2f0R|Vz82|tP literal 0 HcmV?d00001 diff --git a/__snapshots__/form--radio-card-firefox.png b/__snapshots__/form--radio-card-firefox.png new file mode 100644 index 0000000000000000000000000000000000000000..5cf11cc22aa5e75c79170bce52894a7103636c4f GIT binary patch literal 18817 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 literal 0 HcmV?d00001 diff --git a/__snapshots__/form--radio-card-webkit.png b/__snapshots__/form--radio-card-webkit.png new file mode 100644 index 0000000000000000000000000000000000000000..ee9b82ef6f863fa3e8ac04966c907e052fa43212 GIT binary patch literal 10704 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�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 DO^Su) literal 0 HcmV?d00001 diff --git a/__snapshots__/form--radio-example-firefox.png b/__snapshots__/form--radio-example-firefox.png new file mode 100644 index 0000000000000000000000000000000000000000..e6aa51e5a6c6a773c40d798bacb41dc6ce447793 GIT binary patch literal 11346 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 literal 0 HcmV?d00001 diff --git a/__snapshots__/form--radio-without-input-chromium.png b/__snapshots__/form--radio-without-input-chromium.png new file mode 100644 index 0000000000000000000000000000000000000000..0195184ba4a2166771e4c8b0178bdca7d56a23d5 GIT binary patch literal 6588 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 Lp+=S3v+(}`T1F-5 literal 0 HcmV?d00001 diff --git a/__snapshots__/form--radio-without-input-firefox.png b/__snapshots__/form--radio-without-input-firefox.png new file mode 100644 index 0000000000000000000000000000000000000000..d3c17869bee102ba78e62af479ed74f88f4adbef GIT binary patch literal 14643 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 Vs>cA-Eoi7ekb(xVR?g!6{|6%Wj&J|~ literal 0 HcmV?d00001 diff --git a/__snapshots__/form--radio-without-input-webkit.png b/__snapshots__/form--radio-without-input-webkit.png new file mode 100644 index 0000000000000000000000000000000000000000..c2fefde8b1377283268d25338848ea4a317457d5 GIT binary patch literal 6800 zcmcI}XESq004keOHUO-s4@<|SzB%jUhwz`j- zx$}v~($SJevTbXApd024=auAP6VVB8b$1ESX~Xw4EAES~GHNe<)?$dC zkgu@l&9M!;_*q81dlV%)PD2Iim6}HT7G$tY` zNJZIPlWdEbO-VGam^txXZSdQ)7rn`Q6`~(ky5ccUh3%Uxn4?7Sq(o$N_j)lnQt@}; z%NEXf>qb;!M`kcGM&&S?NrwI(BXP&6pB`ruLBP-#>Zw{Nq0b_YX`_`Z-vDuB_dfhx z58|{kH^5sjL8uw@&WG8`B5m0IX)NJC(GE#1R!^eTd{YYRh0dYqAJhLspQ1S+h0W}i zt>q*Ra`Sh$?sa{1Td9JB5sf{O<@ml7pSQZ%V{s+jYuB(#83-bFz0?1cUQLb5FsORG z>qONC)GE1jWxu;>KzCK@)0!FFJ!u>$9_0|vo3kSX(0-Z|Pa$-|NSlKRxmcKo&AfQ? zEZj1M8}V?s(IbG-dd#u9dcqS>*0fY}Y??j?^W#k%Nc{jQK658ZPx(dtx}j`pAXY?a zPO?88qi^w#_q#`#(5;nb!3waI9OhxP%}^X5E>0%UEqd4Lh>h>(6494W8=GBOqJ)0S zy%OscUQ#K(ZOWWwce`moTyC0O0Dun1Bm zmt)brQ5U2oR~9|(pH5?=7$#D8+xKs+?^ObV!YN~F?))Jd_SpWBWxd$3Xij&PVfA3S zc_nA1)x1R{#;STAb~>#HbaSg(0O0nQf{@@ddh6}>or1;%i?PPeiH&(@NtT4hdYAkD zULne>nGQ{Mj1H@Uf%1xwi;pJNX8dhn@doq#s|!wSU!$!tH@J(U|7x$^y3u@M3{!ol zvr-oB;ZOu*0zQN>73%Wd;w~2F+10knlCm5u%IT^F;*|MYl?~d)ENc9$P&f|><~Hn) zpG)oBk0|mLZ_i8k&c?9|-UE4=FXR_Ulw| z>bdcEcFv|zHZ;cKq7S;7a-pc186l3aL-Fy(p5U!=WY1;P@CHxh)qeSoeu4ZmSqV{a zl4-TWVjZT|LnN%H5bBaO{`x%7VL}VtyV6^cL_qLRIqZ1O=>cbd*6?gKjk5p#kKmop zz_=1#J`lUYu@*mlrbJbH2~Ghvj6J!%NVsiTstI9V zWu}N4Qm>~`&J?o=-W(a0<^{P*vJi$HfCn(Rt0U^$CU=YB(j?5~bv1+#L>@Yp)IAVi zM@QfW^tV;(DO)i9@T#l2!l{4i2C--(mmQF#liB?E#qrVUVfk)N#uy+>zSlDXrb7TN|Gp9r&>&zrZ-QKR#e88Zsa`~t6jN3&5E^6BmufdV; z*{NVw_lDyf*Qan+qo=rca(Oqr2ste+xgagQtax$WjGQi1gv9P#;1XNm65&e8J9l@c zs0`?(q<0Q4uI}Dt!r+KMGb+#&E@DqEqNAcnNW>66*te0%&XUmiM&2}mM--Dxy}0fg--7wNd@Ww% zDAW=5^u2HWvFrb0ZvuTMA+$ZK2}Y zuH?eww8~FXNI6xj=b<!#2rTd^>L?~ekn0(!tEG{+F8H`|4Zv$yn(=ECwEn%ALWp1bQG z$M+U$S35yxkegw*VgqxUb>avF1~>Afba7`#Ccn3cnph<#N#})itWTc86VIB!Kl9n=le%UulcZ`OIy(N(XEUhy!5ksAZhjDA+R>D_^SUU{SL+SkL4 zHT`ROxjy?V7oKnP{VtBn&sIA9Jw5pYYL_gc$G1?(`Q`7n&vNu?YbVK>Rm>J8s^=Ts zEp|FW7O38`@kVA(Kre$?_2#Ie)1WS&p=qO=lT|26R&0x<2ya>g9Iuj}c!5GKt%h8( zuITQd`-{er9bOUQWz%4{^~sR=HP(Av1t@>n)FM7Qq7RQe8$$g8O^Zf^LGX#SuN1lq-|a403=@`TlwD!3_0sZAVf$C zLh~G!Y@Y@mt#83M?1u4!Ogroc;KQFS4+^L?bJCi-B3{YejG{1dt-v3F*p})=WC&Ih z-8(aLlsJWR3j1nPJ+J;`CS^@LmL%iMWMpM?2b0We?}&sm<*mNAmy%S z9C*}U`=jI+0$2Bh{OVFK6LHM#Vq|lL$W@(j3@} z*J!~{nAc?nTH&^b=X`|=a4bN{@Dmisbg?A80%RN}oTEH(Z|Tao+f2+%yf<7SmO!7D z+dIX;rb-xC=K*cC=MQt)_F7?PZ|!?Ck*9-j9z;oAA8d4|5BNO?t|b>i1~YvSQ$P%h7Tdkii|PUixl0 zv35LDjN#te+*~0+L9~QRgc&%8ygF>3o-S3`P*76tO!B4Ca+~_*lxigHP`aeCr)5gt z*As59g;TV5on#_34^$s2QxJm*6mS^Nf*xEcgk7C(4j5mW(BvjdHo)7u=!|SFj}J86 zEnS(>nMFVoqc*ZuEI0}K;NAyF*oIiFsu4}(orey8WSHZ|+0n7C+6`5w(fUeXe+ffr zaq-^h!$6sE>CEOWq~$cbd4*oGVY5|t_St6Rwulc`JKfgVNyr%{QS}Mv3MEE}XOdT; z({?w*9I1B9fp%gRj@(v=2M=>IyX43|_Ni5r6Bh%Y6$9Pcff*e*50I<7i;HaVX4*wi z+cM?|f6@2Qf#~mV_>11~PegzJ__>gp`-+!G(>?s1J+1w$_v`NismtDNHj*l$0f@%u zsZxdnfo^ThEY(Qtd;_dsI*5$X(?LAe%FF!xp<}WW4EOLbLhs87 zB@3TDY=~(z;2-enNLg#B36&6dX*b(HL>AfXFqWV-p8J6}bA=bG6!qqyD^^P{ecp~L zn#&?Z#f7ZAev3*Do4BsrRpwH4zjFDGL0gM@6>jq6W#Sylx5GG@D}~K4lN$-97ZfVg z)lSY%cewYGpKUgi$L$g3vCjXXAD|ye9?zE+uZkt8A6tdJ#dF3_TcWQe?~3UO|JI97 zHycL4&1ak8ciXwKzT6 z`$zr*ovEh%2Q)*0Q*=M-_oe@-hg42HL9vKSIZrGaD7t)sZ-TWN;L^&PK>6GOGmZ6T zI6d4$6z;KRU-hJX3O3hn^GdO)5Q=KDq0W18QhplK*mdzf{jUcD2s01qT&LP zeKz;DVvJ?>Za*=#E!a33=){KoSZu=#7Rv9PT)0@$jh>gj5(bMrlNRmvL=a|+F|D4A zb4oi$YyOWbR$0)kj(dzbd<-RTqVgt9nPOFGV^w{8=IoJskn5HIi zW93!T`1lDrKZrXCDd#eK*uUM~CZ)xzqGvN)!{c~4B}PMeR)Q6nzO{W;Mut3ag!Vje z-BzT+zlw#|)G*unqpjU|i87|M>z$)u$?4H{f=acg(dv_^4ijg5<#J=?>3f0CDy9*F zkgm2M;#@*Lr>(L&W`JrFWtilwewm?&5agW~v8%KyF9tdo{0nBHd^XM+o=L_>aQOd| zv5j|x2!P^qPCaEZ9ZuB0GO&L;PyolOuJ5L7L?#nh%15<-y$Z6?ix%0`6Vu@UnKD|= za52a+3V1oAC|c7hrZ%ancI!^ICm0?Xg=b68zg%5VUX3e%TH^amU>;T;nX{!{lwvHi zgx7F#+~YYUE^ecqp6(0|e!jnt1ru_foa&vS?4wYnV3|Dgzg5XMRFpu! zN~;EX^>iR(xwF?wZli!S?zfh*y_Ih zBB%Iu`CBW~!3c!%^>4Q6mQAtN(blyjSR4L0_VK3ynPy{RtNdDhcTF|E7t&63ho^Ca zT~*}hRz`HICmENvv|d#cw&a~-5Z8B!@+k@POrFRxZ_j2+4>a}so2o}mseNlkicB${ zbgbV-Mlz(_%;fUxcrdjbVBaU*UHjS1U2?Q?nW;wWaa3Ak+!a3C-1_xj2!c}#ERQEE z*GYFns`XEp*6fcZD2=CIcvY2fO9 z>568B*x9*`FW|+jziyRQ*onJrDP)$=<>vHeYH~YJ3lI!1LzxJ`Jw)KO=47R+ZLd&* z*)rxbEkdAsKl=g%71$DKo+$K*jQ{#JSgy0I0bKoRu4@^Tq^8Yg=}4Tr&$+cdks;gd z8re~s(!rqfE`1#*@b-N{denxmq}~}8?Kd$A!7VY(vnLv*kLSE*k$837p@+__Z1+u( zsr*_|fB-dQi`uYUU!Bx{QD6jA8MJ+(or1kH>|K(sG{*2!jYYkeFyMlV82@90>4XnR zG;E#lrZJcp`7(P?5w-uoJZ+H+9@OqjvrWL&pPu~to)e0f z=C_SoI`#23T#-NA{lsq9KZb{s_grNaLNnVeMesNbVhP#lh!JcW-1nUzY*7uucu-H! z#cX*Bd!hc(9>gO?dC>f zy7_FMXRgw!azgcYD-Me)m&H2$M+rkiL&3_LW{Uw8&je`GM#b-D4-eHn zqPQesU-4bLDxVl0OdTyFsdZ4xD(9H)yx;JV=+ApGm6mwM$n%fnS>~C{?Cg`F@)^2} z4>YLdFU~)S-Hcc|d9|-pRS*)sQLhdT#oGyTv74uCiS(qFe-b!Cq;(&zCmmpyk}m=g zA~7Nq$>e_IEq8PH{;mA$^WIt^jLXJRK~;s!SF?lIH5^sT+dT#$$d(Nm%V*Ca)$UwNCH`Z#g!GHi95wtzAn9z?pfK0fhq zjax_DF*Ju1PBSzy$V^KabHg&Q;S~faxx=qb6B*cLvFPgLFTW zxt27Qk6GTG-5JbO|M&v4G!StT%K;;kA&zghGxUy4N%+N1v^(+Jp+C4T!-wcOc@Nh) zg6~zz7wkA7>3D8$daCM&(kL7bfKNu0BLqwMeF9#8(9#EspoGY;{)TWr*^%W^TKd@k zu%~_#T{#8B!0iRE|^Or-$;F%)4f= zK2kE2pAJzVzsxj#k;7*plk2tAD%GsiM+KRnqwQ0smHzR;jz7v#CaQMMM-Tcn>W!RV z)vi=p*Q2P0`9*PE9+)TDUuiUSE5PYKMGey^Tz-iZ8ZC?2ex3`PDw0~O^EA+oq>fVH zyiFf}h7$HHj8&D?^U2e%o)f2tICnQl{A=L;%NX@1Yo4kIFmL+H+bJNevj( z%>V$#hU3?7p}0%eBxS)VM?y_5T%c`VqzHWXo1Fn&Oszt+)WubEJsqe^IR-5dB zJP}}i&hq!d)|W0S_wIgCyoAC}X+UMcHEhb2`XvlXDM6A%SR3>Zi+OEqHI9FC?(+-v z`izDr2ZZve-?L`(!GcDMn%V^agze4~<0NE&y+71wLomE}5Z#I9_Y>*zdjLS2F0M|n z__Zf33oldzD2$u9qZYFiW5NuCzk=!5t?g zpa^K`b0fqzNtrOGKP<BBkkuAe^B%KuVt5LrgFbltnaoj&pN{g_PjJJuHGDde>_eeLCfSw@s%(v+5Q?W zm5a4JJBUrn2cE^xjk@?nCY!&B8Qv%dj#WyZ0#{ZLE3{qz7DMEcN(18|-+I5HoM?l~TDD2Q$E4PFn9kLvJ9saGCE82r`ypE*x9@pB@=mX^ud#hls zhTU9_8>tjcdBn2Qa~2SDL^o5ca&!`9~yo$rU9Db#3zrXnrD+Jrq3m z(=R%a!w27m8n*W;hU-Z!EPY0^B46Bi$*>%qgLgEdvDOW)q2478Qwy%3%lbAX*~fl@ z)v&ZnCH?`Dh@D~e=XKqkNHGx1H@v2_J=@+5!wZuJ8t-E8j75rFR^Nn(fnex0?W za|w6A4iz906sihe<>S%IYdR1G@YNb+Zeh@7g8}z(TQ6vcx1LUUJ$7JijxSgmC*Kp$ zBlgWr^0RYIa}z3AWfrq$ap*@77GS*fa>L0KIkOZ z&EXe9m_w`R`j25}v;hTxf6#-W@34WRvEY_(&z|$)~|QE?L)iMn&QzCP~*Rhi5U#TmevinlH26b+o8P{g*2Hyg<7Kj{afkF=Ob*Q e{|lmeOHEUR0I{BLY!S2+prxj-TBmIL;r{@Rl$2Ni literal 0 HcmV?d00001 diff --git a/__snapshots__/form--switch-chromium.png b/__snapshots__/form--switch-chromium.png new file mode 100644 index 0000000000000000000000000000000000000000..58096cb8e5aa42729c0c4c7b844c4cdf8136274c GIT binary patch literal 5738 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 WrN7*9`B!sgfYE((y?Py&xc>sD&13uk literal 0 HcmV?d00001 diff --git a/__snapshots__/form--website-chromium.png b/__snapshots__/form--website-chromium.png new file mode 100644 index 0000000000000000000000000000000000000000..8eee1dfec21ef81258cced596bb5840bf1fc4b77 GIT binary patch literal 6556 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 literal 0 HcmV?d00001 diff --git a/__snapshots__/form--website-firefox.png b/__snapshots__/form--website-firefox.png new file mode 100644 index 0000000000000000000000000000000000000000..266cb5070251ee488ec9f811e7f6df3c38fb8214 GIT binary patch literal 8423 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 CCvXn{ literal 0 HcmV?d00001