Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
8e4776f
fix(onboarding): submit computed money forced values in the right unit
cammellos Sep 29, 2026
ccf0275
refactor(forms): default transformMoneyFields per key
gabrielseco Sep 29, 2026
77136fc
refactor(invoice-schedules): drop redundant money flag
gabrielseco Sep 29, 2026
c28068d
test(onboarding): cover money forced values on the legacy contract de…
gabrielseco Sep 29, 2026
6896273
refactor(form): drop getForcedValue
gabrielseco Sep 29, 2026
2d2809d
test(form): pin that forced values are submitted as their const
gabrielseco Sep 29, 2026
a5b4d35
Merge PR #1426 (refactor/create-headless-form-money-default)
gabrielseco Sep 29, 2026
8ac5bcb
refactor(onboarding): drop explicit transformMoneyFields
gabrielseco Sep 29, 2026
39b2adc
test(form): drop parseSubmitValues forced value test
gabrielseco Sep 29, 2026
8e1421d
refactor(form): add useHeadlessForm with rebuild and buildOnce strate…
gabrielseco Sep 30, 2026
c3cc3b1
refactor(onboarding): build legacy contract details through useHeadle…
gabrielseco Sep 30, 2026
fbdf5a6
fix(form): stop buildOnce from rebuilding on every render with inline…
gabrielseco Sep 30, 2026
f1e9034
refactor(onboarding): build jsf v1 contract details through useHeadle…
gabrielseco Sep 30, 2026
60b4ecb
fix(onboarding): refetch the contract details schema per employment
gabrielseco Sep 30, 2026
e5fc865
test(form): cover options shapes in the jsf engine contract
gabrielseco Sep 30, 2026
5575dbc
docs(form): add useHeadlessForm rollout plan
gabrielseco Sep 30, 2026
956e0f2
Merge branch 'main' into refactor/use-headless-form
gabrielseco Oct 5, 2026
1b51631
chore(lint): enforce useHeadlessForm over direct createHeadlessForm i…
gabrielseco Oct 5, 2026
0a89632
chore(lint): mark legacy createHeadlessForm imports inline instead of…
gabrielseco Oct 5, 2026
d7a65d3
docs(bugbot): drop unclear useHeadlessForm flag line
gabrielseco Oct 5, 2026
7af4ea8
remove no effect
gabrielseco Oct 5, 2026
120c985
chore(lint): fail example lint on unused disable directives
gabrielseco Oct 5, 2026
ede6120
fix(lint): catch relative createHeadlessForm imports
gabrielseco Oct 5, 2026
b718cf6
refactor(form): seed buildOnce forms from initialValues and move basi…
gabrielseco Oct 5, 2026
11dc6f5
test(form): fold useHeadlessForm lifecycle cases into the jsf engine …
gabrielseco Oct 5, 2026
d3e0a35
docs(form): mark basic information as migrated to buildOnce in the ro…
gabrielseco Oct 5, 2026
53da62f
test(onboarding): drop the contract details employment_id query key test
gabrielseco Oct 5, 2026
e3e68c0
Merge remote-tracking branch 'origin/refactor/use-headless-form' into…
gabrielseco Oct 5, 2026
1571e23
docs(form): pass saved initialValues to buildOnce in the useHeadlessF…
gabrielseco Oct 5, 2026
a4acf1a
chore(lint): exempt __tests__ and colocated test files from the creat…
gabrielseco Oct 5, 2026
759774c
refactor(onboarding): build benefits and engagement agreement details…
gabrielseco Oct 5, 2026
f27a6b0
Merge branch 'main' into chore/enforce-use-headless-form
gabrielseco Oct 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .cursor/BUGBOT.md
Original file line number Diff line number Diff line change
Expand Up @@ -230,8 +230,8 @@ Forms are central to this library - ensure consistency:
- **Yup schemas** - Validation schemas defined with Yup
- **JSON Schema Form** - Dynamic fields use `@remoteoss/json-schema-form`
- **Field mapping** - Custom field components mapped in `src/components/form/fields/fieldsMapping.tsx`
- **Validation timing** - Use `handleValidation` for combined static + dynamic validation
- **Parse before submit** - Use `parseJSFToValidate()` to transform form values
- **useHeadlessForm** - Schema-backed forms are built with `useHeadlessForm` (`src/common/useHeadlessForm.ts`): fetch the schema, then pass `schema`, saved `initialValues` (not the live form values), `options` and `strategy: 'buildOnce'`
- **Validation and parsing** - Use the hook's `handleValidation` / `parseFormValues` instead of calling `parseJSFToValidate()` by hand
- **Required vs optional** - Match field requirements to JSON schema

