Skip to content

Releases: edmundhung/conform

v1.1.3

28 Apr 21:08
Compare
Choose a tag to compare

What's Changed

New Contributors

Full Changelog: v1.1.2...v1.1.3

v1.1.2

23 Apr 20:37
Compare
Choose a tag to compare

What's Changed

Full Changelog: v1.1.1...v1.1.2

v1.1.1

23 Apr 20:35
Compare
Choose a tag to compare

What's Changed

  • Fixed a vulnerability with Prototype Pollution. You can find the details here.
  • Fixed broken link to intent button page on docs by @marilari88 in #581

Full Changelog: v1.1.0...v1.1.1

v1.1.0

09 Apr 20:09
Compare
Choose a tag to compare

Improvements

  • The form value should now keep in synced on DOM updates (e.g. when you render an addition input) (#491)
  • You can now access the latest form or field metadata in the callback without the need to subscribe it during render (#467)
  • Form errors will be cleared immediately on form submit now instead of waiting until the server result is back (#553)
  • Both the update and reset intents now accept an optional index similar to the insert intent (#555)
  • Conform will revalidate on blur only if there was any changes made before (i.e. an input event was triggered) to minimize the chance server error get cleared simply because of moving focus out of the inputs. (#559)
  • The useFormMetadata hook now accept no formId (#560)
  • Fixed an issue with form reset failed if the form element is unmounted and form id getting out of sync (#571)
  • The type prop returned from the getCollectionProps helper is narrowed down to the specific type by @AMEH64 (#562)
  • Added object and array support to getYupConstraint by @gglee89 (#465)

Docs

New japanese docs are now available on ja.conform.guide! Huge thanks to @coji for the translations. (#558)

New Contributors

Full Changelog: v1.0.6...v1.1.0

v1.1.0-pre.0

01 Apr 16:32
Compare
Choose a tag to compare
v1.1.0-pre.0 Pre-release
Pre-release

Improvements

  • The form value should now keep in synced on DOM updates (e.g. when you render an addition input) (#491)
  • You can now access the latest form or field metadata in the callback without the need to subscribe it during render (#467)
  • Form errors will be cleared immediately on form submit now instead of waiting until the server result is back (#553)
  • Both the update and reset intents now accept an optional index similar to the insert intent (#555)
  • Conform will revalidate on blur only if there was any changes made before (i.e. an input event was triggered) to minimize the chance server error get cleared simply because of moving focus out of the inputs. (#559)
  • The useFormMetadata hook now accept no formId (#560)

Full Changelog: v1.0.6...v1.1.0-pre.0

v1.0.6

24 Mar 20:02
Compare
Choose a tag to compare

What's Changed

  • docs(tutorial.md): Fix some typos & grammar by @machour in #535
  • fix: ensure nested list keys to be generated properly by @edmundhung in #537
  • fix: validate only if the form element is mounted by @edmundhung in #538

New Contributors

Full Changelog: v1.0.5...v1.0.6

v1.0.5

21 Mar 22:08
Compare
Choose a tag to compare

What's Changed

Full Changelog: v1.0.4...v1.0.5

v1.0.4

11 Mar 20:38
Compare
Choose a tag to compare

What's Changed

  • Reverted the changes made in v1.0.3 to resolve an issue with form value out of sync if multiple intents are dispatched in a single callback (#513) which caused another issue when used in lifecycle method (#512)

Full Changelog: v1.0.3...v1.0.4

v1.0.3

07 Mar 21:25
Compare
Choose a tag to compare

Improvements

New Contributors

Full Changelog: v1.0.2...v1.0.3

v1.0.2

19 Feb 22:45
Compare
Choose a tag to compare

New APIs: unstable_useControl and <unstable_Control />

In v1, the useInputControl hook is introduced with ability to insert an hidden input for you. Unfortunately, this is found to be problematic in situations where you need to dynamically render the input. After some discussions, we believe it would be better stop supporting this and have developers deciding how they wanna render the hidden input instead. To avoid breaking changes on the useInputControl hook, a new useControl hook is introduced which works similar to useInputControl() except you are required to register the input element yourself:

Here is an example with Headless UI Listbox

function Select({
    name,
    options,
    placeholder,
}: {
    name: FieldName<string>;
    placeholder: string;
    options: string[];
}) {
    const [field] = useField(name);
    const control = useControl(field);

    return (
        <Listbox
            value={control.value ?? ''}
            onChange={value => control.change(value)}
        >
            {/* Render a select element manually and register with a callback ref */}
            <select
                className="sr-only"
                aria-hidden
                tabIndex={-1}
                ref={control.register}
                name={field.name}
                defaultValue={field.initialValue}
            >
                <option value="" />
                {options.map((option) => (
                    <option key={option} value={option} />
                ))}
            </select>
            <div className="relative mt-1">
                <Listbox.Button className="...">
                    <span className="block truncate">
                        {control.value ?? placeholder}
                    </span>
                    <span className="...">
                        <ChevronUpDownIcon
                            className="h-5 w-5 text-gray-400"
                            aria-hidden="true"
                        />
                    </span>
                </Listbox.Button>
                <Listbox.Options className="...">
                    {options.map((option) => (
                        <Listbox.Option
                            key={option}
                            className="..."
                            value={option}
                        >
                            {({ selected, active }) => (
                                <>
                                    <span className="...">
                                        {option}
                                    </span>

                                    {option !== '' && selected ? (
                                        <span className="...">
                                            <CheckIcon className="h-5 w-5" aria-hidden="true" />
                                        </span>
                                    ) : null}
                                </>
                            )}
                        </Listbox.Option>
                    ))}
                </Listbox.Options>
            </div>
        </Listbox>
    );
}

You might also find the <Control /> component in the render-props style useful when working with checkbox group in which we can use it to register each individual checkbox element without creating an additional component. Here is an example based on Radix Checkbox:

function CheckboxGroup({
    name,
    options,
}: {
    name: FieldName<string[]>;
    options: string[];
}) {
    const [field] = useField(name);
    // The initialValue can be a string or string array depending on how it was submitted before. 
    // To make it easy working with the initial value, we make sure it is always an array
    const initialValue =
        typeof field.initialValue === 'string'
            ? [field.initialValue]
            : field.initialValue ?? [];

    return (
        <div className="py-2 space-y-4">
            {options.map((option) => (
                <Control
                    key={option}
                    meta={{
                        key: field.key,
                        initialValue: initialValue.includes(option) ? option : '',
                    }}
                    render={(control) => (
                        <div
                            className="flex items-center"
                            ref={(element) => {
                                // Radix does not expose the inner input ref. That's why we query it from the container element
                                control.register(element?.querySelector('input'))
                            }}
                        >
                            <RadixCheckbox.Root
                                type="button"
                                className="flex h-[25px] w-[25px] appearance-none items-center justify-center rounded-[4px] bg-white outline-none shadow-[0_0_0_2px_black]"
                                id={`${field.id}-${option}`}
                                name={field.name}
                                value={option}
                                checked={control.value === option}
                                onCheckedChange={(state) =>
                                    control.change(state.valueOf() ? option : '')
                                }
                                onBlur={control.blur}
                            >
                                <RadixCheckbox.Indicator>
                                    <CheckIcon className="w-4 h-4" />
                                </RadixCheckbox.Indicator>
                            </RadixCheckbox.Root>
                            <label
                                htmlFor={`${field.id}-${option}`}
                                className="pl-[15px] text-[15px] leading-none"
                            >
                                {option}
                            </label>
                        </div>
                    )}
                />
            ))}
        </div>
    );
}

Feel free to open a discussion if you have any issue using the new APIs. We will deprecate useInputControl and remove the unstable prefix once we are confident with the new APIs.

Improvements

  • Improved type inference with nested discriminated union (#459)
  • Fixed an issue with zod not coercing the value of a multi select correctly (#447)
  • Fixed an issue with react devtool inspecting the state of the useForm hook.
  • Fixed an issue with file input never marked as dirty (#457)
  • Fixed several typos on the docs. Thanks to @ngbrown (#449) and @Kota-Yamaguchi (#463)

New Contributors

Full Changelog: v1.0.1...v1.0.2