Releases: edmundhung/conform
v1.1.3
What's Changed
- Narrow the
type
prop returned from thegetInputProps
helper by @AMEH64 in #579 - Remove usage of
instanceof
for Zod schemas by @colinhacks in #601 - fix: getButtonProps types by @lifeiscontent in #597
- fix: subfield errors should be consider validated based on its parent by @edmundhung in #607
- fix: setValue should work with null by @edmundhung in #608
- fix: root key should be updated after form update by @edmundhung in #609
- chore(playground): ensure css is built before remix build by @edmundhung in #614
New Contributors
- @colinhacks made their first contribution in #601
Full Changelog: v1.1.2...v1.1.3
v1.1.2
What's Changed
- Swapped out the usage of Object.hasOwn as introduced in v1.1.1 with Object.prototype.hasOwnProperty for better browser support
Full Changelog: v1.1.1...v1.1.2
v1.1.1
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
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
andreset
intents now accept an optional index similar to theinsert
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 noformId
(#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 thegetCollectionProps
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)
- Added a language switcher by @coji (#544)
- Fixed wrong import example by @hpiaia (#574)
- Added one-time-code input to shadcn-ui examples by @lewisblackburn (#530)
New Contributors
- @lewisblackburn made their first contribution in #530
- @hpiaia made their first contribution in #574
- @gglee89 made their first contribution in #465
- @AMEH64 made their first contribution in #562
Full Changelog: v1.0.6...v1.1.0
v1.1.0-pre.0
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
andreset
intents now accept an optional index similar to theinsert
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 noformId
(#560)
Full Changelog: v1.0.6...v1.1.0-pre.0
v1.0.6
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
What's Changed
- docs: Fix missing map index in intent-button.md by @hawkcookie in #517
- docs: using a variable-width font for docs by @aust1nz in #500
- fix: conform should derive keys of nested list properly by @edmundhung in #528
- fix: update form value at the form level by @edmundhung in #521
Full Changelog: v1.0.4...v1.0.5
v1.0.4
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
Improvements
- GET form will no longer include the internal state in the URLSearchParams (#501)
- Resolved an issue with form value out of sync if multiple intents are dispatched in a single callback (#496)
- Fixed a regression introduced in v1.0.2 in which Nextjs complains about returning file to the client (#490)
- Refined type inference with interface and nullable schemas by @aaronadamsCA (#508)
- New Shadcn UI example by @marilari88 (#489)
- Fixed several typos on the docs. Thanks to @Forus-Spec (#471), @nphmuller (#477), @ozanbulut (#483), @notomo (#492), @hawkcookie (#498, #502)
New Contributors
- @nphmuller made their first contribution in #477
- @ozanbulut made their first contribution in #483
- @notomo made their first contribution in #492
- @hawkcookie made their first contribution in #498
Full Changelog: v1.0.2...v1.0.3
v1.0.2
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
- @ngbrown made their first contribution in #449
- @Kota-Yamaguchi made their first contribution in #463
Full Changelog: v1.0.1...v1.0.2