**Check:** Are validation errors user-friendly? Do they display with proper field labels?
Expand Down
68 changes: 35 additions & 33 deletions .cursor/rules/json-schema-form-usage.mdc
Original file line number Diff line number Diff line change
@@ -1,57 +1,59 @@
---
alwaysApply: true
description: Call createHeadlessForm once and recompute via handleValidation, not by re-calling createHeadlessForm on every value change
description: Build JSON Schema forms with useHeadlessForm, never by calling createHeadlessForm directly
glob: '{src,example/e2e}/**/*.{ts,tsx}'
---

# createHeadlessForm / handleValidation Rule
# useHeadlessForm Rule

## Philosophy: Recompute Incrementally, Don't Re-Derive From Scratch
## Philosophy: One Hook Owns the Form Engine

`createHeadlessForm` (from `@remoteoss/remote-json-schema-form-kit`, wrapping either
`@remoteoss/json-schema-form` or the deprecated v0 package) is designed to be called **once**
per schema. When values change and conditional fields (`if`/`then`, visibility, available
`options`) need to be re-evaluated, call the `handleValidation` function it returns instead of
calling `createHeadlessForm` again.
`useHeadlessForm` (`src/common/useHeadlessForm.ts`) is the only place app code builds a form from a JSON Schema. It builds the form once per schema and options, then recomputes conditionals through `handleValidation`, which mutates the same `fields` array in place. Calling `createHeadlessForm` again on every value change throws that array away and rebuilds the whole form from the raw schema.

**Both jsf versions implement `handleValidation` by mutating the same `fields` array `createHeadlessForm`
returned, in place** — it does not return a new one. Re-invoking `createHeadlessForm` from scratch every
time values change throws away that array and re-derives the entire form (types, options, conditionals)
from the raw JSON Schema for no reason.
Importing `createHeadlessForm` is an oxlint error (`no-restricted-imports` in `.oxlintrc.json`).

## Pattern to Follow

### ❌ DON'T: Re-call createHeadlessForm on every value change
### ❌ DON'T: Call createHeadlessForm yourself

```typescript
function recompute(values: Record<string, unknown>) {
// Wasteful: re-parses the schema and rebuilds every field from scratch each time.
const { fields } = createHeadlessForm(schema, { initialValues: values });
return fields;
}
const form = useMemo(
() => (schema ? createHeadlessForm(schema, fieldValues, options) : null),
[schema, fieldValues, options],
);
```

### ✅ DO: Call createHeadlessForm once, then drive updates through handleValidation
### ✅ DO: Fetch the schema, hand it to useHeadlessForm

```typescript
const { fields, handleValidation } = createHeadlessForm(schema, {
initialValues: values,
const { data: schema, isLoading } = useQuery({
queryKey: ['my-form-schema', countryCode],
queryFn: fetchMySchema,
select: ({ data }) => data?.data,
});

function recompute(values: Record<string, unknown>) {
handleValidation(values); // mutates `fields` in place — re-read it, don't re-derive it
return fields;
}
const { form, handleValidation, parseFormValues, onValuesChange } =
useHeadlessForm({
schema,
initialValues: savedValues,
options: { jsfModify: options?.jsfModify },
strategy: 'buildOnce',
});
```

