/* eslint-disable react/display-name */ import React, { forwardRef, useMemo, useState } from 'react'; import { hasValidator } from '@/utils'; import { fileToBase64 } from '@/views/mint/nfa-step/form-step/form.utils'; import { ColorPicker, Combobox, ComboboxItem } from '../core'; import { Input, LogoFileInput, Textarea } from '../core/input'; import { FormProvider, useFormContext, useFormFieldValidatorValue, } from './form.context'; import { FormStyles } from './form.styles'; import { FormFieldContext, FormFieldProvider, useFormFieldContext, } from './form-field.context'; export abstract class Form { static readonly Root = FormProvider; static readonly Field = forwardRef( ({ children, context, ...props }, ref) => { const { value: [value], } = context; const validationEnabled = useState(Boolean(value)); return ( {children} ); } ); static readonly Label = forwardRef( ({ children, ...props }, ref) => { const { validators } = useFormFieldContext(); const isRequired = useMemo( () => hasValidator(validators, 'required'), [validators] ); return ( {children} {isRequired && *} ); } ); static readonly Overline = forwardRef((props, ref) => { const { validations: [validations], } = useFormContext(); const { id, value: [value], validationEnabled: [validationEnabled], validators, } = useFormFieldContext(); const errors = useMemo(() => { if (!validationEnabled) return []; if (!validations[id]) return []; return validations[id].map((validator) => validator.message); }, [validations, id, validationEnabled]); const counter = useMemo( () => hasValidator(validators, 'maxLength')?.args || 0, [validators] ); return ( {errors.map((error) => ( {error} ))} {Boolean(counter) && ( {`${value.length}/${counter}`} )} ); }); static readonly Input = forwardRef( (props, ref) => { const { id, validators, value: [value, setValue], validationEnabled: [validationEnabled, setValidationEnabled], } = useFormFieldContext(); const isValid = useFormFieldValidatorValue(id, validators, value); const handleInputChange = ( e: React.ChangeEvent ): void => { if (props.onChange) props.onChange(e); setValue(e.target.value); }; const handleInputBlur = ( e: React.FocusEvent ): void => { if (props.onBlur) props.onBlur(e); setValidationEnabled(true); }; return ( ); } ); static readonly Combobox = forwardRef( (props, ref) => { const { id, validators, value: [value, setValue], validationEnabled: [validationEnabled, setValidationEnabled], } = useFormFieldContext(); const comboboxValue = useMemo(() => { // if it's with autocomplete maybe won't be on the items list const item = props.items.find((item) => item.label === value); if (props.withAutocomplete && !item && value !== '') { //return the selected value if the item doesn't exist return { label: value, value: value }; } return item; }, [props.items, props.withAutocomplete, value]); const isValid = useFormFieldValidatorValue(id, validators, value); const handleComboboxChange = (option: ComboboxItem): void => { if (props.onChange) props.onChange(option); setValue(option.label); }; const handleComboboxBlur = (): void => { setValidationEnabled(true); }; return ( ); } ); static readonly ColorPicker: React.FC = ({ logo, setLogoColor, }: Form.ColorPickerProps) => { const { value: [value, setValue], validationEnabled: [, setValidationEnabled], } = useFormFieldContext(); const handleColorChange = (color: string): void => { if (setLogoColor) setLogoColor(color); setValue(color); }; const handleInputBlur = (): void => { setValidationEnabled(true); }; return ( ); }; static readonly Textarea = forwardRef< HTMLTextAreaElement, Form.TextareaProps >((props, ref) => { const { id, validators, value: [value, setValue], validationEnabled: [validationEnabled, setValidationEnabled], } = useFormFieldContext(); const isValid = useFormFieldValidatorValue(id, validators, value); const handleTextareaChange = ( e: React.ChangeEvent ): void => { if (props.onChange) props.onChange(e); setValue(e.target.value); }; const handleTextareaBlur = ( e: React.FocusEvent ): void => { if (props.onBlur) props.onBlur(e); setValidationEnabled(true); }; return (