Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(conform-react): useInputEvent API #90

Merged
merged 10 commits into from
Jan 25, 2023
Merged

feat(conform-react): useInputEvent API #90

merged 10 commits into from
Jan 25, 2023

Conversation

edmundhung
Copy link
Owner

@edmundhung edmundhung commented Jan 22, 2023

Introducing the useInputEvent() hook

This APIs has several improvements over useControlledInput():

  • It no longer enforces creating a shadow input element
  • Use your own value instead of built-in value state
  • Explicit focus forwarding for flexiblity
  • Wider event type support, e.g. focus-in / focus / focus-out / change (react-only)
// Before
function ExampleAutocomplete({ label, error, ...config }: FieldProps<string>) {
    const [shadowInput, control] = useControlledInput(config);

    return (
        <>
            <input {...shadowInput} />
            <Autocomplete
                disablePortal
                options={['The Godfather', 'Pulp Fiction']}
                value={control.value}
                onChange={(_, option) => control.change(`${option ?? ''}`)}
                renderInput={(params) => (
                    <TextField
                        {...params}
                        label={label}
                        inputRef={control.ref}
                        onBlur={control.blur}
                        error={Boolean(error)}
                        helperText={error}
                        required={config.required}
                        inputProps={{
                            ...params.inputProps,
                            // To disable error bubble caused by the constraint
                            // attribute set by mui input, e.g. `required`
                            required: false,
                        }}
                    />
                )}
            />
        </>
    );
}

// After - To achieve exactly the same features as before
function ExampleAutocomplete({ label, error, ...config }: FieldProps<string>) {
    const [value, setValue] = useState(config.defaultValue ?? '');
    const [ref, control] = useInputEvent({
        onReset: () => setValue(config.defaultValue ?? ''),
    });
    const inputRef = useRef<HTMLInputElement>();

    return (
        <>
            <input
                ref={ref}
                {...conform.input(config, { hidden: true })}
                onFoucs={() => inputRef.current?.focus()}
            />
            <Autocomplete
                disablePortal
                options={['The Godfather', 'Pulp Fiction']}
                value={value}
                onChange={(_, option) => {
                    control.change(`${option ?? ''}`);
                    setValue(option);
                }}
                onFocus={control.focus}
                onBlur={control.blur}
                renderInput={(params) => (
                    <TextField
                        {...params}
                        inputRef={inputRef}
                        label={label}
                        error={Boolean(error)}
                        helperText={error}
                        required={config.required}
                        inputProps={{
                            ...params.inputProps,
                            required: false,
                        }}
                    />
                )}
            />
        </>
    );
}

// After - To reuse existing input element if possible
function ExampleAutocomplete({ label, error, ...config }: FieldProps<string>) {
    const [value, setValue] = useState(config.defaultValue ?? '');
    const [inputRef, control] = useInputEvent({
        onReset: () => setValue(config.defaultValue ?? ''),
    });

    return (
        <Autocomplete
            disablePortal
            options={['The Godfather', 'Pulp Fiction']}
            value={value}
            onChange={(_, option) => {
                control.change(`${option ?? ''}`);
                setValue(option);
            }}
            onFocus={control.focus}
            onBlur={control.blur}
            renderInput={(params) => (
                <TextField
                    {...params}
                    inputRef={inputRef}
                    label={label}
                    error={Boolean(error)}
                    helperText={error}
                    required={config.required}
                    inputProps={{
                        ...params.inputProps,
                        required: false,
                    }}
                />
            )}
        />
    );
}

// After - If there is no need to support form reset event, you can also use the defaultValue
function ExampleAutocomplete({ label, error, ...config }: FieldProps<string>) {
    const [inputRef, control] = useInputEvent();

    return (
        <Autocomplete
            disablePortal
            options={['The Godfather', 'Pulp Fiction']}
            defaultValue={config.defaultValue ?? ''}
            onChange={(_, option) => control.change(`${option ?? ''}`)}
            onFocus={control.focus}
            onBlur={control.blur}
            renderInput={(params) => (
                <TextField
                    {...params}
                    inputRef={inputRef}
                    label={label}
                    error={Boolean(error)}
                    helperText={error}
                    required={config.required}
                    inputProps={{
                        ...params.inputProps,
                        required: false,
                    }}
                />
            )}
        />
    );
}

@codesandbox
Copy link

codesandbox bot commented Jan 22, 2023

CodeSandbox logoCodeSandbox logo  Open in CodeSandbox Web Editor | VS Code | VS Code Insiders

@cloudflare-pages
Copy link

cloudflare-pages bot commented Jan 23, 2023

Deploying with  Cloudflare Pages  Cloudflare Pages

Latest commit: a4a3993
Status: ✅  Deploy successful!
Preview URL: https://dfa4a45f.conform.pages.dev
Branch Preview URL: https://better-integration.conform.pages.dev

View logs

@edmundhung edmundhung changed the title feat(conform-react): useInputControl API feat(conform-react): useInputEvent API Jan 23, 2023
@edmundhung
Copy link
Owner Author

This API will probably be released on 0.5.1, while the useControlledInput API will be deprecated and removed on 0.6.

@edmundhung edmundhung merged commit 63ae80c into main Jan 25, 2023
@edmundhung edmundhung deleted the better-integration branch January 25, 2023 23:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

1 participant