**Reference:** `example/e2e/helpers/benefits.ts` (`fillOnboardingBenefitsStepDynamically`) calls
`createHeadlessForm` once and loops on `handleValidation(values)` to discover fields that only
become visible once a sibling field (e.g. a benefit's "value" after its "filter") has a value.
`initialValues` are the saved values in API units (partner initial values merged with the employment's saved step data), not the live form values. They seed the first build so conditional fields are visible before the step mounts; after that, visibility follows `handleValidation`, and a rebuild caused by a `jsfModify` change keeps the last validated values.

Expose `handleValidation` and `parseFormValues` from the hook on the flow bag rather than calling `parseJSFToValidate` by hand, and call `onValuesChange` when the form values change.

**Reference:** `useBasicInformationSchema` and `useContractDetailsSchema` in `src/flows/Onboarding/api.ts`.

## Strategies

- **`buildOnce`**: use this for all new code.
- **`rebuild`**: only for moving a legacy call site onto the hook without changing behaviour. It will be removed (see `docs/USE_HEADLESS_FORM_ROLLOUT.md`).

## Known Exception: Legacy Call Sites

Some existing code (e.g. `useBenefitOffersSchema` and similar hooks in `src/flows/*/api.ts`) calls
`createHeadlessForm` fresh inside a React Query `select` that re-runs whenever `fieldValues`
changes, instead of using `handleValidation`. This is accepted technical debt, not the pattern to
copy — new code and refactors of these call sites should move to the `handleValidation` pattern
above.
Files that still call `createHeadlessForm` directly carry a `// oxlint-disable-next-line no-restricted-imports -- TODO` comment on the import and are tracked in `docs/USE_HEADLESS_FORM_ROLLOUT.md`. That's debt, not a pattern to copy. Moving a file onto the hook removes its comment (lint fails on unused ones). New code never adds one.

Tests, `scripts/`, and `example/e2e` helpers (e.g. `fillOnboardingBenefitsStepDynamically` in `example/e2e/helpers/benefits.ts`) may still use the engine directly.
34 changes: 33 additions & 1 deletion .oxlintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,46 @@
"react-hooks/rules-of-hooks": "error",
"react-hooks/exhaustive-deps": "warn",
"typescript/no-explicit-any": "error",
"typescript/no-deprecated": "error"
"typescript/no-deprecated": "error",
"no-restricted-imports": [
"error",
{
"paths": [
{
"name": "@remoteoss/remote-json-schema-form-kit",
"importNames": ["createHeadlessForm"],
"message": "Build JSON Schema forms with useHeadlessForm from @/src/common/useHeadlessForm instead of calling createHeadlessForm directly. See docs/USE_HEADLESS_FORM_ROLLOUT.md."
}
],
"patterns": [
{
"group": ["**/createHeadlessForm"],
"importNames": ["createHeadlessForm"],
"message": "Build JSON Schema forms with useHeadlessForm from @/src/common/useHeadlessForm instead of calling createHeadlessForm directly. See docs/USE_HEADLESS_FORM_ROLLOUT.md."
}
]
}
]
},
"overrides": [
{
"files": ["src/client/**"],
"rules": {
"typescript/no-deprecated": "off"
}
},
{
"files": [
"scripts/**",
"src/common/createHeadlessForm.tsx",
"src/common/useHeadlessForm.ts",
"src/**/tests/**",
"src/**/__tests__/**",
"src/**/*.test.{ts,tsx}"
],
"rules": {
"no-restricted-imports": "off"
}
}
]
}
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ Flows are exposed two ways: the prebuilt `<FlowNameFlow render={...}>` component

Forms use **React Hook Form + Yup + `@remoteoss/remote-json-schema-form-kit`**. Field rendering is delegated to the `FormFieldsContext` component map; consumers override per-type renderers via the `<RemoteFlows components={...}>` prop, and built-ins come from [src/lazy-default-components.ts](src/lazy-default-components.ts) (lazy-loaded to keep the bundle small). The `flowBag` exposes `handleValidation` and `parseFormValues` — both are **async** (changed in v1.0.0, see [MIGRATION.md](MIGRATION.md)).

Call `createHeadlessForm` once per schema and recompute conditionals via the `handleValidation` it returns (both jsf v0 and v1 mutate the same `fields` array in place) rather than calling `createHeadlessForm` again on every value change — some existing `src/flows/*/api.ts` hooks do the latter, which is accepted technical debt, not the pattern to copy. Detailed guidance lives in [.cursor/rules/json-schema-form-usage.mdc](.cursor/rules/json-schema-form-usage.mdc).
Build every schema-backed form with `useHeadlessForm` ([src/common/useHeadlessForm.ts](src/common/useHeadlessForm.ts)), never by calling `createHeadlessForm` directly. For a new schema: fetch it with React Query (`select` the raw schema), pass `schema`, the saved `initialValues` (API units, e.g. partner initial values merged with the employment's saved step data), `options` (`{ jsfModify }`) and `strategy: 'buildOnce'` to the hook, expose its `handleValidation` / `parseFormValues` on the flow bag, and call its `onValuesChange` when the form values change. Don't pass the live form values; the hook tracks them through validation. `strategy: 'rebuild'` only exists to migrate legacy call sites and is going away. oxlint's `no-restricted-imports` fails on any new `createHeadlessForm` import. Legacy files that still import it carry a `no-restricted-imports -- TODO` disable comment. They're debt tracked in [docs/USE_HEADLESS_FORM_ROLLOUT.md](docs/USE_HEADLESS_FORM_ROLLOUT.md). Don't copy them, and never add a new disable comment for this rule. Detailed guidance lives in [.cursor/rules/json-schema-form-usage.mdc](.cursor/rules/json-schema-form-usage.mdc).

### React Query patterns

Expand Down
13 changes: 8 additions & 5 deletions docs/USE_HEADLESS_FORM_ROLLOUT.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@ Pure refactor. Each call site keeps the strategy it effectively has today, so no

Call sites that don't pass values already behave like `buildOnce`, so they go straight onto it.

A `rebuild` step can also skip this phase and go straight onto `buildOnce` when it passes the phase 2 checklist. Basic information did this in #1433.
A `rebuild` step can also skip this phase and go straight onto `buildOnce` when it passes the phase 2 checklist. Basic information did this in #1433, benefits and engagement agreement details in #1442.

Importing `createHeadlessForm` is banned by `no-restricted-imports` in `.oxlintrc.json`. Call sites that haven't moved yet carry a `// oxlint-disable-next-line no-restricted-imports -- TODO` comment on the import, so `grep -rn "no-restricted-imports -- TODO" src` lists what's left. Lint also fails on unused disable comments, so a PR that moves a file onto the hook has to delete that file's comment too.

### Phase 2: switch `rebuild` steps to `buildOnce`, one step per PR

Expand All @@ -55,7 +57,8 @@ For each step, test all of these before switching (they come from #1430):

- [ ] Remove the `rebuild` strategy from `useHeadlessForm`
- [ ] Remove `transformMoneyFields` and the pre-fill money conversion from `createHeadlessForm`
- [ ] Add an oxlint `no-restricted-imports` rule that bans importing `createHeadlessForm` in `src/flows/**`
- [x] Add an oxlint `no-restricted-imports` rule that bans importing `createHeadlessForm`
- [ ] Remove the last `no-restricted-imports -- TODO` disable comment

## Call sites

Expand All @@ -68,10 +71,10 @@ Status: `todo`, `phase 1` (on the hook, old behaviour), `done` (on the hook with
| Onboarding `useLegacyContractDetailsSchema` | phase 1 | #1433. Only building moved; validation and submit parsing still go through the hand-written branches in `Onboarding/hooks.tsx` |
| Onboarding basic information `useBasicInformationSchema` | done | #1433. Went straight to `buildOnce`; building, validation and submit parsing all go through the hook |
| Onboarding `useJSONSchemaForm` | todo | No Onboarding step uses it anymore; only `JsonSchemaComparison` does |
| Onboarding `useBenefitOffersSchema` | todo | |
| Onboarding `useEngagementAgreementDetailsSchema` | todo | |
| Onboarding `useBenefitOffersSchema` | done | #1442. Went straight to `buildOnce`, seeded with the saved benefit offers |
| Onboarding `useEngagementAgreementDetailsSchema` | done | #1442. Went straight to `buildOnce`, seeded with the saved engagement agreement details |
| Contractor contract details `useContractorOnboardingDetailsSchema` | todo | Money-sensitive |
| ContractorOnboarding `useGetContractDocumentSignatureSchema` | todo | |
| Contract documents `useGetContractDocumentSignatureSchema` | todo | |
| ContractorOnboarding `useGetEligibilityQuestionnaire` | todo | |
| ContractorOnboarding `useGetContractOriginSchema` | todo | |
| Invoice schedules `useGetCreateInvoiceScheduleSchema` | todo | Money-sensitive |
Expand Down
2 changes: 1 addition & 1 deletion example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"audit": "npm audit --audit-level=high",
"dev": "nodemon ./dev_server.js",
"build": "tsc -b && vite build",
"lint": "oxlint --type-aware .",
"lint": "oxlint --type-aware --report-unused-disable-directives-severity=error .",
"preview": "vite preview",
"postinstall": "react-flagpack",
"test:e2e": "playwright test",
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"check-format": "oxfmt --check",
"dev": "NODE_ENV=development tsdown --config-loader unrun --watch",
"build:reset": "postcss src/styles/reset.css -o ./example/src/css/reset.css",
"lint": "oxlint --type-aware --ignore-pattern 'example/**' .",
"lint": "oxlint --type-aware --report-unused-disable-directives-severity=error --ignore-pattern 'example/**' .",
Comment thread
gabrielseco marked this conversation as resolved.
"lint:workflows": "zizmor .github/workflows/",
"lint:workflows:fix": "zizmor --fix .github/workflows/",
"format": "oxfmt",
Expand Down
1 change: 1 addition & 0 deletions src/common/api/contractor-contract-details.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
} from '@/src/client';
import { useClient } from '@/src/context';
import { Client } from '@/src/client/client';
// oxlint-disable-next-line no-restricted-imports -- TODO: move onto useHeadlessForm, see docs/USE_HEADLESS_FORM_ROLLOUT.md
import { createHeadlessForm } from '@/src/common/createHeadlessForm';
import {
FlowOptions,
Expand Down
1 change: 1 addition & 0 deletions src/common/contract-documents/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
} from '@/src/client';
import { Client } from '@/src/client/client';
import { signatureSchema } from '@/src/common/contract-documents/json-schemas/signature';
// oxlint-disable-next-line no-restricted-imports -- TODO: move onto useHeadlessForm, see docs/USE_HEADLESS_FORM_ROLLOUT.md
import { createHeadlessForm } from '@/src/common/createHeadlessForm';
import { useClient } from '@/src/context';
import { JSFModify } from '@/src/flows/types';
Expand Down
1 change: 0 additions & 1 deletion src/common/createHeadlessForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ export const createHeadlessForm = (
actionableWarnings.length > 0 &&
process.env.RF_INTERNAL_DEV === 'true'
) {
// eslint-disable-next-line no-console
Comment thread
gabrielseco marked this conversation as resolved.
console.warn('jsfModify warnings:', actionableWarnings);
}
}
Expand Down
1 change: 1 addition & 0 deletions src/common/invoice-schedules/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
} from '@/src/client';
import { Client } from '@/src/client/client';
import { useClient } from '@/src/context';
// oxlint-disable-next-line no-restricted-imports -- TODO: move onto useHeadlessForm, see docs/USE_HEADLESS_FORM_ROLLOUT.md
import { createHeadlessForm } from '@/src/common/createHeadlessForm';
import { useContractorCurrencies } from '@/src/common/api/contractor-contract-details';
import { INVOICE_SCHEDULE_STATUS } from '@/src/common/invoice-schedules/constants';
Expand Down
1 change: 0 additions & 1 deletion src/components/ui/file-uploader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ export function FileUploader({
if (externalFiles && externalFiles !== syncedRef.current) {
syncedRef.current = externalFiles;
// effect is okay here, we just track with a ref to avoid unnecessary re-renders
// oxlint-disable-next-line react-hooks/set-state-in-effect
Comment thread
gabrielseco marked this conversation as resolved.
setFiles(externalFiles);
}
}, [externalFiles]);
Expand Down
2 changes: 0 additions & 2 deletions src/components/ui/form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -146,8 +146,6 @@ const FormControl = React.forwardRef<

return React.cloneElement(
children as React.ReactElement<Record<string, unknown>>,
// WE NEED TO FIX: react-hooks/refs - Passing a ref to a function may read its value during render
// oxlint-disable-next-line react-hooks/refs
Comment thread
gabrielseco marked this conversation as resolved.
{ ...(children.props as object), ...controlProps, ref },
);
});
Expand Down
1 change: 1 addition & 0 deletions src/flows/ContractAmendment/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
import { parseJSFToValidate } from '@/src/components/form/utils';
import { mutationToPromise } from '@/src/lib/mutations';
import { Client } from '@/src/client/client';
// oxlint-disable-next-line no-restricted-imports -- TODO: move onto useHeadlessForm, see docs/USE_HEADLESS_FORM_ROLLOUT.md
import { createHeadlessForm } from '@/src/common/createHeadlessForm';
import { useEmploymentQuery } from '@/src/common/api/employment';
import { useClient } from '@/src/context';
Expand Down
1 change: 1 addition & 0 deletions src/flows/ContractorOnboarding/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import {
JSFModify,
} from '@/src/flows/types';
import { Client } from '@/src/client/client';
// oxlint-disable-next-line no-restricted-imports -- TODO: move onto useHeadlessForm, see docs/USE_HEADLESS_FORM_ROLLOUT.md
import { createHeadlessForm } from '@/src/common/createHeadlessForm';
import { useMutation, useQuery } from '@tanstack/react-query';
import { FieldValues } from 'react-hook-form';
Expand Down
1 change: 1 addition & 0 deletions src/flows/CostCalculator/api.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// oxlint-disable-next-line no-restricted-imports -- TODO: move onto useHeadlessForm, see docs/USE_HEADLESS_FORM_ROLLOUT.md
import { createHeadlessForm } from '@/src/common/createHeadlessForm';
import {
CostCalculatorEstimateParams,
Expand Down
1 change: 1 addition & 0 deletions src/flows/CostCalculator/hooks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import type { JSFModify } from '@/src/flows/types';

import { parseJSFToValidate } from '@/src/components/form/utils';
import { iterateErrors } from '@/src/components/form/validationResolver';
// oxlint-disable-next-line no-restricted-imports -- TODO: move onto useHeadlessForm, see docs/USE_HEADLESS_FORM_ROLLOUT.md
import { createHeadlessForm } from '@/src/common/createHeadlessForm';
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { string, ValidationError } from 'yup';
Expand Down
1 change: 1 addition & 0 deletions src/flows/CreateCompany/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { useClient } from '@/src/context';
import { Client } from '@/src/client/client';
import { FieldValues } from 'react-hook-form';
import { FlowOptions } from '@/src/flows/types';
// oxlint-disable-next-line no-restricted-imports -- TODO: move onto useHeadlessForm, see docs/USE_HEADLESS_FORM_ROLLOUT.md
import { createHeadlessForm } from '@/src/common/createHeadlessForm';
import { companyBasicInformationStepSchema } from '@/src/flows/CreateCompany/json-schemas/companyBasicInformationStep';
import { useQuery } from '@tanstack/react-query';
Expand Down
1 change: 1 addition & 0 deletions src/flows/JsonSchemaPlayground/hooks.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useState, useCallback, useMemo, useEffect } from 'react';
import { FieldValues } from 'react-hook-form';
// oxlint-disable-next-line no-restricted-imports -- TODO: move onto useHeadlessForm, see docs/USE_HEADLESS_FORM_ROLLOUT.md
import { createHeadlessForm } from '@/src/common/createHeadlessForm';
import {
getInitialValues,
Expand Down
Loading
Loading